self->name = util_strdup(name);
self->irblock = NULL;
+ self->gotos = NULL;
return self;
}
void ast_label_delete(ast_label *self)
{
mem_d((void*)self->name);
+ vec_free(self->gotos);
ast_expression_delete((ast_expression*)self);
mem_d(self);
}
+void ast_label_register_goto(ast_label *self, ast_goto *g)
+{
+ vec_push(self->gotos, g);
+}
+
+ast_goto* ast_goto_new(lex_ctx ctx, const char *name)
+{
+ ast_instantiate(ast_goto, ctx, ast_goto_delete);
+ ast_expression_init((ast_expression*)self, (ast_expression_codegen*)&ast_goto_codegen);
+
+ self->name = util_strdup(name);
+ self->target = NULL;
+ self->irblock_from = NULL;
+
+ return self;
+}
+
+void ast_goto_delete(ast_goto *self)
+{
+ mem_d((void*)self->name);
+ ast_expression_delete((ast_expression*)self);
+ mem_d(self);
+}
+
+void ast_goto_set_label(ast_goto *self, ast_label *label)
+{
+ self->target = label;
+}
+
ast_call* ast_call_new(lex_ctx ctx,
ast_expression *funcexpr)
{
v = ir_builder_create_field(ir, self->name, vtype);
if (!v) {
- asterror(ast_ctx(self), "ir_builder_create_global failed");
+ asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name);
return false;
}
if (vtype == TYPE_FIELD)
array->ir_values[ai] = ir_builder_create_field(ir, name, vtype);
if (!array->ir_values[ai]) {
mem_d(name);
- asterror(ast_ctx(self), "ir_builder_create_global failed");
+ asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", name);
return false;
}
if (vtype == TYPE_FIELD)
v = ir_builder_create_global(ir, self->name, vtype);
if (!v) {
- asterror(ast_ctx(self), "ir_builder_create_global failed");
+ asterror(ast_ctx(self), "ir_builder_create_global failed `%s`", self->name);
return false;
}
if (vtype == TYPE_FIELD)
self->ir_values[ai] = ir_builder_create_global(ir, name, vtype);
if (!self->ir_values[ai]) {
mem_d(name);
- asterror(ast_ctx(self), "ir_builder_create_global failed");
+ asterror(ast_ctx(self), "ir_builder_create_global failed `%s`", name);
return false;
}
if (vtype == TYPE_FIELD)
*/
v = ir_builder_create_global(ir, self->name, self->expression.vtype);
if (!v) {
- asterror(ast_ctx(self), "ir_builder_create_global failed");
+ asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", self->name);
return false;
}
if (self->expression.vtype == TYPE_FIELD)
snprintf(name + namelen, 16, "[%u]", (unsigned int)ai);
self->ir_values[ai] = ir_function_create_local(func, name, vtype, param);
if (!self->ir_values[ai]) {
- asterror(ast_ctx(self), "ir_builder_create_global failed");
+ asterror(ast_ctx(self), "ir_builder_create_global failed on `%s`", name);
return false;
}
if (vtype == TYPE_FIELD)
for (i = 0; i < vec_size(self->exprs); ++i)
{
ast_expression_codegen *gen = self->exprs[i]->expression.codegen;
- if (func->curblock->final) {
+ if (func->curblock->final && !ast_istype(self->exprs[i], ast_label)) {
asterror(ast_ctx(self->exprs[i]), "unreachable statement");
return false;
}
}
cgen = self->index->expression.codegen;
- if (!(*cgen)((ast_expression*)(self->index), func, true, &iridx))
+ if (!(*cgen)((ast_expression*)(self->index), func, false, &iridx))
return false;
cgen = arr->getter->expression.codegen;
bool ast_label_codegen(ast_label *self, ast_function *func, bool lvalue, ir_value **out)
{
+ size_t i;
+ ir_value *dummy;
+
*out = NULL;
if (lvalue) {
asterror(ast_ctx(self), "internal error: ast_label cannot be an lvalue");
/* enter the new block */
func->curblock = self->irblock;
+
+ /* Generate all the leftover gotos */
+ for (i = 0; i < vec_size(self->gotos); ++i) {
+ if (!ast_goto_codegen(self->gotos[i], func, false, &dummy))
+ return false;
+ }
+
+ return true;
+}
+
+bool ast_goto_codegen(ast_goto *self, ast_function *func, bool lvalue, ir_value **out)
+{
+ *out = NULL;
+ if (lvalue) {
+ asterror(ast_ctx(self), "internal error: ast_goto cannot be an lvalue");
+ return false;
+ }
+
+ if (self->target->irblock) {
+ if (self->irblock_from) {
+ /* we already tried once, this is the callback */
+ self->irblock_from->final = false;
+ if (!ir_block_create_jump(self->irblock_from, self->target->irblock)) {
+ asterror(ast_ctx(self), "failed to generate goto to `%s`", self->name);
+ return false;
+ }
+ }
+ else
+ {
+ if (!ir_block_create_jump(func->curblock, self->target->irblock)) {
+ asterror(ast_ctx(self), "failed to generate goto to `%s`", self->name);
+ return false;
+ }
+ }
+ }
+ else
+ {
+ /* the target has not yet been created...
+ * close this block in a sneaky way:
+ */
+ func->curblock->final = true;
+ self->irblock_from = func->curblock;
+ ast_label_register_goto(self->target, self);
+ }
+
return true;
}