mem_d(self);
}
+ast_breakcont* ast_breakcont_new(lex_ctx ctx, bool iscont)
+{
+ ast_instantiate(ast_breakcont, ctx, ast_breakcont_delete);
+ ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_breakcont_codegen);
+
+ self->is_continue = iscont;
+
+ return self;
+}
+
+void ast_breakcont_delete(ast_breakcont *self)
+{
+ ast_expression_delete((ast_expression*)self);
+ mem_d(self);
+}
+
ast_call* ast_call_new(lex_ctx ctx,
ast_expression *funcexpr)
{
return true;
}
+bool ast_breakcont_codegen(ast_breakcont *self, ast_function *func, bool lvalue, ir_value **out)
+{
+ ir_block *target;
+
+ if (lvalue) {
+ asterror(ast_ctx(self), "break/continue expression is not an l-value");
+ return false;
+ }
+
+ if (self->expression.outr) {
+ asterror(ast_ctx(self), "internal error: ast_breakcont cannot be reused!");
+ return false;
+ }
+ self->expression.outr = (ir_value*)1;
+
+ if (self->is_continue)
+ target = func->continueblock;
+ else
+ target = func->breakblock;
+
+ if (!ir_block_create_jump(func->curblock, target))
+ return false;
+ return true;
+}
+
bool ast_call_codegen(ast_call *self, ast_function *func, bool lvalue, ir_value **out)
{
ast_expression_codegen *cgen;
typedef struct ast_return_s ast_return;
typedef struct ast_member_s ast_member;
typedef struct ast_array_index_s ast_array_index;
+typedef struct ast_breakcont_s ast_breakcont;
enum {
TYPE_ast_node,
TYPE_ast_unary,
TYPE_ast_return,
TYPE_ast_member,
- TYPE_ast_array_index
+ TYPE_ast_array_index,
+ TYPE_ast_breakcont
};
#define ast_istype(x, t) ( ((ast_node_common*)x)->nodetype == (TYPE_##t) )
bool ast_loop_codegen(ast_loop*, ast_function*, bool lvalue, ir_value**);
+/* Break/Continue
+ */
+struct ast_breakcont_s
+{
+ ast_expression_common expression;
+ bool is_continue;
+};
+ast_breakcont* ast_breakcont_new(lex_ctx ctx, bool iscont);
+void ast_breakcont_delete(ast_breakcont*);
+
+bool ast_breakcont_codegen(ast_breakcont*, ast_function*, bool lvalue, ir_value**);
+
/* CALL node
*
* Contains an ast_expression as target, rather than an ast_function/value.
bool ir_block_create_store_op(ir_block *self, int op, ir_value *target, ir_value *what)
{
- ir_instr *in = ir_instr_new(self, op);
+ ir_instr *in;
+ if (self->final) {
+ irerror(self->context, "unreachable statement (%s)", self->label);
+ return false;
+ }
+ in = ir_instr_new(self, op);
if (!in)
return false;
{
ir_instr *in;
if (self->final) {
- irerror(self->context, "block already ended (%s)", self->label);
+ irerror(self->context, "unreachable statement (%s)", self->label);
return false;
}
self->final = true;
{
ir_instr *in;
if (self->final) {
- irerror(self->context, "block already ended (%s)", self->label);
+ irerror(self->context, "unreachable statement (%s)", self->label);
return false;
}
self->final = true;
{
ir_instr *in;
if (self->final) {
- irerror(self->context, "block already ended (%s)", self->label);
+ irerror(self->context, "unreachable statement (%s)", self->label);
return false;
}
self->final = true;
{
ir_instr *in;
if (self->final) {
- irerror(self->context, "block already ended (%s)", self->label);
+ irerror(self->context, "unreachable statement (%s)", self->label);
return false;
}
self->final = true;
return true;
}
+static bool parse_break_continue(parser_t *parser, ast_block *block, ast_expression **out, bool is_continue)
+{
+ ast_expression *exp = NULL;
+ ast_return *ret = NULL;
+
+ lex_ctx ctx = parser_ctx(parser);
+
+ if (!parser_next(parser) || parser->tok != ';') {
+ parseerror(parser, "expected semicolon");
+ return false;
+ }
+
+ if (!parser_next(parser))
+ parseerror(parser, "parse error");
+
+ *out = ast_breakcont_new(ctx, is_continue);
+ return true;
+}
+
static bool parse_statement(parser_t *parser, ast_block *block, ast_expression **out)
{
if (parser->tok == TOKEN_TYPENAME || parser->tok == '.')
}
return parse_for(parser, block, out);
}
+ else if (!strcmp(parser_tokval(parser), "break"))
+ {
+ return parse_break_continue(parser, block, out, false);
+ }
+ else if (!strcmp(parser_tokval(parser), "continue"))
+ {
+ return parse_break_continue(parser, block, out, true);
+ }
parseerror(parser, "Unexpected keyword");
return false;
}