return false;
}
- if (sy->ops[vec_size(sy->ops)-1].paren) {
+ if (vec_last(sy->ops).paren) {
parseerror(parser, "unmatched parenthesis");
return false;
}
- op = &operators[sy->ops[vec_size(sy->ops)-1].etype - 1];
- ctx = sy->ops[vec_size(sy->ops)-1].ctx;
+ op = &operators[vec_last(sy->ops).etype - 1];
+ ctx = vec_last(sy->ops).ctx;
DEBUGSHUNTDO(con_out("apply %s\n", op->op));
(ast_istype((A), ast_value) && ((ast_value*)(A))->isconst)
#define CanConstFold(A, B) \
(CanConstFold1(A) && CanConstFold1(B))
+#define CanConstFold3(A, B, C) \
+ (CanConstFold1(A) && CanConstFold1(B) && CanConstFold1(C))
#define ConstV(i) (asvalue[(i)]->constval.vvec)
#define ConstF(i) (asvalue[(i)]->constval.vfloat)
#define ConstS(i) (asvalue[(i)]->constval.vstring)
out = (ast_expression*)ast_binary_new(ctx, generated_op, exprs[0], exprs[1]);
break;
+ case opid2('?',':'):
+ if (exprs[1]->expression.vtype != exprs[2]->expression.vtype) {
+ ast_type_to_string(exprs[1], ty1, sizeof(ty1));
+ ast_type_to_string(exprs[2], ty2, sizeof(ty2));
+ parseerror(parser, "iperands of ternary expression must have the same type, got %s and %s", ty1, ty2);
+ return false;
+ }
+ if (CanConstFold1(exprs[0]))
+ out = (ConstF(0) ? exprs[1] : exprs[2]);
+ else
+ out = (ast_expression*)ast_ternary_new(ctx, exprs[0], exprs[1], exprs[2]);
+ break;
+
case opid1('>'):
generated_op += 1; /* INSTR_GT */
case opid1('<'):
* end of a condition is an unmatched closing paren
*/
int parens = 0;
+ int ternaries = 0;
sy.out = NULL;
sy.ops = NULL;
break;
}
+ /* a colon without a pervious question mark cannot be a ternary */
+ if (!ternaries && op->id == opid2(':','?')) {
+ parser->tok = ':';
+ break;
+ }
+
if (vec_size(sy.ops) && !vec_last(sy.ops).paren)
olast = &operators[vec_last(sy.ops).etype-1];
vec_push(sy.ops, syop(parser_ctx(parser), op));
vec_push(sy.ops, syparen(parser_ctx(parser), SY_PAREN_INDEX, 0));
wantop = false;
+ } else if (op->id == opid2('?',':')) {
+ wantop = false;
+ vec_push(sy.ops, syop(parser_ctx(parser), op));
+ wantop = false;
+ --ternaries;
+ } else if (op->id == opid2(':','?')) {
+ /* we don't push this operator */
+ wantop = false;
+ ++ternaries;
} else {
DEBUGSHUNTDO(con_out("push operator %s\n", op->op));
vec_push(sy.ops, syop(parser_ctx(parser), op));
goto onerr;
}
if (parser->tok == ';' ||
- (!parens && parser->tok == ']') ||
- parser->tok == ':')
+ (!parens && parser->tok == ']'))
{
break;
}
static bool parse_switch(parser_t *parser, ast_block *block, ast_expression **out)
{
ast_expression *operand;
+ ast_value *opval;
ast_switch *switchnode;
ast_switch_case swcase;
if (!operand)
return false;
+ if (!OPTS_FLAG(RELAXED_SWITCH)) {
+ opval = (ast_value*)operand;
+ if (!ast_istype(operand, ast_value) || !opval->isconst) {
+ parseerror(parser, "case on non-constant values need to be explicitly enabled via -frelaxed-switch");
+ ast_unref(operand);
+ return false;
+ }
+ }
+
switchnode = ast_switch_new(ctx, operand);
/* closing paren */
varentry_t *ve;
ve = &vec_last(parser->locals);
- if (ast_istype(ve->var, ast_value) && !(((ast_value*)(ve->var))->uses)) {
- if (parsewarning(parser, WARN_UNUSED_VARIABLE, "unused variable: `%s`", ve->name))
- rv = false;
+ if (!parser->errors) {
+ if (ast_istype(ve->var, ast_value) && !(((ast_value*)(ve->var))->uses)) {
+ if (parsewarning(parser, WARN_UNUSED_VARIABLE, "unused variable: `%s`", ve->name))
+ rv = false;
+ }
}
mem_d(ve->name);
vec_pop(parser->locals);
ir_builder_delete(ir);
return false;
}
+ }
+ if (opts_dump)
+ ir_builder_dump(ir, con_out);
+ for (i = 0; i < vec_size(parser->functions); ++i) {
if (!ir_function_finalize(parser->functions[i]->ir_func)) {
con_out("failed to finalize function %s\n", parser->functions[i]->name);
ir_builder_delete(ir);
}
if (retval) {
- if (opts_dump)
+ if (opts_dumpfin)
ir_builder_dump(ir, con_out);
generate_checksum(parser);