\f
/* Public functions. */
+static struct expr_node *
+parse_expr (struct lexer *lexer, struct expression *e)
+{
+ struct expr_node *n = parse_or (lexer, e);
+ if (n && n->type == OP_VEC_ELEM_NUM_RAW)
+ n->type = OP_VEC_ELEM_NUM;
+ return n;
+}
+
/* Parses an expression of the given TYPE. If DS is nonnull then variables and
vectors within it may be referenced within the expression; otherwise, the
expression must not reference any variables or vectors. Returns the new
assert (val_type_is_valid (type));
struct expression *e = expr_create (ds);
- struct expr_node *n = parse_or (lexer, e);
+ struct expr_node *n = parse_expr (lexer, e);
if (!n || !type_check (e, n, type))
{
expr_free (e);
expr_parse_bool (struct lexer *lexer, struct dataset *ds)
{
struct expression *e = expr_create (ds);
- struct expr_node *n = parse_or (lexer, e);
+ struct expr_node *n = parse_expr (lexer, e);
if (!n)
{
expr_free (e);
atom_type actual_type = expr_node_returns (n);
if (actual_type == OP_number)
- n = expr_allocate_unary (e, OP_NUM_TO_BOOLEAN, n);
+ n = expr_allocate_binary (e, OP_EXPR_TO_BOOLEAN, n,
+ expr_allocate_expr_node (e, n));
else if (actual_type != OP_boolean)
{
msg_at (SE, expr_location (e, n),
const char *new_var_name)
{
struct expression *e = expr_create (ds);
- struct expr_node *n = parse_or (lexer, e);
+ struct expr_node *n = parse_expr (lexer, e);
if (!n)
{
expr_free (e);
struct expression *e;
e = expr_create (ds);
- n = parse_or (lexer, e);
+ n = parse_expr (lexer, e);
if (n == NULL)
{
expr_free (e);
{
case OP_number:
case OP_boolean:
+ case OP_num_vec_elem:
return &on_number_stack;
case OP_string:
case OP_integer:
case OP_pos_int:
case OP_vector:
+ case OP_expr_node:
return ¬_on_stack;
default:
*argp = expr_allocate_unary (e, OP_BOOLEAN_TO_NUM, arg);
return true;
}
+ else if (actual_type == OP_num_vec_elem)
+ {
+ if (do_coercion)
+ arg->type = OP_VEC_ELEM_NUM;
+ return true;
+ }
break;
case OP_string:
{
/* Convert numeric to boolean. */
if (do_coercion)
- *argp = expr_allocate_unary (e, OP_NUM_TO_BOOLEAN, arg);
+ *argp = expr_allocate_binary (e, OP_OPERAND_TO_BOOLEAN, arg,
+ expr_allocate_expr_node (e, node));
return true;
}
break;
break;
case OP_format:
+ /* We never coerce to OP_format, only to OP_ni_format or OP_no_format. */
NOT_REACHED ();
case OP_ni_format:
"not produce the mathematically expected result. "
"Use the AND logical operator to fix the problem "
"(e.g. `a < b AND b < c'). "
- "If chaining is really intended, parentheses will disable "
- "this warning (e.g. `(a < b) < c'.)");
+ "To disable this warning, insert parentheses.");
static const struct operator ops[] =
{
const char *chain_warning =
_("The exponentiation operator (`**') is left-associative: "
- "`a**b**c' equals `(a**b)**c', not as `a**(b**c)'. "
+ "`a**b**c' equals `(a**b)**c', not `a**(b**c)'. "
"To disable this warning, insert parentheses.");
if (lex_token (lexer) != T_NEG_NUM || lex_next_token (lexer, 1) != T_EXP)
int start_ofs = lex_ofs (lexer);
struct expr_node *lhs = expr_allocate_number (e, -lex_tokval (lexer));
lex_get (lexer);
+ expr_add_location (lexer, e, start_ofs, lhs);
struct expr_node *node = parse_binary_operators__ (
lexer, e, &op, 1, parse_primary, chain_warning, lhs);
case T_LPAREN:
{
- /* Count number of left parentheses so that we can match them against
- an equal number of right parentheses. This defeats trivial attempts
- to exhaust the stack with a lot of left parentheses. (More
- sophisticated attacks will still succeed.) */
- size_t n = 0;
- while (lex_match (lexer, T_LPAREN))
- n++;
-
+ lex_get (lexer);
struct expr_node *node = parse_or (lexer, e);
- if (!node)
- return NULL;
-
- for (size_t i = 0; i < n; i++)
- if (!lex_force_match (lexer, T_RPAREN))
- return NULL;
-
- return node;
+ return !node || !lex_force_match (lexer, T_RPAREN) ? NULL : node;
}
default:
return NULL;
operation_type type = (vector_get_type (vector) == VAL_NUMERIC
- ? OP_VEC_ELEM_NUM : OP_VEC_ELEM_STR);
+ ? OP_VEC_ELEM_NUM_RAW : OP_VEC_ELEM_STR);
struct expr_node *node = expr_allocate_binary (
e, type, element, expr_allocate_vector (e, vector));
expr_add_location (lexer, e, vector_start_ofs, node);
static void
no_match (struct expression *e, const char *func_name, struct expr_node *node,
- const struct operation *first, const struct operation *last)
+ const struct operation *ops, size_t n)
{
struct string s;
- const struct operation *f;
ds_init_empty (&s);
- if (last - first == 1)
+ if (n == 1)
{
- ds_put_format (&s, _("Type mismatch invoking %s as "), first->prototype);
+ ds_put_format (&s, _("Type mismatch invoking %s as "), ops->prototype);
put_invocation (&s, func_name, node);
}
else
put_invocation (&s, func_name, node);
ds_put_cstr (&s, _(" does not match any known function. Candidates are:"));
- for (f = first; f < last; f++)
- ds_put_format (&s, "\n%s", f->prototype);
+ for (size_t i = 0; i < n; i++)
+ ds_put_format (&s, "\n%s", ops[i].prototype);
}
ds_put_byte (&s, '.');
msg_at (SE, expr_location (e, node), "%s", ds_cstr (&s));
+ if (n == 1 && ops->n_args == node->n_args)
+ {
+ for (size_t i = 0; i < ops->n_args; i++)
+ if ((ops->args[i] == OP_ni_format
+ || ops->args[i] == OP_no_format)
+ && expr_node_returns (node->args[i]) == OP_format)
+ {
+ const struct fmt_spec *f = &node->args[i]->format;
+ char *error = fmt_check__ (f, (ops->args[i] == OP_ni_format
+ ? FMT_FOR_INPUT : FMT_FOR_OUTPUT));
+ if (!error)
+ error = fmt_check_type_compat__ (f, VAL_NUMERIC);
+ if (error)
+ {
+ msg_at (SN, expr_location (e, node->args[i]), "%s", error);
+ free (error);
+ }
+ }
+ }
+
ds_destroy (&s);
}
const struct operation *f = match_function (n, first, last);
if (!f)
{
- no_match (e, ds_cstr (&func_name), n, first, last);
+ no_match (e, ds_cstr (&func_name), n, first, last - first);
goto fail;
}
n->type = f - operations;
return n;
}
+struct expr_node *
+expr_allocate_expr_node (struct expression *e,
+ const struct expr_node *expr_node)
+{
+ struct expr_node *n = pool_alloc (e->expr_pool, sizeof *n);
+ *n = (struct expr_node) { .type = OP_expr_node, .expr_node = expr_node };
+ return n;
+}
+
/* Allocates a unary composite node that represents the value of
variable V in expression E. */
static struct expr_node *