ctx = vec_last(sy->ops).ctx;
if (vec_size(sy->out) < op->operands) {
- compile_error(ctx, "internal error: not enough operands: %i (operator %s (%i))", vec_size(sy->out),
- op->op, (int)op->id);
+ if (op->flags & OP_PREFIX)
+ compile_error(ctx, "expected expression after unary operator `%s`", op->op, (int)op->id);
+ else /* this should have errored previously already */
+ compile_error(ctx, "expected expression after operator `%s`", op->op, (int)op->id);
return false;
}
* intrinsic call and just evaluate it i.e constant fold it.
*/
if (fold && ast_istype(fun, ast_value) && ((ast_value*)fun)->intrinsic) {
- ast_expression **exprs = NULL;
- ast_expression *fold = NULL;
+ ast_expression **exprs = NULL;
+ ast_expression *foldval = NULL;
for (i = 0; i < paramcount; i++)
vec_push(exprs, sy->out[fid+1 + i].out);
- if (!(fold = intrin_fold(parser->intrin, (ast_value*)fun, exprs))) {
+ if (!(foldval = intrin_fold(parser->intrin, (ast_value*)fun, exprs))) {
vec_free(exprs);
goto fold_leave;
}
* Blub: what sorts of unreffing and resizing of
* sy->out should I be doing here?
*/
- sy->out[fid] = syexp(fold->node.context, fold);
+ sy->out[fid] = syexp(foldval->node.context, foldval);
vec_shrinkby(sy->out, 1);
vec_free(exprs);
/* only warn once about an assignment in a truth value because the current code
* would trigger twice on: if(a = b && ...), once for the if-truth-value, once for the && part
*/
- bool warn_truthvalue = true;
+ bool warn_parenthesis = true;
/* count the parens because an if starts with one, so the
* end of a condition is an unmatched closing paren
}
}
if (o == operator_count) {
- compile_error(parser_ctx(parser), "unknown operator: %s", parser_tokval(parser));
+ compile_error(parser_ctx(parser), "unexpected operator: %s", parser_tokval(parser));
goto onerr;
}
/* found an operator */
if (vec_size(sy.ops) && !vec_last(sy.ops).isparen)
olast = &operators[vec_last(sy.ops).etype-1];
+ /* first only apply higher precedences, assoc_left+equal comes after we warn about precedence rules */
+ while (olast && op->prec < olast->prec)
+ {
+ if (!parser_sy_apply_operator(parser, &sy))
+ goto onerr;
+ if (vec_size(sy.ops) && !vec_last(sy.ops).isparen)
+ olast = &operators[vec_last(sy.ops).etype-1];
+ else
+ olast = NULL;
+ }
+
#define IsAssignOp(x) (\
(x) == opid1('=') || \
(x) == opid2('+','=') || \
(x) == opid2('|','=') || \
(x) == opid3('&','~','=') \
)
- if (warn_truthvalue) {
+ if (warn_parenthesis) {
if ( (olast && IsAssignOp(olast->id) && (op->id == opid2('&','&') || op->id == opid2('|','|'))) ||
(olast && IsAssignOp(op->id) && (olast->id == opid2('&','&') || olast->id == opid2('|','|'))) ||
(truthvalue && !vec_size(sy.paren) && IsAssignOp(op->id))
)
{
(void)!parsewarning(parser, WARN_PARENTHESIS, "suggesting parenthesis around assignment used as truth value");
- warn_truthvalue = false;
+ warn_parenthesis = false;
+ }
+
+ if (olast && olast->id != op->id) {
+ if ((op->id == opid1('&') || op->id == opid1('|') || op->id == opid1('^')) &&
+ (olast->id == opid1('&') || olast->id == opid1('|') || olast->id == opid1('^')))
+ {
+ (void)!parsewarning(parser, WARN_PARENTHESIS, "suggesting parenthesis around bitwise operations");
+ warn_parenthesis = false;
+ }
+ else if ((op->id == opid2('&','&') || op->id == opid2('|','|')) &&
+ (olast->id == opid2('&','&') || olast->id == opid2('|','|')))
+ {
+ (void)!parsewarning(parser, WARN_PARENTHESIS, "suggesting parenthesis around logical operations");
+ warn_parenthesis = false;
+ }
}
}
else if (!strcmp(parser_tokval(parser), "inline")) {
flags |= AST_FLAG_INLINE;
if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
- parseerror(parser, "`noref` attribute has no parameters, expected `]]`");
+ parseerror(parser, "`inline` attribute has no parameters, expected `]]`");
+ *cvq = CV_WRONG;
+ return false;
+ }
+ }
+ else if (!strcmp(parser_tokval(parser), "eraseable")) {
+ flags |= AST_FLAG_ERASEABLE;
+ if (!parser_next(parser) || parser->tok != TOKEN_ATTRIBUTE_CLOSE) {
+ parseerror(parser, "`eraseable` attribute has no parameters, expected `]]`");
*cvq = CV_WRONG;
return false;
}