aboutsummaryrefslogtreecommitdiff
path: root/src/actualize.c
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2024-04-07 01:28:45 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2024-04-07 01:28:45 +0300
commit170f3ddc3d8967c0b5d4755c0221c396db215b2f (patch)
tree00314209cd7878b9d5b3fe6fc2e0c7297f76dec8 /src/actualize.c
parent2bdf1f8b1856bca8091d66a7a447e6c90993c297 (diff)
downloadek-170f3ddc3d8967c0b5d4755c0221c396db215b2f.tar.gz
ek-170f3ddc3d8967c0b5d4755c0221c396db215b2f.zip
implement some initial qbt backend stuff
Diffstat (limited to 'src/actualize.c')
-rw-r--r--src/actualize.c325
1 files changed, 213 insertions, 112 deletions
diff --git a/src/actualize.c b/src/actualize.c
index 3460851..744dc1a 100644
--- a/src/actualize.c
+++ b/src/actualize.c
@@ -18,7 +18,8 @@
#define UNUSED(x) do { (void)(x); } while (0)
-static int replace_type_id(struct ast_node *nodes, struct ast_node *id, struct ast_node *replacement);
+static int replace_type_id(struct ast_node *nodes, struct ast_node *id,
+ struct ast_node *replacement);
struct act_stack {
struct ast_node *node;
@@ -85,11 +86,14 @@ static struct ast_node *void_type()
return v;
}
-/* very inefficient, should probably cache somewhere */
static struct ast_node *i27_type(struct scope *scope)
{
- struct ast_node *i27 = gen_id("i27", NULL_LOC());
+ struct ast_node *i27 = gen_id(strdup("i27"), NULL_LOC());
struct ast_node *def = file_scope_find_type(scope, i27);
+ if (!def) {
+ error("missing definition of type 'i27'");
+ return NULL;
+ }
struct ast_node *a = gen_primitive(AST_I27, def, def->loc);
ast_set_flags(a, AST_FLAG_INIT | AST_FLAG_ACTUAL);
@@ -97,10 +101,29 @@ static struct ast_node *i27_type(struct scope *scope)
return a;
}
+static struct ast_node *i9_type(struct scope *scope)
+{
+ struct ast_node *i27 = gen_id(strdup("i9"), NULL_LOC());
+ struct ast_node *def = file_scope_find_type(scope, i27);
+ if (!def) {
+ error("missing definition of type 'i9'");
+ return NULL;
+ }
+
+ struct ast_node *a = gen_primitive(AST_I9, def, def->loc);
+ ast_set_flags(a, AST_FLAG_INIT | AST_FLAG_ACTUAL);
+ a->type = a;
+ return a;
+}
+
static struct ast_node *str_type(struct scope *scope)
{
- struct ast_node *str = gen_id("str", NULL_LOC());
+ struct ast_node *str = gen_id(strdup("str"), NULL_LOC());
struct ast_node *def = file_scope_find_type(scope, str);
+ if (!def) {
+ error("missing definition of type 'str'");
+ return NULL;
+ }
struct ast_node *a = gen_primitive(AST_STR, def, def->loc);
ast_set_flags(a, AST_FLAG_INIT | AST_FLAG_ACTUAL);
@@ -110,8 +133,12 @@ static struct ast_node *str_type(struct scope *scope)
static struct ast_node *bool_type(struct scope *scope)
{
- struct ast_node *b = gen_id("bool", NULL_LOC());
+ struct ast_node *b = gen_id(strdup("bool"), NULL_LOC());
struct ast_node *def = file_scope_find_type(scope, b);
+ if (!def) {
+ error("missing definition of type 'bool'");
+ return NULL;
+ }
struct ast_node *a = gen_primitive(AST_BOOL, def, def->loc);
ast_set_flags(a, AST_FLAG_INIT | AST_FLAG_ACTUAL);
@@ -155,7 +182,8 @@ static struct ast_node *find_label(struct act_state *state,
if (prev)
do {
cur = prev->next;
- if (same_id(AST_LABEL(prev->node).id, AST_LABEL(label).id))
+ if (same_id(AST_LABEL(prev->node).id,
+ AST_LABEL(label).id))
return prev->node;
} while ((prev = cur));
@@ -314,7 +342,8 @@ static int analyze_visibility(struct scope *scope, struct ast_node *node)
case AST_IMPORT: {
const char *file = AST_IMPORT(node).file;
ret |= process_file(&scope,
- ast_flags(node, AST_FLAG_PUBLIC), file);
+ (int)ast_flags(node, AST_FLAG_PUBLIC),
+ file);
break;
}
@@ -379,8 +408,17 @@ static int analyze_var(struct scope *scope, struct ast_node *node)
return actualize(&state, scope, node);
}
+static void set_type(struct ast_node *node, struct ast_node *type)
+{
+ assert(type->node_type == AST_TYPE);
+ node->type = clone_ast_node(type);
+}
+
static int analyze_proc(struct scope *scope, struct ast_node *node)
{
+ /* not sure if this is the best place for this */
+ AST_PROC(node).id->scope = scope;
+
struct scope *proc_scope = create_scope();
scope_add_scope(scope, proc_scope);
node->scope = proc_scope;
@@ -389,14 +427,16 @@ static int analyze_proc(struct scope *scope, struct ast_node *node)
struct act_state state = {0};
int ret = actualize(&state, proc_scope, sign);
- node->type = sign;
+ set_type(node, sign);
return ret;
}
-static struct ast_node *analyze_type_expand(struct scope *scope, struct ast_node *n)
+static struct ast_node *analyze_type_expand(struct scope *scope,
+ struct ast_node *n)
{
assert(n->node_type == AST_TYPE_EXPAND);
- struct ast_node *trait = file_scope_find_type(scope, AST_TYPE_EXPAND(n).id);
+ struct ast_node *trait = file_scope_find_type(scope,
+ AST_TYPE_EXPAND(n).id);
if (!trait) {
semantic_error(scope->fctx, n, "no such type");
return NULL;
@@ -407,7 +447,8 @@ static struct ast_node *analyze_type_expand(struct scope *scope, struct ast_node
return NULL;
}
- semantic_info(scope->fctx, n, "FIXME: skipping type param check for now");
+ semantic_info(scope->fctx, n,
+ "FIXME: skipping type param check for now");
struct ast_node *body = AST_TRAIT(trait).raw_body;
body = clone_ast_node(body);
@@ -454,20 +495,22 @@ static int analyze_struct(struct scope *scope, struct ast_node *node)
if (generics)
ast_set_flags(node, AST_FLAG_GENERIC);
- struct ast_node *type = gen_type(AST_TYPE_STRUCT, node, NULL, node->loc);
+ struct ast_node *type = gen_type(AST_TYPE_STRUCT, node, NULL,
+ node->loc);
foreach_node(n, AST_STRUCT(node).body) {
if (n->node_type != AST_TYPE_EXPAND)
continue;
- if (implements_trait(AST_STRUCT(node).body, AST_TYPE_EXPAND(n).id)) {
+ if (implements_trait(AST_STRUCT(node).body,
+ AST_TYPE_EXPAND(n).id)) {
n->node_type = AST_EMPTY;
continue;
}
if (same_id(AST_STRUCT(node).id, AST_TYPE_EXPAND(n).id)) {
semantic_error(scope->fctx, n,
- "recursive trait implementations not allowed");
+ "recursive trait implementations not allowed");
return -1;
}
@@ -488,7 +531,7 @@ static int analyze_struct(struct scope *scope, struct ast_node *node)
switch (n->node_type) {
case AST_EMPTY: continue;
case AST_ID: continue;
- /* prototypes are checked later */
+ /* prototypes are checked later */
case AST_PROC: if (!AST_PROC(n).body) continue;
default:
}
@@ -514,9 +557,11 @@ static int analyze_struct(struct scope *scope, struct ast_node *node)
if (AST_PROC(n).body)
continue;
- struct ast_node *proc = scope_find_proc(struct_scope, AST_PROC(n).id);
+ struct ast_node *proc = scope_find_proc(struct_scope,
+ AST_PROC(n).id);
if (!proc) {
- semantic_error(scope->fctx, n, "missing implementation");
+ semantic_error(scope->fctx, n,
+ "missing implementation");
return -1;
}
@@ -556,7 +601,8 @@ static int analyze_trait(struct scope *scope, struct ast_node *node)
continue;
/* don't re-expand already implemented traits */
- if (implements_trait(AST_TRAIT(node).body, AST_TYPE_EXPAND(n).id)) {
+ if (implements_trait(AST_TRAIT(node).body,
+ AST_TYPE_EXPAND(n).id)) {
/* not sure about this, but at least we don't have stray
* type expands everywhere */
n->node_type = AST_EMPTY;
@@ -565,7 +611,7 @@ static int analyze_trait(struct scope *scope, struct ast_node *node)
if (same_id(AST_TRAIT(node).id, AST_TYPE_EXPAND(n).id)) {
semantic_error(scope->fctx, n,
- "recursive trait implementations not allowed");
+ "recursive trait implementations not allowed");
return -1;
}
@@ -589,7 +635,7 @@ static int analyze_trait(struct scope *scope, struct ast_node *node)
switch (n->node_type) {
case AST_EMPTY: continue;
case AST_ID: continue;
- /* prototypes are added later */
+ /* prototypes are added later */
case AST_PROC: if (!AST_PROC(n).body) continue;
default:
}
@@ -619,9 +665,9 @@ static int analyze_trait(struct scope *scope, struct ast_node *node)
}
foreach_node(n, AST_TRAIT(node).body) {
- if (n->node_type != AST_PROC);
+ if (n->node_type != AST_PROC)
+ continue;
- struct act_state state = {0};
if (analyze_proc(trait_scope, n))
return -1;
}
@@ -645,7 +691,6 @@ static int analyze_signs(struct scope *scope, struct ast_node *node)
static int analyze(struct scope *scope, struct ast_node *tree)
{
- struct ast_node *node = tree, *next;
foreach_node(node, tree) {
if (analyze_visibility(scope, node))
return -1;
@@ -661,7 +706,7 @@ static int analyze(struct scope *scope, struct ast_node *tree)
if (actualize(&state, scope, node))
return -1;
- printf("actualized:\n");
+ printf("//actualized:\n");
dump_ast_node(0, node);
}
@@ -784,31 +829,6 @@ static void actualize_trait_types(struct ast_node *params,
assert(!args && !params);
}
-static int actualize_proc_call(struct act_state *state,
- struct scope *scope, struct ast_node *call,
- struct ast_node *proc)
-{
- /* clone procedure definition to
- * replace trait types with actual types and actualize it */
- struct ast_node *def = clone_ast_node(proc);
- if (!def) {
- /* internal error */
- internal_error("failed allocating actualization");
- return -1;
- }
-
- struct ast_node *sign = AST_PROC(def).sign;
- struct ast_node *params = AST_SIGN_TYPE(sign).params;
- struct ast_node *args = AST_CALL(call).args;
- actualize_trait_types(params, args);
-
- if (actualize(state, def->scope, def))
- return -1;
-
- call->type = AST_SIGN_TYPE(sign).ret;
- return 0;
-}
-
static int actualize_macro_expand(struct act_state *state,
struct scope *scope,
struct ast_node *macro_expand)
@@ -885,13 +905,14 @@ static int actualize_call(struct act_state *state,
struct ast_node *expr = AST_CALL(call).expr;
if (AST_TYPE(expr->type).kind != AST_TYPE_SIGN) {
char *tstr = type_str(expr->type);
- semantic_info(scope->fctx, call, "not a callable type: %s", tstr);
+ semantic_info(scope->fctx, call, "not a callable type: %s",
+ tstr);
free(tstr);
return -1;
}
struct ast_node *sign = expr->type;
- call->type = AST_SIGN_TYPE(sign).ret;
+ set_type(call, AST_SIGN_TYPE(sign).ret);
return 0;
}
@@ -943,7 +964,7 @@ static int actualize_proc(struct act_state *state,
if (actualize(&new_state, proc->scope, sign))
return -1;
- proc->type = sign;
+ set_type(proc, sign);
/* actualize body */
new_state.cur_proc = proc;
@@ -974,6 +995,11 @@ static int actualize_proc(struct act_state *state,
if (undefined_gotos(&new_state, scope))
return -1;
+ /* if we're main, don't mangle the entry point */
+ struct ast_node *id = AST_PROC(proc).id;
+ if (strcmp("main", AST_ID(id).id) == 0)
+ ast_set_flags(id, AST_FLAG_NOMANGLE);
+
/* we have successfully actualized the procedure */
return 0;
}
@@ -1020,8 +1046,7 @@ static int actualize_binop(struct act_state *state,
* should be allowed to operate on eachother */
/* types are the same, so the type of this expression is whichever */
- binop->type = left->type;
-
+ set_type(binop, left->type);
return 0;
}
@@ -1041,11 +1066,19 @@ static int actualize_block(struct act_state *state,
}
struct act_stack *defers = state->defer_stack;
- if (actualize(state, block_scope, node->_block.body))
- return -1;
+ foreach_node(pt, node->_block.body) {
+ if (actualize(state, block_scope, pt))
+ return -1;
+ }
+
+ if (node->_block.body == NULL) {
+ node->type = void_type();
+ node->_block.body = gen_empty();
+ return 0;
+ }
/* the block type is the last statement in the block's type */
- node->type = ast_last_node(node->_block.body)->type;
+ set_type(node, ast_last_node(node->_block.body)->type);
if (!node->type) {
semantic_error(scope->fctx, node,
"unable to detect block type");
@@ -1072,6 +1105,8 @@ static int actualize_id(struct act_state *state,
{
UNUSED(state);
assert(id && id->node_type == AST_ID);
+ id->scope = scope;
+
/** @todo vars and procs kind of override eachother, i.e.
* do_something(){..}
* ^() do_something;
@@ -1086,13 +1121,15 @@ static int actualize_id(struct act_state *state,
* */
struct ast_node *decl = file_scope_find_var(scope, id);
if (decl) {
- id->type = decl->type;
+ set_type(id, decl->type);
+ decl->uses++;
return 0;
}
decl = file_scope_find_proc(scope, id);
if (decl) {
- id->type = decl->type;
+ set_type(id, decl->type);
+ decl->uses++;
return 0;
}
@@ -1117,7 +1154,7 @@ static int actualize_var(struct act_state *state,
if (init && init->node_type == AST_INIT) {
assert(!init->type);
- init->type = type;
+ set_type(init, type);
/* TODO: some kind of check_init() */
}
@@ -1135,14 +1172,18 @@ static int actualize_var(struct act_state *state,
}
}
+ /* this is important for lowering */
+ AST_VAR(var).id->scope = scope;
+ var->scope = scope;
+
if (init)
/* infer */
- var->type = init->type;
+ set_type(var, init->type);
if (type)
/* TODO: should there be some default value? */
/* declare */
- var->type = type;
+ set_type(var, type);
/* an unnamed var is a var in a signature that should not produce a
* warning on not being used (if I ever get around to adding those kinds
@@ -1196,9 +1237,9 @@ static int struct_is_primitive(struct ast_node *s)
return 1;
/* special case of a special case?
- if (strcmp(name, "str"))
- return 1;
- */
+ if (strcmp(name, "str"))
+ return 1;
+ */
return 0;
}
@@ -1228,7 +1269,8 @@ static int actualize_type(struct act_state *state,
}
struct ast_node *exists = file_scope_find_type(scope,
- AST_ID_TYPE(type).id);
+ AST_ID_TYPE(
+ type).id);
if (!exists) {
semantic_error(scope->fctx, type, "no such type");
EXIT_ACT(-1);
@@ -1241,9 +1283,9 @@ static int actualize_type(struct act_state *state,
}
/*
- if (actualize(state, exists->scope, exists))
- EXIT_ACT(-1);
- */
+ if (actualize(state, exists->scope, exists))
+ EXIT_ACT(-1);
+ */
assert(AST_TYPE(type).next == NULL);
if (exists->node_type == AST_ALIAS) {
@@ -1253,28 +1295,30 @@ static int actualize_type(struct act_state *state,
else if (exists->node_type == AST_TRAIT) {
/* this is kind of weird, have to think about it */
*type = *gen_type(AST_TYPE_TRAIT, exists,
- NULL, exists->loc);
+ NULL, exists->loc);
}
else if (exists->node_type == AST_STRUCT) {
if (struct_is_primitive(exists)) {
*type = *gen_primitive(
- id_to_primitive(AST_STRUCT(exists).id),
- exists,
- exists->loc);
+ id_to_primitive(AST_STRUCT(exists).id),
+ exists,
+ exists->loc);
} else {
*type = *gen_type(AST_TYPE_STRUCT, exists,
- NULL, exists->loc);
+ NULL, exists->loc);
}
}
else if (exists->node_type == AST_ENUM) {
*type = *gen_type(AST_TYPE_ENUM, exists,
- NULL, exists->loc);
+ NULL, exists->loc);
}
break;
}
case AST_TYPE_CONSTRUCT:
+ /** @todo fully qualified constructs should be added to the
+ * actual list for code generation */
semantic_info(scope->fctx, type,
"constructs unimplemented, continuing with compilation to see what breaks");
break;
@@ -1311,19 +1355,22 @@ static int actualize_type(struct act_state *state,
case AST_TYPE_TRAIT: {
assert(ast_flags(type, AST_FLAG_ACTUAL));
- semantic_info(scope->fctx, type, "FIXME skipping trait type checks");
+ semantic_info(scope->fctx, type,
+ "FIXME skipping trait type checks");
break;
}
case AST_TYPE_STRUCT: {
assert(ast_flags(type, AST_FLAG_ACTUAL));
- semantic_info(scope->fctx, type, "FIXME skipping struct type checks");
+ semantic_info(scope->fctx, type,
+ "FIXME skipping struct type checks");
break;
}
case AST_TYPE_PRIMITIVE: {
assert(ast_flags(type, AST_FLAG_ACTUAL));
- semantic_info(scope->fctx, type, "FIXME skipping primitive type checks");
+ semantic_info(scope->fctx, type,
+ "FIXME skipping primitive type checks");
break;
}
@@ -1344,7 +1391,8 @@ static int actualize_empty(struct act_state *state,
* creating a function for */
struct ast_node *void_id = gen_id(strdup("void"), NULL_LOC());
if (!void_id) {
- internal_error("couldn't allocate type id for empty statement\n");
+ internal_error(
+ "couldn't allocate type id for empty statement\n");
return -1;
}
@@ -1601,7 +1649,7 @@ static int actualize_cast(struct act_state *state,
return -1;
if (proc_choice(expr, type)) {
- cast->type = type;
+ set_type(cast, type);
return match_proc(state, scope, cast);
}
@@ -1609,28 +1657,28 @@ static int actualize_cast(struct act_state *state,
return -1;
if (expr->node_type == AST_INIT) {
- cast->type = type;
+ set_type(cast, type);
return actualize_init_cast(state, scope, expr, type);
}
if (types_match(expr->type, type)) {
- cast->type = type;
+ set_type(cast, type);
return 0;
}
if (integral_type(expr->type) && integral_type(type)) {
- cast->type = type;
+ set_type(cast, type);
return 0;
}
if (pointer_type(expr->type) && pointer_type(type)) {
- cast->type = type;
+ set_type(cast, type);
return 0;
}
if (pointer_conversion(expr->type, type)
|| pointer_conversion(type, expr->type)) {
- cast->type = type;
+ set_type(cast, type);
return 0;
}
@@ -1650,19 +1698,17 @@ static int actualize_const(struct act_state *state, struct scope *scope,
{
UNUSED(state);
assert(cons->node_type == AST_CONST);
- if (AST_CONST(cons).kind == AST_CONST_INTEGER) {
- /* error checking would be doog */
+ if (AST_CONST(cons).kind == AST_CONST_INTEGER)
cons->type = i27_type(scope);
- return 0;
- }
- if (AST_CONST(cons).kind == AST_CONST_STRING) {
+ else if (AST_CONST(cons).kind == AST_CONST_STRING)
cons->type = str_type(scope);
+
+ if (cons->type)
return 0;
- }
semantic_error(scope->fctx, cons, "unimplemented constant");
- return 0;
+ return 1;
}
static int actualize_alias(struct act_state *state, struct scope *scope,
@@ -1709,7 +1755,7 @@ static int actualize_return(struct act_state *state, struct scope *scope,
if (actualize(state, scope, expr))
return -1;
- node->type = expr->type;
+ set_type(node, expr->type);
}
else {
node->type = void_type();
@@ -1726,7 +1772,7 @@ static int actualize_return(struct act_state *state, struct scope *scope,
"return type mismatch: %s", et);
semantic_info(scope->fctx, ret,
- "vs %s", rt);
+ "vs %s", rt);
free(rt);
free(et);
return -1;
@@ -1854,7 +1900,7 @@ static int actualize_unop(struct act_state *state,
return -1;
/* generally speaking */
- node->type = expr->type;
+ set_type(node, expr->type);
switch (node->_unop.op) {
case AST_DEREF: {
@@ -1866,7 +1912,7 @@ static int actualize_unop(struct act_state *state,
return -1;
}
- node->type = AST_PTR_TYPE(type).base;
+ set_type(node, AST_PTR_TYPE(type).base);
assert(node->type);
break;
}
@@ -1874,18 +1920,20 @@ static int actualize_unop(struct act_state *state,
case AST_REF: {
node->type = gen_type(AST_TYPE_POINTER, NULL, NULL,
NULL_LOC());
- node->AST_TYPE(type).next = expr->type;
+ set_type(node->AST_TYPE(type).next, expr->type);
break;
}
case AST_LNOT: {
if (AST_TYPE(expr->type).kind != AST_TYPE_PRIMITIVE) {
- semantic_error(scope->fctx, node, "'!' only implemented for primitive types");
+ semantic_error(scope->fctx, node,
+ "'!' only implemented for primitive types");
return -1;
}
if (AST_PRIMITIVE_TYPE(expr->type).type == AST_VOID) {
- semantic_error(scope->fctx, node, "'!' not implemented for void");
+ semantic_error(scope->fctx, node,
+ "'!' not implemented for void");
return -1;
}
@@ -1909,7 +1957,7 @@ static int actualize_as(struct act_state *state,
if (actualize(state, scope, type))
return -1;
- as->type = type;
+ set_type(as, type);
return 0;
}
@@ -1952,7 +2000,8 @@ next:
return ast_call_on(_replace_type_id, node, data);
}
-static int replace_type_id(struct ast_node *nodes, struct ast_node *id, struct ast_node *replacement)
+static int replace_type_id(struct ast_node *nodes, struct ast_node *id,
+ struct ast_node *replacement)
{
assert(replacement->node_type == AST_TYPE);
struct ast_node *pair[2] = {id, replacement};
@@ -2050,29 +2099,29 @@ static int actualize_dot(struct act_state *state,
default: {
char *tstr = type_str(type);
semantic_error(scope->fctx, node,
- "illegal type in dot expression: %s",
- tstr);
+ "illegal type in dot expression: %s",
+ tstr);
free(tstr);
- return -1;
- }
+ return -1;
+ }
}
struct ast_node *exists = scope_find_var(def->scope, id);
if (exists) {
assert(exists->type);
- node->type = exists->type;
+ set_type(node, exists->type);
return 0;
}
exists = scope_find_proc(def->scope, id);
if (exists) {
assert(exists->type);
- node->type = exists->type;
+ set_type(node, exists->type);
return 0;
}
semantic_error(scope->fctx, node,
- "does not have member");
+ "does not have member");
return -1;
}
@@ -2102,7 +2151,7 @@ static int actualize_assign(struct act_state *state, struct scope *scope,
return -1;
if (from->node_type == AST_INIT) {
- node->type = to->type;
+ set_type(node, to->type);
return actualize_init_cast(state, scope, from, to->type);
}
@@ -2123,7 +2172,7 @@ static int actualize_assign(struct act_state *state, struct scope *scope,
return -1;
}
- node->type = to->type;
+ set_type(node, to->type);
return 0;
}
@@ -2153,7 +2202,7 @@ static int actualize_fetch(struct act_state *state, struct scope *scope,
return -1;
}
- fetch->type = def->type;
+ set_type(fetch, def->type);
return 0;
}
@@ -2176,7 +2225,7 @@ static int actualize_enum(struct act_state *state, struct scope *scope,
node->type = type;
struct ast_node *members = node->_enum.body;
while (members) {
- members->type = type;
+ set_type(members, type);
if (members->_val.val) {
struct ast_node *val = members->_val.val;
if (actualize(state, enum_scope, val))
@@ -2208,6 +2257,56 @@ static int actualize_enum(struct act_state *state, struct scope *scope,
return 0;
}
+static int actualize_if(struct act_state *state, struct scope *scope,
+ struct ast_node *node)
+{
+ assert(node->node_type == AST_IF);
+ if (actualize(state, scope, AST_IF(node).cond))
+ return -1;
+
+ if (actualize(state, scope, AST_IF(node).body))
+ return -1;
+
+ if (actualize(state, scope, AST_IF(node).els))
+ return -1;
+
+ if (ast_flags(node, AST_FLAG_DOEXPR)) {
+ struct ast_node *tt = ast_last_node(AST_IF(node).body)->type;
+ struct ast_node *ft = ast_last_node(AST_IF(node).els)->type;
+ if (!types_match(tt, ft)) {
+ semantic_error(scope->fctx, node,
+ "mismatched if/else body values");
+ return -1;
+ }
+
+ set_type(node, tt);
+ return 0;
+ }
+
+ node->type = void_type();
+ return 0;
+}
+
+static int actualize_for(struct act_state *state, struct scope *scope,
+ struct ast_node *node)
+{
+ assert(node->node_type == AST_FOR);
+ if (actualize(state, scope, AST_FOR(node).pre))
+ return -1;
+
+ if (actualize(state, scope, AST_FOR(node).post))
+ return -1;
+
+ if (actualize(state, scope, AST_FOR(node).cond))
+ return -1;
+
+ if (actualize(state, scope, AST_FOR(node).body))
+ return -1;
+
+ node->type = void_type();
+ return 0;
+}
+
static int actualize(struct act_state *state, struct scope *scope,
struct ast_node *node)
{
@@ -2261,6 +2360,8 @@ static int actualize(struct act_state *state, struct scope *scope,
case AST_ASSIGN: ret |= actualize_assign(state, scope, node); break;
case AST_FETCH: ret |= actualize_fetch(state, scope, node); break;
case AST_ENUM: ret |= actualize_enum(state, scope, node); break;
+ case AST_IF: ret |= actualize_if(state, scope, node); break;
+ case AST_FOR: ret |= actualize_for(state, scope, node); break;
default:
/* more like internal_error, maybe? */