static const char *atom_type_name (atom_type);
static struct expression *finish_expression (struct expr_node *,
struct expression *);
-static bool type_check (const struct expr_node *, enum val_type expected_type);
+static bool type_check (const struct expression *, const struct expr_node *,
+ enum val_type expected_type);
static struct expr_node *allocate_unary_variable (struct expression *,
const struct variable *);
\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);
- if (!n || !type_check (n, type))
+ struct expr_node *n = parse_expr (lexer, e);
+ if (!n || !type_check (e, n, type))
{
expr_free (e);
return NULL;
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_unary (e, OP_EXPR_TO_BOOLEAN, n);
else if (actual_type != OP_boolean)
{
- msg (SE, _("Type mismatch: expression has %s type, "
+ msg_at (SE, expr_location (e, n),
+ _("Type mismatch: expression has %s type, "
"but a boolean value is required here."),
atom_type_name (actual_type));
expr_free (e);
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:
converted to type EXPECTED_TYPE, inserting a conversion at *N
if necessary. Returns true if successful, false on failure. */
static bool
-type_check (const struct expr_node *n, enum val_type expected_type)
+type_check (const struct expression *e, const struct expr_node *n,
+ enum val_type expected_type)
{
atom_type actual_type = expr_node_returns (n);
case VAL_NUMERIC:
if (actual_type != OP_number && actual_type != OP_boolean)
{
- msg (SE, _("Type mismatch: expression has %s type, "
- "but a numeric value is required here."),
+ msg_at (SE, expr_location (e, n),
+ _("Type mismatch: expression has type '%s', "
+ "but a numeric value is required."),
atom_type_name (actual_type));
return false;
}
case VAL_STRING:
if (actual_type != OP_string)
{
- msg (SE, _("Type mismatch: expression has %s type, "
- "but a string value is required here."),
+ msg_at (SE, expr_location (e, n),
+ _("Type mismatch: expression has type '%s', "
+ "but a string value is required."),
atom_type_name (actual_type));
return false;
}
/* Returns the source code location corresponding to expression NODE, computing
it lazily if needed. */
-static const struct msg_location *
-expr_location (struct expression *e, const struct expr_node *node_)
+const struct msg_location *
+expr_location (const struct expression *e_, const struct expr_node *node_)
{
struct expr_node *node = CONST_CAST (struct expr_node *, node_);
if (!node)
if (!node->location)
{
+ struct expression *e = CONST_CAST (struct expression *, e_);
const struct msg_location *min = NULL;
const struct msg_location *max = NULL;
expr_location__ (e, node, &min, &max);
*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;
+
+ case OP_integer:
+ if (actual_type == OP_number)
+ {
+ /* Convert number to integer. */
+ if (do_coercion)
+ *argp = expr_allocate_unary (e, OP_NUM_TO_INTEGER, arg);
return true;
}
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:
return type_coercion__ (NULL, node, arg_idx, false);
}
-/* How to parse an operator. */
+/* How to parse an operator.
+
+ Some operators support both numeric and string operators. For those,
+ 'num_op' and 'str_op' are both nonzero. Otherwise, only one 'num_op' is
+ nonzero. (PSPP doesn't have any string-only operators.) */
struct operator
{
enum token_type token; /* Operator token. */
- operation_type type; /* Operation. */
+ operation_type num_op; /* Operation for numeric operands (or 0). */
+ operation_type str_op; /* Operation for string operands (or 0). */
};
-/* Attempts to match the current token against the tokens for the
- OP_CNT operators in OPS[]. If successful, returns true
- and, if OPERATOR is non-null, sets *OPERATOR to the operator.
- On failure, returns false and, if OPERATOR is non-null, sets
- *OPERATOR to a null pointer. */
-static const struct operator *
+static operation_type
match_operator (struct lexer *lexer, const struct operator ops[], size_t n_ops,
const struct expr_node *lhs)
{
for (const struct operator *op = ops; op < ops + n_ops; op++)
if (lex_token (lexer) == op->token)
{
- bool op_is_numeric = operations[op->type].args[0] != OP_string;
- if (op_is_numeric == lhs_is_numeric)
- {
- if (op->token != T_NEG_NUM)
- lex_get (lexer);
- return op;
- }
+ if (op->token != T_NEG_NUM)
+ lex_get (lexer);
+
+ return op->str_op && !lhs_is_numeric ? op->str_op : op->num_op;
}
- return NULL;
+ return 0;
}
static const char *
-operator_name (const struct operator *op)
+operator_name (enum token_type token)
{
- return op->token == T_NEG_NUM ? "-" : token_type_to_string (op->token);
+ return token == T_NEG_NUM ? "-" : token_type_to_string (token);
}
static struct expr_node *
{
for (int op_count = 0; ; op_count++)
{
- const struct operator *operator = match_operator (lexer, ops, n_ops, lhs);
- if (!operator)
+ enum token_type token = lex_token (lexer);
+ operation_type optype = match_operator (lexer, ops, n_ops, lhs);
+ if (!optype)
{
if (op_count > 1 && chain_warning)
msg_at (SW, expr_location (e, lhs), "%s", chain_warning);
if (!rhs)
return NULL;
- struct expr_node *node = expr_allocate_binary (e, operator->type,
- lhs, rhs);
- bool lhs_ok = type_coercion (e, node, 0);
- bool rhs_ok = type_coercion (e, node, 1);
-
- if (!lhs_ok || !rhs_ok)
+ struct expr_node *node = expr_allocate_binary (e, optype, lhs, rhs);
+ if (!is_coercible (node, 0) || !is_coercible (node, 1))
{
- int n_matches = 0;
+ bool both = false;
for (size_t i = 0; i < n_ops; i++)
- if (ops[i].token == operator->token)
- n_matches++;
+ if (ops[i].token == token)
+ both = ops[i].num_op && ops[i].str_op;
- const char *name = operator_name (operator);
- if (n_matches > 1)
+ const char *name = operator_name (token);
+ if (both)
msg_at (SE, expr_location (e, node),
- _("The operands of %s must have the same type."), name);
+ _("Both operands of %s must have the same type."), name);
else if (operations[node->type].args[0] != OP_string)
msg_at (SE, expr_location (e, node),
_("Both operands of %s must be numeric."), name);
else
- msg_at (SE, expr_location (e, node),
- _("Both operands of %s must be strings."), name);
+ NOT_REACHED ();
msg_at (SN, expr_location (e, node->args[0]),
- _("The left-hand operand of %s has type '%s'."),
- name, atom_type_name (expr_node_returns (node->args[0])));
+ _("This operand has type '%s'."),
+ atom_type_name (expr_node_returns (node->args[0])));
msg_at (SN, expr_location (e, node->args[1]),
- _("The right-hand operand of %s has type '%s'."),
- name, atom_type_name (expr_node_returns (node->args[1])));
+ _("This operand has type '%s'."),
+ atom_type_name (expr_node_returns (node->args[1])));
return NULL;
}
+ if (!type_coercion (e, node, 0) || !type_coercion (e, node, 1))
+ NOT_REACHED ();
+
lhs = node;
}
}
if (!inner || !op_count)
return inner;
- struct expr_node *outer = expr_allocate_unary (e, op->type, inner);
+ struct expr_node *outer = expr_allocate_unary (e, op->num_op, inner);
expr_add_location (lexer, e, start_ofs, outer);
if (!type_coercion (e, outer, 0))
{
assert (operations[outer->type].args[0] != OP_string);
- const char *name = operator_name (op);
+ const char *name = operator_name (op->token);
msg_at (SE, expr_location (e, outer),
_("The unary %s operator requires a numeric operand."), name);
static struct expr_node *
parse_or (struct lexer *lexer, struct expression *e)
{
- static const struct operator op = { T_OR, OP_OR };
+ static const struct operator op = { .token = T_OR, .num_op = OP_OR };
return parse_binary_operators (lexer, e, &op, 1, parse_and, NULL);
}
static struct expr_node *
parse_and (struct lexer *lexer, struct expression *e)
{
- static const struct operator op = { T_AND, OP_AND };
+ static const struct operator op = { .token = T_AND, .num_op = OP_AND };
return parse_binary_operators (lexer, e, &op, 1, parse_not, NULL);
}
static struct expr_node *
parse_not (struct lexer *lexer, struct expression *e)
{
- static const struct operator op = { T_NOT, OP_NOT };
+ static const struct operator op = { .token = T_NOT, .num_op = OP_NOT };
return parse_inverting_unary_operator (lexer, e, &op, parse_rel);
}
"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[] =
{
- /* Numeric operators. */
- { T_EQUALS, OP_EQ },
- { T_EQ, OP_EQ },
- { T_GE, OP_GE },
- { T_GT, OP_GT },
- { T_LE, OP_LE },
- { T_LT, OP_LT },
- { T_NE, OP_NE },
-
- /* String operators. */
- { T_EQUALS, OP_EQ_STRING },
- { T_EQ, OP_EQ_STRING },
- { T_GE, OP_GE_STRING },
- { T_GT, OP_GT_STRING },
- { T_LE, OP_LE_STRING },
- { T_LT, OP_LT_STRING },
- { T_NE, OP_NE_STRING },
+ { .token = T_EQUALS, .num_op = OP_EQ, .str_op = OP_EQ_STRING },
+ { .token = T_EQ, .num_op = OP_EQ, .str_op = OP_EQ_STRING },
+ { .token = T_GE, .num_op = OP_GE, .str_op = OP_GE_STRING },
+ { .token = T_GT, .num_op = OP_GT, .str_op = OP_GT_STRING },
+ { .token = T_LE, .num_op = OP_LE, .str_op = OP_LE_STRING },
+ { .token = T_LT, .num_op = OP_LT, .str_op = OP_LT_STRING },
+ { .token = T_NE, .num_op = OP_NE, .str_op = OP_NE_STRING },
};
return parse_binary_operators (lexer, e, ops, sizeof ops / sizeof *ops,
{
static const struct operator ops[] =
{
- { T_PLUS, OP_ADD },
- { T_DASH, OP_SUB },
- { T_NEG_NUM, OP_ADD },
+ { .token = T_PLUS, .num_op = OP_ADD },
+ { .token = T_DASH, .num_op = OP_SUB },
+ { .token = T_NEG_NUM, .num_op = OP_ADD },
};
return parse_binary_operators (lexer, e, ops, sizeof ops / sizeof *ops,
{
static const struct operator ops[] =
{
- { T_ASTERISK, OP_MUL },
- { T_SLASH, OP_DIV },
+ { .token = T_ASTERISK, .num_op = OP_MUL },
+ { .token = T_SLASH, .num_op = OP_DIV },
};
return parse_binary_operators (lexer, e, ops, sizeof ops / sizeof *ops,
static struct expr_node *
parse_neg (struct lexer *lexer, struct expression *e)
{
- static const struct operator op = { T_DASH, OP_NEG };
+ static const struct operator op = { .token = T_DASH, .num_op = OP_NEG };
return parse_inverting_unary_operator (lexer, e, &op, parse_exp);
}
static struct expr_node *
parse_exp (struct lexer *lexer, struct expression *e)
{
- static const struct operator op = { T_EXP, OP_POW };
+ static const struct operator op = { .token = T_EXP, .num_op = OP_POW };
const char *chain_warning =
- _("The exponentiation operator (`**') is left-associative, "
- "even though right-associative semantics are more useful. "
- "That is, `a**b**c' equals `(a**b)**c', not as `a**(b**c)'. "
+ _("The exponentiation operator (`**') is left-associative: "
+ "`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);
return node;
}
+static double
+ymd_to_offset (int y, int m, int d)
+{
+ char *error;
+ double retval = calendar_gregorian_to_offset (
+ y, m, d, settings_get_fmt_settings (), &error);
+ if (error)
+ {
+ msg (SE, "%s", error);
+ free (error);
+ }
+ return retval;
+}
+
+static struct expr_node *
+expr_date (struct expression *e, int year_digits)
+{
+ static const char *months[12] =
+ {
+ "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
+ "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
+ };
+
+ time_t last_proc_time = time_of_last_procedure (e->ds);
+ struct tm *time = localtime (&last_proc_time);
+
+ char *tmp = (year_digits == 2
+ ? xasprintf ("%02d-%s-%02d", time->tm_mday, months[time->tm_mon],
+ time->tm_year % 100)
+ : xasprintf ("%02d-%s-%04d", time->tm_mday, months[time->tm_mon],
+ time->tm_year + 1900));
+
+ struct substring s;
+ ss_alloc_substring_pool (&s, ss_cstr (tmp), e->expr_pool);
+
+ free (tmp);
+
+ return expr_allocate_string (e, s);
+}
+
/* Parses system variables. */
static struct expr_node *
parse_sysvar (struct lexer *lexer, struct expression *e)
if (lex_match_id (lexer, "$CASENUM"))
return expr_allocate_nullary (e, OP_CASENUM);
else if (lex_match_id (lexer, "$DATE"))
- {
- static const char *months[12] =
- {
- "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
- "JUL", "AUG", "SEP", "OCT", "NOV", "DEC",
- };
-
- time_t last_proc_time = time_of_last_procedure (e->ds);
- struct tm *time;
- char temp_buf[10];
- struct substring s;
-
- time = localtime (&last_proc_time);
- sprintf (temp_buf, "%02d %s %02d", abs (time->tm_mday) % 100,
- months[abs (time->tm_mon) % 12], abs (time->tm_year) % 100);
-
- ss_alloc_substring (&s, ss_cstr (temp_buf));
- return expr_allocate_string (e, s);
- }
+ return expr_date (e, 2);
+ else if (lex_match_id (lexer, "$DATE11"))
+ return expr_date (e, 4);
else if (lex_match_id (lexer, "$TRUE"))
return expr_allocate_boolean (e, 1.0);
else if (lex_match_id (lexer, "$FALSE"))
{
time_t time = time_of_last_procedure (e->ds);
struct tm *tm = localtime (&time);
- return expr_allocate_number (e, expr_ymd_to_ofs (tm->tm_year + 1900,
- tm->tm_mon + 1,
- tm->tm_mday));
+ return expr_allocate_number (e, ymd_to_offset (tm->tm_year + 1900,
+ tm->tm_mon + 1,
+ tm->tm_mday));
}
else if (lex_match_id (lexer, "$TIME"))
{
time_t time = time_of_last_procedure (e->ds);
struct tm *tm = localtime (&time);
- return expr_allocate_number (e,
- expr_ymd_to_date (tm->tm_year + 1900,
+ return expr_allocate_number (e, ymd_to_offset (tm->tm_year + 1900,
tm->tm_mon + 1,
tm->tm_mday)
+ tm->tm_hour * 60 * 60.
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);
- if (!type_coercion (e, node, 1))
+ if (!type_coercion (e, node, 0))
{
msg_at (SE, expr_location (e, node),
_("A vector index must be numeric."));
|| node->n_args - (f->n_args - 1) < f->array_min_elems)
return false;
+ node->type = f - operations;
for (size_t i = 0; i < node->n_args; i++)
if (!is_coercible (node, i))
return false;
}
static bool
-validate_function_args (const struct operation *f, int n_args, int min_valid)
+validate_function_args (const struct expression *e, const struct expr_node *n,
+ const struct operation *f, int n_args, int min_valid)
{
/* Count the function arguments that go into the trailing array (if any). We
know that there must be at least the minimum number because
here. */
assert (f->array_granularity == 2);
assert (n_args % 2 == 0);
- msg (SE, _("%s must have an odd number of arguments."), f->prototype);
+ msg_at (SE, expr_location (e, n),
+ _("%s must have an odd number of arguments."), f->prototype);
return false;
}
if (f->array_min_elems == 0)
{
assert ((f->flags & OPF_MIN_VALID) == 0);
- msg (SE, _("%s function cannot accept suffix .%d to specify the "
- "minimum number of valid arguments."),
- f->prototype, min_valid);
+ msg_at (SE, expr_location (e, n),
+ _("%s function cannot accept suffix .%d to specify the "
+ "minimum number of valid arguments."),
+ f->prototype, min_valid);
return false;
}
else
assert (f->flags & OPF_MIN_VALID);
if (min_valid > array_n_args)
{
- msg (SE, _("For %s with %d arguments, at most %d (not %d) may be "
- "required to be valid."),
- f->prototype, n_args, array_n_args, min_valid);
+ msg_at (SE, expr_location (e, n),
+ _("For %s with %d arguments, at most %d (not %d) may be "
+ "required to be valid."),
+ f->prototype, n_args, array_n_args, min_valid);
return false;
}
}
static void
put_invocation (struct string *s,
- const char *func_name, struct expr_node **args, size_t n_args)
+ const char *func_name, struct expr_node *node)
{
size_t i;
ds_put_format (s, "%s(", func_name);
- for (i = 0; i < n_args; i++)
+ for (i = 0; i < node->n_args; i++)
{
if (i > 0)
ds_put_cstr (s, ", ");
- ds_put_cstr (s, operations[expr_node_returns (args[i])].prototype);
+ ds_put_cstr (s, operations[expr_node_returns (node->args[i])].prototype);
}
ds_put_byte (s, ')');
}
static void
-no_match (const char *func_name,
- struct expr_node **args, size_t n_args,
- const struct operation *first, const struct operation *last)
+no_match (struct expression *e, const char *func_name, struct expr_node *node,
+ 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);
- put_invocation (&s, func_name, args, n_args);
+ ds_put_format (&s, _("Type mismatch invoking %s as "), ops->prototype);
+ put_invocation (&s, func_name, node);
}
else
{
ds_put_cstr (&s, _("Function invocation "));
- put_invocation (&s, func_name, args, n_args);
+ 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 (SE, "%s", ds_cstr (&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 < node->n_args; i++)
+ if (!is_coercible (node, i))
+ {
+ atom_type expected = ops->args[i];
+ atom_type actual = expr_node_returns (node->args[i]);
+ if ((expected == OP_ni_format || expected == OP_no_format)
+ && actual == 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);
+ }
+ }
+ else
+ msg_at (SN, expr_location (e, node->args[i]),
+ _("This argument has type '%s' but '%s' is required."),
+ atom_type_name (actual), atom_type_name (expected));
+ }
+ }
ds_destroy (&s);
}
const struct operation *f = match_function (n, first, last);
if (!f)
{
- no_match (ds_cstr (&func_name), args, n_args, first, last);
+ no_match (e, ds_cstr (&func_name), n, first, last - first);
goto fail;
}
n->type = f - operations;
arguments were coercible. */
NOT_REACHED ();
}
- if (!validate_function_args (f, n_args, min_valid))
+ if (!validate_function_args (e, n, f, n_args, min_valid))
goto fail;
if ((f->flags & OPF_EXTENSION) && settings_get_syntax () == COMPATIBLE)
- msg (SW, _("%s is a PSPP extension."), f->prototype);
+ msg_at (SW, expr_location (e, n),
+ _("%s is a PSPP extension."), f->prototype);
if (f->flags & OPF_UNIMPLEMENTED)
{
- msg (SE, _("%s is not available in this version of PSPP."),
- f->prototype);
+ msg_at (SE, expr_location (e, n),
+ _("%s is not available in this version of PSPP."), f->prototype);
goto fail;
}
if ((f->flags & OPF_PERM_ONLY) &&
proc_in_temporary_transformations (e->ds))
{
- msg (SE, _("%s may not appear after %s."), f->prototype, "TEMPORARY");
+ msg_at (SE, expr_location (e, n),
+ _("%s may not appear after %s."), f->prototype, "TEMPORARY");
goto fail;
}
atom_type_name (atom_type type)
{
assert (is_atom (type));
- return operations[type].name;
+
+ /* The Boolean type is purely an internal concept that the documentation
+ doesn't mention, so it might confuse users if we talked about them in
+ diagnostics. */
+ return type == OP_boolean ? "number" : operations[type].name;
}
struct expr_node *
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 *