aboutsummaryrefslogtreecommitdiff
path: root/src/actualize.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/actualize.c')
-rw-r--r--src/actualize.c1855
1 files changed, 844 insertions, 1011 deletions
diff --git a/src/actualize.c b/src/actualize.c
index 744dc1a..6d85640 100644
--- a/src/actualize.c
+++ b/src/actualize.c
@@ -18,11 +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);
-
struct act_stack {
- struct ast_node *node;
+ struct ast *node;
struct act_stack *next;
};
@@ -35,23 +32,36 @@ enum act_flags {
struct act_state {
enum act_flags flags;
- struct ast_node *last_var;
- struct ast_node *cur_trait;
- struct ast_node *cur_proc;
+ struct ast *cur_proc;
struct act_stack *defer_stack;
struct act_stack *goto_stack;
struct act_stack *label_stack;
};
-static int is_lvalue(struct ast_node *n)
+static int replace_type_id(struct ast *nodes, char *id,
+ struct type *replacement);
+
+static int actualize(struct act_state *state, struct scope *scope,
+ struct ast *node);
+
+static int actualize_list(struct act_state *state, struct scope *scope,
+ struct ast *l);
+
+static int actualize_type(struct act_state *state, struct scope *scope,
+ struct type *node);
+
+static int actualize_type_list(struct act_state *state, struct scope *scope,
+ struct type *node);
+
+static int is_lvalue(struct ast *n)
{
- if (n->node_type == AST_ARR_ACCESS)
+ if (n->k == AST_ARR)
return 1;
- if (n->node_type == AST_ID)
+ if (n->k == AST_ID)
return 1;
- if (n->node_type == AST_UNOP && AST_UNOP(n).op == AST_DEREF)
+ if (n->k == AST_DEREF)
return 1;
return 0;
@@ -68,85 +78,65 @@ static enum act_flags act_flags(struct act_state *state, enum act_flags flags)
return state->flags & flags;
}
-/* TODO: this could be improved if we get a global void thing */
-static int is_void(struct ast_node *type)
+static bool is_void(struct type *t)
{
- assert(type->node_type == AST_TYPE);
- if (AST_TYPE(type).kind != AST_TYPE_PRIMITIVE)
- return 0;
+ /* missing return is void */
+ if (!t)
+ return 1;
- return AST_PRIMITIVE_TYPE(type).type == AST_VOID;
+ return t->k == TYPE_VOID;
}
-static struct ast_node *void_type()
+static struct type *void_type()
{
- struct ast_node *v = gen_primitive(AST_VOID, NULL, NULL_LOC());
- ast_set_flags(v, AST_FLAG_INIT | AST_FLAG_ACTUAL);
- v->type = v;
- return v;
+ return tgen_primitive(TYPE_VOID, strdup("void"), NULL, NULL_LOC());
}
-static struct ast_node *i27_type(struct scope *scope)
+static struct type *i27_type(struct scope *scope)
{
- struct ast_node *i27 = gen_id(strdup("i27"), NULL_LOC());
- struct ast_node *def = file_scope_find_type(scope, i27);
+ struct ast *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);
- a->type = a;
- return a;
+ return tgen_primitive(TYPE_I27, strdup("i27"), def, def->loc);
}
-static struct ast_node *i9_type(struct scope *scope)
+static struct type *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);
+ struct ast *def = file_scope_find_type(scope, "i9");
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;
+ return tgen_primitive(TYPE_I9, strdup("i9"), def, def->loc);
}
-static struct ast_node *str_type(struct scope *scope)
+static struct type *str_type(struct scope *scope)
{
- struct ast_node *str = gen_id(strdup("str"), NULL_LOC());
- struct ast_node *def = file_scope_find_type(scope, str);
+ struct ast *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);
- a->type = a;
- return a;
+ return tgen_primitive(TYPE_STR, strdup("str"), def, def->loc);
}
-static struct ast_node *bool_type(struct scope *scope)
+static struct type *bool_type(struct scope *scope)
{
- struct ast_node *b = gen_id(strdup("bool"), NULL_LOC());
- struct ast_node *def = file_scope_find_type(scope, b);
+ struct ast *def = file_scope_find_type(scope, "bool");
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);
- a->type = a;
- return a;
+ return tgen_primitive(TYPE_BOOL, strdup("bool"), def, def->loc);
}
-static int push_defer(struct act_state *state, struct ast_node *expr)
+static int push_defer(struct act_state *state, struct ast *expr)
{
struct act_stack *new = calloc(1, sizeof(struct act_stack));
if (!new) {
@@ -160,7 +150,7 @@ static int push_defer(struct act_state *state, struct ast_node *expr)
return 0;
}
-static int push_label(struct act_state *state, struct ast_node *label)
+static int push_label(struct act_state *state, struct ast *label)
{
struct act_stack *new = calloc(1, sizeof(struct act_stack));
if (!new) {
@@ -174,23 +164,20 @@ static int push_label(struct act_state *state, struct ast_node *label)
return 0;
}
-static struct ast_node *find_label(struct act_state *state,
- struct ast_node *label)
+static struct ast *find_label(struct act_state *state, char *label)
{
- assert(label->node_type == AST_LABEL);
struct act_stack *prev = state->label_stack, *cur;
if (prev)
do {
cur = prev->next;
- if (same_id(AST_LABEL(prev->node).id,
- AST_LABEL(label).id))
+ if (same_id(label_id(prev->node), label))
return prev->node;
} while ((prev = cur));
return NULL;
}
-static int push_goto(struct act_state *state, struct ast_node *got)
+static int push_goto(struct act_state *state, struct ast *got)
{
struct act_stack *new = calloc(1, sizeof(struct act_stack));
if (!new) {
@@ -204,17 +191,17 @@ static int push_goto(struct act_state *state, struct ast_node *got)
return 0;
}
-static struct ast_node *clone_defers(struct act_state *state,
+static struct ast *clone_defers(struct act_state *state,
struct act_stack *to)
{
struct act_stack *from = state->defer_stack;
/* maintain reverse order */
- struct ast_node *defers = NULL, *prev = NULL;
+ struct ast *defers = NULL, *prev = NULL;
while (from != to) {
- struct ast_node *defer = clone_ast_node(from->node);
+ struct ast *defer = clone_ast(from->node);
if (prev)
- prev->next = defer;
+ prev->n = defer;
if (!defers)
defers = defer;
@@ -263,130 +250,78 @@ static void destroy_act_state(struct act_state *state)
clear_gotos(state, NULL);
}
-static int actualize(struct act_state *state, struct scope *scope,
- struct ast_node *node);
-static int analyze(struct scope *scope, struct ast_node *tree);
+static void type_mismatch(struct scope *scope, struct ast *node, struct type *a, struct type *b)
+{
+ char *left_type = type_str(a);
+ char *right_type = type_str(b);
+ semantic_error(scope->fctx, node,
+ "type mismatch: %s vs %s",
+ left_type, right_type);
+ free(left_type);
+ free(right_type);
+}
+
+static int analyze(struct scope *scope, struct ast *tree);
-static int eval_const_if(struct scope *scope, struct ast_node *node)
+static int eval_const_if(struct scope *scope, struct ast *node)
{
assert(node
- && node->node_type == AST_IF
+ && node->k == AST_IF
&& ast_flags(node, AST_FLAG_CONST));
- int eval = 0;
- struct ast_node *cond = node->_if.cond;
- struct ast_node *next = node->next;
-
- switch (cond->node_type) {
- /* for now just check if the variable exists, might change in
- * the future */
- case AST_ID: eval = file_scope_find_var(scope, cond) != NULL;
- break;
- default: semantic_error(scope->fctx, node,
- "const if conditional at file scope unimplemented");
- return -1;
- }
-
- if (eval) {
- /* condition evaluated true, so keep the if block */
- struct ast_node *body = node->_if.body;
- ast_last_node(body)->next = node->next;
-
- /* an if must have a body, otherwise the parser messed up */
- assert(body);
-
- *node = *body;
- free(body);
- return 0;
- }
-
- struct ast_node *els = node->_if.els;
- if (els) {
- *node = *els;
- ast_last_node(els)->next = next;
- free(els);
- return 0;
- }
-
- if (next) {
- /* copy the next node into our place */
- *node = *next;
- free(next);
- return 0;
- }
-
- free(node);
- return 0;
+ semantic_error(scope->fctx, node,
+ "const if unimplemented");
+ return -1;
}
-static int analyze_visibility(struct scope *scope, struct ast_node *node)
+static int analyze_visibility(struct scope *scope, struct ast *node)
{
if (!node)
return 0;
- int ret = 0;
node->scope = scope;
- /* TODO: add error checking */
- switch (node->node_type) {
- case AST_PROC: {
- ret |= scope_add_proc(scope, node);
- break;
- }
-
- case AST_VAR: {
- ret |= scope_add_var(scope, node);
- break;
- }
+ switch (node->k) {
+ case AST_PROC_DEF: return scope_add_proc(scope, node);
+ case AST_MACRO_DEF: return scope_add_macro(scope, node);
+ case AST_VAR_DEF: return scope_add_var(scope, node);
case AST_IMPORT: {
- const char *file = AST_IMPORT(node).file;
- ret |= process_file(&scope,
+ const char *file = import_file(node);
+ return process_file(&scope,
(int)ast_flags(node, AST_FLAG_PUBLIC),
file);
- break;
}
case AST_IF: {
assert(ast_flags(node, AST_FLAG_CONST));
- ret |= eval_const_if(scope, node);
- if (ret)
+ if (eval_const_if(scope, node))
return -1;
/* since a const if likely replaced the current node with
* something else, we have to analyze the replacement */
- ret = analyze(scope, node);
- break;
+ return analyze(scope, node);
}
- case AST_STRUCT: {
+ case AST_STRUCT_DEF: {
/* we shouldn't get any anonymous structs at this stage */
- struct ast_node *id = AST_STRUCT(node).id;
- ret |= scope_add_type(scope, id, node);
- break;
+ char *id = struct_id(node);
+ return scope_add_type(scope, id, node);
}
- case AST_ENUM: {
- struct ast_node *id = AST_ENUM(node).id;
- ret |= scope_add_type(scope, id, node);
- break;
+ case AST_ENUM_DEF: {
+ char *id = enum_id(node);
+ return scope_add_type(scope, id, node);
}
- case AST_ALIAS: {
- struct ast_node *id = AST_ALIAS(node).id;
- ret |= scope_add_type(scope, id, node);
- break;
+ case AST_ALIAS_DEF: {
+ char *id = alias_id(node);
+ return scope_add_type(scope, id, node);
}
- case AST_TRAIT: {
- struct ast_node *id = AST_TRAIT(node).id;
- ret |= scope_add_type(scope, id, node);
- break;
- }
-
- case AST_MACRO_CONSTRUCT: {
- ret |= scope_add_macro(scope, node);
- break;
+ case AST_TRAIT_DEF: {
+ char *id = trait_id(node);
+ return scope_add_type(scope, id, node);
}
case AST_EMPTY: {
@@ -394,145 +329,188 @@ static int analyze_visibility(struct scope *scope, struct ast_node *node)
}
default:
- ret = -1;
semantic_error(scope->fctx, node, "unknown top element");
- break;
+ return -1;
};
- return ret;
+ return 0;
}
-static int analyze_var(struct scope *scope, struct ast_node *node)
+static int analyze_var(struct scope *scope, struct ast *node)
{
struct act_state state = {0};
return actualize(&state, scope, node);
}
-static void set_type(struct ast_node *node, struct ast_node *type)
+static void set_type(struct ast *node, struct type *type)
+{
+ node->t = clone_type_list(type);
+}
+
+static void replace_type(struct type *t, struct type *r)
{
- assert(type->node_type == AST_TYPE);
- node->type = clone_ast_node(type);
+ /* free strings before they get overwritten */
+ if (t->id)
+ free(t->id);
+
+ struct src_loc loc = t->loc;
+ struct scope *scope = t->scope;
+
+ *t = *r;
+
+ /* clone so we don't accidentally free same string twice later */
+ if (t->id)
+ t->id = strdup(t->id);
+
+ /* these things we generally don't want to replace */
+ t->loc = loc;
+ t->scope = scope;
}
-static int analyze_proc(struct scope *scope, struct ast_node *node)
+static void replace_ast(struct ast *n, struct ast *t)
{
- /* not sure if this is the best place for this */
- AST_PROC(node).id->scope = scope;
+ if (n->s)
+ free(n->s);
+
+ struct src_loc loc = n->loc;
+ struct scope *scope = n->scope;
+ *n = *t;
+
+ if (n->s)
+ n->s = strdup(n->s);
+
+ n->loc = loc;
+ t->scope = scope;
+}
+
+static int analyze_proc(struct scope *scope, struct ast *node)
+{
struct scope *proc_scope = create_scope();
scope_add_scope(scope, proc_scope);
node->scope = proc_scope;
- struct ast_node *sign = AST_PROC(node).sign;
-
+ struct ast *params = proc_params(node);
struct act_state state = {0};
- int ret = actualize(&state, proc_scope, sign);
- set_type(node, sign);
- return ret;
+ if (actualize_list(&state, proc_scope, params))
+ return -1;
+
+ struct type *rtype = proc_rtype(node);
+
+ if (actualize_type_list(&state, proc_scope, rtype))
+ return -1;
+
+ if (!rtype)
+ proc_rtype(node) = void_type();
+
+ struct type *callable = tgen_callable(NULL, proc_rtype(node), node->loc);
+ foreach_node(p, params) {
+ /* we must manually 'start' the chain **/
+ if (!callable_ptypes(callable)) {
+ callable_ptypes(callable) = clone_type(p->t);
+ continue;
+ }
+
+ type_append(callable_ptypes(callable), p->t);
+ }
+
+ set_type(node, callable);
+ return 0;
}
-static struct ast_node *analyze_type_expand(struct scope *scope,
- struct ast_node *n)
+static struct ast *analyze_type_expand(struct scope *scope,
+ struct ast *n)
{
- assert(n->node_type == AST_TYPE_EXPAND);
- struct ast_node *trait = file_scope_find_type(scope,
- AST_TYPE_EXPAND(n).id);
+ assert(n->k == AST_TYPE_EXPAND);
+ struct ast *trait = file_scope_find_type(scope, type_expand_id(n));
if (!trait) {
semantic_error(scope->fctx, n, "no such type");
return NULL;
}
- if (trait->node_type != AST_TRAIT) {
+ if (trait->k != AST_TRAIT_DEF) {
semantic_error(scope->fctx, n, "not a trait");
return NULL;
}
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);
+ struct ast *body = trait_raw_body(trait);
+ body = clone_ast(body);
- struct ast_node *pa = AST_TYPE_EXPAND(n).args;
- foreach_node(pt, AST_TRAIT(trait).params) {
- replace_type_id(body, AST_VAR(pt).id, pa);
- pa = pa->next;
+ struct type *pa = type_expand_args(n);
+ foreach_node(pt, trait_params(trait)) {
+ replace_type_id(body, var_id(pt), pa);
+ pa = pa->n;
}
return body;
}
-static int implements_trait(struct ast_node *body, struct ast_node *id)
+static int implements_trait(struct ast *body, char *id)
{
foreach_node(n, body) {
- if (n->node_type != AST_ID)
+ /* traits don't currently take generic parameters I guess? */
+ if (n->k != AST_ID)
continue;
- if (same_id(n, id))
+ if (same_id(id_str(n), id))
return 1;
}
return 0;
}
-static void mark_implemented(struct ast_node *n)
-{
- assert(n->node_type == AST_TYPE_EXPAND);
- /** @todo very hacky but good enough for now */
- struct ast_node *id = AST_TYPE_EXPAND(n).id;
- n->node_type = AST_ID;
- AST_ID(n).id = strdup(AST_ID(id).id);
-}
-
-static int analyze_struct(struct scope *scope, struct ast_node *node)
+static int analyze_struct(struct scope *scope, struct ast *node)
{
- assert(node->node_type == AST_STRUCT);
- struct ast_node *generics = AST_STRUCT(node).generics;
+ assert(node->k == AST_STRUCT_DEF);
+ struct ast *params = struct_params(node);
struct scope *struct_scope = create_scope();
if (!struct_scope)
return -1;
scope_add_scope(node->scope, struct_scope);
node->scope = struct_scope;
- if (generics)
+ if (params)
ast_set_flags(node, AST_FLAG_GENERIC);
- struct ast_node *type = gen_type(AST_TYPE_STRUCT, node, NULL,
- node->loc);
+ struct type *type = tgen_type(TYPE_STRUCT,
+ NULL, NULL,
+ node, NULL,
+ strdup(struct_id(node)),
+ node->loc);
- foreach_node(n, AST_STRUCT(node).body) {
- if (n->node_type != AST_TYPE_EXPAND)
+ foreach_node(n, struct_body(node)) {
+ if (n->k != AST_TYPE_EXPAND)
continue;
- if (implements_trait(AST_STRUCT(node).body,
- AST_TYPE_EXPAND(n).id)) {
- n->node_type = AST_EMPTY;
+ if (implements_trait(struct_body(node), type_expand_id(n))) {
+ n->k = AST_EMPTY;
continue;
}
- if (same_id(AST_STRUCT(node).id, AST_TYPE_EXPAND(n).id)) {
+ if (same_id(struct_id(node), type_expand_id(n))) {
semantic_error(scope->fctx, n,
"recursive trait implementations not allowed");
return -1;
}
- struct ast_node *body = analyze_type_expand(scope, n);
+ struct ast *body = analyze_type_expand(scope, n);
if (!body) {
- n->node_type = AST_EMPTY;
+ n->k = AST_EMPTY;
continue;
}
- replace_type_id(body, AST_TYPE_EXPAND(n).id, type);
- ast_block_last(body)->next = n->next;
- n->next = body;
-
- mark_implemented(n);
+ replace_type_id(body, type_expand_id(n), type);
+ ast_block_last(body)->n = n->n;
+ n->n = body;
}
- foreach_node(n, AST_STRUCT(node).body) {
- switch (n->node_type) {
+ foreach_node(n, struct_body(node)) {
+ switch (n->k) {
case AST_EMPTY: continue;
case AST_ID: continue;
/* prototypes are checked later */
- case AST_PROC: if (!AST_PROC(n).body) continue;
+ case AST_PROC_DEF: if (!proc_body(n)) continue;
default:
}
@@ -540,9 +518,9 @@ static int analyze_struct(struct scope *scope, struct ast_node *node)
return -1;
}
- foreach_node(n, AST_STRUCT(node).body) {
+ foreach_node(n, struct_body(node)) {
/* also checks prototypes */
- if (n->node_type != AST_PROC)
+ if (n->k != AST_PROC_DEF)
continue;
if (analyze_proc(struct_scope, n))
@@ -550,38 +528,47 @@ static int analyze_struct(struct scope *scope, struct ast_node *node)
}
/* check that all prototypes are implemented */
- foreach_node(n, AST_STRUCT(node).body) {
- if (n->node_type != AST_PROC)
+ foreach_node(n, struct_body(node)) {
+ if (n->k != AST_PROC_DEF)
continue;
- if (AST_PROC(n).body)
+ if (proc_body(n))
continue;
- struct ast_node *proc = scope_find_proc(struct_scope,
- AST_PROC(n).id);
+ struct ast *proc = scope_find_proc(struct_scope, proc_id(n));
if (!proc) {
semantic_error(scope->fctx, n,
"missing implementation");
return -1;
}
- if (!equiv_nodes(AST_PROC(n).sign, AST_PROC(proc).sign)) {
+ if (!types_match(n->t, proc->t)) {
semantic_error(scope->fctx, n, "mismatched signatures");
semantic_info(scope->fctx, proc, "note: here");
return -1;
}
}
+ char *id = strdup(struct_id(node));
+ if (same_id(id, "i27"))
+ node->t = tgen_primitive(TYPE_I27, id, node, node->loc);
+ else if (same_id(id, "i9"))
+ node->t = tgen_primitive(TYPE_I9, id, node, node->loc);
+ else if (same_id(id, "bool"))
+ node->t = tgen_primitive(TYPE_BOOL, id, node, node->loc);
+ else
+ node->t = tgen_struct(id, node, node->loc);
+
/** @todo there is the possibility that two different traits add the
* same prototype, which is reported in traits but not structs? */
return 0;
}
/* quite a lot of overlap with analyze_struct, kind of ugly I guess */
-static int analyze_trait(struct scope *scope, struct ast_node *node)
+static int analyze_trait(struct scope *scope, struct ast *node)
{
- assert(node->node_type == AST_TRAIT);
- struct ast_node *generics = AST_TRAIT(node).params;
+ assert(node->k == AST_TRAIT_DEF);
+ struct ast *params = trait_params(node);
struct scope *trait_scope = create_scope();
if (!trait_scope)
return -1;
@@ -589,54 +576,55 @@ static int analyze_trait(struct scope *scope, struct ast_node *node)
scope_add_scope(node->scope, trait_scope);
node->scope = trait_scope;
/** @todo should probably add in aliases for the traits in scope? */
- if (generics)
+ if (params)
ast_set_flags(node, AST_FLAG_GENERIC);
- struct ast_node *type = gen_type(AST_TYPE_TRAIT, node, NULL, node->loc);
+ struct type *type = tgen_type(TYPE_TRAIT, NULL, NULL,
+ node, NULL, strdup(trait_id(node)),
+ node->loc);
+
+ /* copy body */
+ node->a2 = clone_ast(trait_raw_body(node));
- AST_TRAIT(node).body = clone_ast_node(AST_TRAIT(node).raw_body);
/* do type expansions */
- foreach_node(n, AST_TRAIT(node).body) {
- if (n->node_type != AST_TYPE_EXPAND)
+ foreach_node(n, trait_body(node)) {
+ if (n->k != AST_TYPE_EXPAND)
continue;
/* don't re-expand already implemented traits */
- if (implements_trait(AST_TRAIT(node).body,
- AST_TYPE_EXPAND(n).id)) {
+ if (implements_trait(trait_body(node), type_expand_id(n))) {
/* not sure about this, but at least we don't have stray
* type expands everywhere */
- n->node_type = AST_EMPTY;
+ n->k = AST_EMPTY;
continue;
}
- if (same_id(AST_TRAIT(node).id, AST_TYPE_EXPAND(n).id)) {
+ if (same_id(trait_id(node), type_expand_id(n))) {
semantic_error(scope->fctx, n,
"recursive trait implementations not allowed");
return -1;
}
- struct ast_node *body = analyze_type_expand(scope, n);
+ struct ast *body = analyze_type_expand(scope, n);
if (!body) {
- n->node_type = AST_EMPTY;
+ n->k = AST_EMPTY;
continue;
}
- replace_type_id(body, AST_TYPE_EXPAND(n).id, type);
- ast_last_node(body)->next = n->next;
- n->next = body;
-
- mark_implemented(n);
+ replace_type_id(body, type_expand_id(n), type);
+ ast_last(body)->n = n->n;
+ n->n = body;
}
/* add all procedure definitions to scope */
- foreach_node(n, AST_TRAIT(node).body) {
+ foreach_node(n, trait_body(node)) {
/* kind of a hack but these shouldn't be shown to
* analyze_visibility */
- switch (n->node_type) {
+ switch (n->k) {
case AST_EMPTY: continue;
case AST_ID: continue;
/* prototypes are added later */
- case AST_PROC: if (!AST_PROC(n).body) continue;
+ case AST_PROC_DEF: if (!proc_body(n)) continue;
default:
}
@@ -649,47 +637,49 @@ static int analyze_trait(struct scope *scope, struct ast_node *node)
* would be. Add a prototypes -list to scopes? */
/* add all prototypes that don't have matching definition to scope */
- foreach_node(n, AST_TRAIT(node).body) {
- if (n->node_type != AST_PROC)
+ foreach_node(n, trait_body(node)) {
+ if (n->k != AST_PROC_DEF)
continue;
- if (AST_PROC(n).body)
+ if (proc_body(n))
continue;
/* prototypes are checked only if there's no implementation */
- if (scope_find_proc(trait_scope, AST_PROC(n).id))
+ if (scope_find_proc(trait_scope, proc_id(n)))
continue;
if (analyze_visibility(trait_scope, n))
return -1;
}
- foreach_node(n, AST_TRAIT(node).body) {
- if (n->node_type != AST_PROC)
+ foreach_node(n, trait_body(node)) {
+ if (n->k != AST_PROC_DEF)
continue;
if (analyze_proc(trait_scope, n))
return -1;
}
+ node->t = tgen_trait(strdup(struct_id(node)), node, node->loc);
+
return 0;
}
-static int analyze_signs(struct scope *scope, struct ast_node *node)
+static int analyze_signs(struct scope *scope, struct ast *node)
{
/** @todo aliases? */
- switch (node->node_type) {
- case AST_VAR: return analyze_var(scope, node); break;
- case AST_PROC: return analyze_proc(scope, node); break;
- case AST_STRUCT: return analyze_struct(scope, node); break;
- case AST_TRAIT: return analyze_trait(scope, node); break;
+ switch (node->k) {
+ case AST_VAR_DEF: return analyze_var(scope, node); break;
+ case AST_PROC_DEF: return analyze_proc(scope, node); break;
+ case AST_STRUCT_DEF: return analyze_struct(scope, node); break;
+ case AST_TRAIT_DEF: return analyze_trait(scope, node); break;
default:
}
return 0;
}
-static int analyze(struct scope *scope, struct ast_node *tree)
+static int analyze(struct scope *scope, struct ast *tree)
{
foreach_node(node, tree) {
if (analyze_visibility(scope, node))
@@ -707,13 +697,13 @@ static int analyze(struct scope *scope, struct ast_node *tree)
return -1;
printf("//actualized:\n");
- dump_ast_node(0, node);
+ ast_dump(0, node);
}
return 0;
}
-int analyze_root(struct scope *scope, struct ast_node *tree)
+int analyze_root(struct scope *scope, struct ast *tree)
{
if (analyze(scope, tree))
return -1;
@@ -721,22 +711,13 @@ int analyze_root(struct scope *scope, struct ast_node *tree)
return 0;
}
-static int structs_match(struct ast_node *a, struct ast_node *b)
+static int structs_match(struct type *a, struct type *b)
{
- /** @todo: iterate over elements in structure */
- /** @todo: check tag as well? */
- return 0;
+ /* dunno, let's go with this for now */
+ return a->d == b->d;
}
-static int primitives_match(struct ast_node *a, struct ast_node *b)
-{
- enum ast_primitive at = AST_PRIMITIVE_TYPE(a).type;
- enum ast_primitive bt = AST_PRIMITIVE_TYPE(b).type;
-
- return at == bt;
-}
-
-int types_match(struct ast_node *a, struct ast_node *b)
+int types_match(struct type *a, struct type *b)
{
if (!a && !b)
return 1;
@@ -744,111 +725,85 @@ int types_match(struct ast_node *a, struct ast_node *b)
if (!a || !b)
return 0;
- assert(a->node_type == AST_TYPE);
- assert(b->node_type == AST_TYPE);
-
/* if the type kind doesn't match, we're done. */
- if (AST_TYPE(a).kind != AST_TYPE(b).kind)
+ if (a->k != b->k)
return 0;
- if (AST_TYPE(a).kind == AST_TYPE_STRUCT)
+ if (a->k == TYPE_STRUCT)
return structs_match(a, b);
- if (AST_TYPE(a).kind == AST_TYPE_POINTER)
- return types_match(AST_PTR_TYPE(a).base,
- AST_PTR_TYPE(b).base);
-
- if (AST_TYPE(a).kind == AST_TYPE_PRIMITIVE)
- return primitives_match(a, b);
+ if (a->k == TYPE_PTR)
+ return types_match(ptr_base(a), ptr_base(b));
- return 0;
+ return 1;
}
-static int _replace_id(struct ast_node *node, void *data)
+static int _replace_id(struct ast *node, void *data)
{
if (!node)
return 0;
- if (node->node_type != AST_ID)
- return ast_call_on(_replace_id, node, data);
+ if (node->k != AST_ID)
+ return 0;
- struct ast_node **pair = data;
- struct ast_node *id = pair[0];
- struct ast_node *expr = pair[1];
+ struct ast **pair = data;
+ struct ast *id = pair[0];
+ struct ast *expr = pair[1];
- if (!same_id(node, id))
- return ast_call_on(_replace_id, node, data);
+ /* no match, continue */
+ if (!same_id(id_str(node), id_str(id)))
+ return 0;
- struct ast_node *clone = clone_ast_node(expr);
+ struct ast *clone = clone_ast(expr);
if (!clone) {
internal_error("failed cloning replacement expr");
return -1;
}
- clone->next = node->next;
+ clone->n = node->n;
clone->scope = node->scope;
- *node = *clone;
+ replace_ast(node, clone);
/* a succesful replacement needs no futher replacements, I think */
return 0;
}
-static int replace_id(struct ast_node *body, struct ast_node *id,
- struct ast_node *expr)
+static int replace_id(struct ast *body, struct ast *id,
+ struct ast *expr)
{
- struct ast_node *pair[2] = {id, expr};
- return ast_call_on(_replace_id, body, pair);
+ struct ast *pair[2] = {id, expr};
+ return ast_visit(_replace_id, NULL, body, pair);
}
-static int actualize_macro_construct(struct act_state *state,
- struct scope *scope, struct ast_node *n)
+static int actualize_macro_def(struct act_state *state,
+ struct scope *scope, struct ast *n)
{
UNUSED(state);
/* macro bodies, arguments, etc aren't expanded upon until the macro is
* called, so just try to add it to the local scope */
- assert(n && n->node_type == AST_MACRO_CONSTRUCT);
+ assert(n && n->k == AST_MACRO_DEF);
return scope_add_macro(scope, n);
}
-struct ast_node *extract_trait(struct ast_node *type)
-{
- if (!type)
- return 0;
-
- assert(type->node_type == AST_TYPE);
- if (type->_type.kind == AST_TYPE_TRAIT)
- return type;
-
- return extract_trait(type->_type.next);
-}
-
-static void actualize_trait_types(struct ast_node *params,
- struct ast_node *args)
-{
- /** @todo replace trait types with arg types, should probably be merged
- * */
- assert(!args && !params);
-}
-
static int actualize_macro_expand(struct act_state *state,
struct scope *scope,
- struct ast_node *macro_expand)
+ struct ast *macro_expand)
{
- assert(macro_expand->node_type == AST_MACRO_EXPAND);
- struct ast_node *id = AST_MACRO_EXPAND(macro_expand).id;
- struct ast_node *macro = file_scope_find_macro(scope, id);
+ assert(macro_expand->k == AST_MACRO_EXPAND);
+ char *id = macro_expand_id(macro_expand);
+ struct ast *macro = file_scope_find_macro(scope, id);
if (!macro) {
semantic_error(scope->fctx, macro_expand, "no such macro");
return -1;
}
- assert(macro->node_type == AST_MACRO_CONSTRUCT);
+ assert(macro->k == AST_MACRO_DEF);
if (ast_flags(macro, AST_FLAG_VARIADIC)) {
semantic_error(scope->fctx, macro,
"variadic macros not yet implemented");
return -1;
}
- struct ast_node *body = clone_ast_node(AST_MACRO_CONSTRUCT(macro).body);
+ struct ast *body = clone_ast(macro_def_body(macro));
if (!body) {
internal_error("failed allocating body for macro expansion");
return -1;
@@ -856,63 +811,79 @@ static int actualize_macro_expand(struct act_state *state,
/** @todo update all macro IDs to the correct scope */
body->scope = macro_expand->scope;
- body->next = macro_expand->next;
+ body->n = macro_expand->n;
- struct ast_node *param = AST_MACRO_CONSTRUCT(macro).params;
- struct ast_node *arg = AST_MACRO_EXPAND(macro_expand).args;
+ struct ast *param = macro_def_params(macro);
+ struct ast *arg = macro_expand_args(macro_expand);
- /* TODO: actual replacements */
while (param && arg) {
/* feels slightly hacky, but essentially replace each individual
* component in the arg list by breaking it out of the list
* temporarily. After the replacement, insert it back into the
* list so the cleanup is easier. */
- struct ast_node *next_arg = arg->next;
- arg->next = NULL;
+ struct ast *next_arg = arg->n;
+ arg->n = NULL;
if (replace_id(body, param, arg)) {
semantic_error(scope->fctx, macro_expand,
"failed replacing params with args");
- arg->next = next_arg;
+ arg->n = next_arg;
return -1;
}
- param = param->next;
- arg = arg->next = next_arg;
+ param = param->n;
+ arg = arg->n = next_arg;
}
+ free(macro_expand_id(macro_expand));
*macro_expand = *body;
/* actualize the new content */
return actualize(state, scope, macro_expand);
}
static int actualize_call(struct act_state *state,
- struct scope *scope, struct ast_node *call)
+ struct scope *scope, struct ast *call)
{
- assert(call && call->node_type == AST_CALL);
+ assert(call && call->k == AST_CALL);
- /* check that arguments exist, make sure they have types etc. */
- /* TODO: procedure callbacks? */
- int ret = actualize(state, scope, AST_CALL(call).args);
- if (ret)
- return ret;
+ if (actualize_list(state, scope, call_args(call)))
+ return -1;
- ret = actualize(state, scope, AST_CALL(call).expr);
- if (ret)
- return ret;
+ if (actualize_list(state, scope, call_expr(call)))
+ return -1;
- semantic_info(scope->fctx, call, "FIXME: skipping type checks for now");
- 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",
+ struct ast *expr = call_expr(call);
+ if (expr->t->k != TYPE_CALLABLE) {
+ char *tstr = type_str(expr->t);
+ semantic_error(scope->fctx, call, "not a callable type: %s",
tstr);
free(tstr);
return -1;
}
- struct ast_node *sign = expr->type;
- set_type(call, AST_SIGN_TYPE(sign).ret);
+ struct type *callable = expr->t;
+ struct type *ptypes = callable_ptypes(callable);
+ struct ast *arg = call_args(call);
+ foreach_type(p, ptypes) {
+ if (!arg) {
+ semantic_error(scope->fctx, call, "too many arguments");
+ return -1;
+ }
+
+ if (!types_match(p, arg->t)) {
+ type_mismatch(scope, arg, p, arg->t);
+ return -1;
+ }
+
+ arg = arg->n;
+ }
+
+ if (arg) {
+ semantic_error(scope->fctx, arg, "too many arguments");
+ return -1;
+ }
+
+ set_type(call, callable_rtype(callable));
return 0;
}
@@ -923,7 +894,7 @@ static void warn_unused_labels(struct act_state *state, struct scope *scope)
return;
do {
- struct ast_node *label = labels->node;
+ struct ast *label = labels->node;
if (!ast_flags(label, AST_FLAG_ACTUAL))
semantic_warn(scope->fctx, label,
"unused label");
@@ -939,7 +910,7 @@ static int undefined_gotos(struct act_state *state, struct scope *scope)
return ret;
do {
- struct ast_node *got = gotos->node;
+ struct ast *got = gotos->node;
if (!ast_flags(got, AST_FLAG_ACTUAL)) {
semantic_warn(scope->fctx, got,
"undefined label");
@@ -952,39 +923,35 @@ static int undefined_gotos(struct act_state *state, struct scope *scope)
}
static int actualize_proc(struct act_state *state,
- struct scope *scope, struct ast_node *proc)
+ struct scope *scope, struct ast *proc)
{
+ UNUSED(state);
/* actualize_proc is called on trait procs as well, but I believe
* that's fine? */
- assert(proc && proc->node_type == AST_PROC);
- struct ast_node *sign = AST_PROC(proc).sign;
+ assert(proc && proc->k == AST_PROC_DEF);
- /* signature should already be typed etc. */
struct act_state new_state = {0};
- if (actualize(&new_state, proc->scope, sign))
- return -1;
-
- set_type(proc, sign);
+ /* params should already have been actualized, should maybe check */
/* actualize body */
new_state.cur_proc = proc;
- if (actualize(&new_state, proc->scope, AST_PROC(proc).body))
+ if (actualize(&new_state, proc->scope, proc_body(proc)))
return -1;
if (!act_flags(&new_state, ACT_HAS_RETURN)) {
- if (!is_void(AST_SIGN_TYPE(sign).ret)) {
+ if (!is_void(proc_rtype(proc))) {
semantic_error(scope->fctx, proc,
"no return with non-void return type");
return -1;
}
/* add 'implicit' return */
- struct ast_node *body = AST_PROC(proc).body;
- struct ast_node *r = gen_return(NULL, NULL_LOC());
+ struct ast *body = proc_body(proc);
+ struct ast *r = gen_return(NULL, NULL, NULL_LOC());
r->scope = body->scope;
- ast_append(AST_BLOCK(body).body, r);
+ ast_append(block_body(body), r);
}
- else if (ast_block_last(AST_PROC(proc).body)->node_type != AST_RETURN) {
+ else if (ast_block_last(proc_body(proc))->k != AST_RETURN) {
/* TODO: something more sophisticated than this */
semantic_warn(scope->fctx, proc,
"unable to determine explicit return for all branches");
@@ -996,63 +963,41 @@ static int actualize_proc(struct act_state *state,
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);
+ char *id = proc_id(proc);
+ if (strcmp("main", id) == 0)
+ ast_set_flags(proc, AST_FLAG_NOMANGLE);
/* we have successfully actualized the procedure */
return 0;
}
static int actualize_binop(struct act_state *state,
- struct scope *scope, struct ast_node *binop)
+ struct scope *scope, struct ast *binop)
{
- assert(binop && binop->node_type == AST_BINOP);
+ assert(binop && is_binop(binop));
- struct ast_node *left = AST_BINOP(binop).left;
- struct ast_node *right = AST_BINOP(binop).right;
-
- int ret = 0;
- ret |= actualize(state, scope, left);
- ret |= actualize(state, scope, right);
- if (ret)
- return ret;
+ struct ast *left = binop_left(binop);
+ struct ast *right = binop_right(binop);
- if (!left->type) {
- semantic_error(scope->fctx, binop,
- "unable to detect lefthand type");
+ if (actualize(state, scope, left))
return -1;
- }
- if (!right->type) {
- semantic_error(scope->fctx, binop,
- "unable to detect righthand type");
+ if (actualize(state, scope, right))
return -1;
- }
- if (!types_match(left->type, right->type)) {
- char *left_type = type_str(left);
- char *right_type = type_str(right);
- semantic_error(scope->fctx, binop,
- "type mismatch (%s vs %s)", left_type,
- right_type);
- free(left_type);
- free(right_type);
+ if (!types_match(left->t, right->t)) {
+ type_mismatch(scope, binop, left->t, right->t);
return -1;
}
- /* TODO: also check trait types, just because two traits collapse
- * to the same actual type doesn't mean that the two trait types
- * should be allowed to operate on eachother */
-
/* types are the same, so the type of this expression is whichever */
- set_type(binop, left->type);
+ set_type(binop, left->t);
return 0;
}
static int actualize_block(struct act_state *state,
- struct scope *scope, struct ast_node *node)
+ struct scope *scope, struct ast *node)
{
struct scope *block_scope = scope;
if (!ast_flags(node, AST_FLAG_UNHYGIENIC)) {
@@ -1066,20 +1011,21 @@ static int actualize_block(struct act_state *state,
}
struct act_stack *defers = state->defer_stack;
- foreach_node(pt, node->_block.body) {
+ foreach_node(pt, block_body(node)) {
if (actualize(state, block_scope, pt))
return -1;
}
- if (node->_block.body == NULL) {
- node->type = void_type();
- node->_block.body = gen_empty();
+ if (block_body(node) == NULL) {
+ node->t = void_type();
+ /* still not a huge fan of directly mucking about with ast slots */
+ block_body(node) = gen_empty(NULL_LOC());
return 0;
}
/* the block type is the last statement in the block's type */
- set_type(node, ast_last_node(node->_block.body)->type);
- if (!node->type) {
+ set_type(node, ast_last(block_body(node))->t);
+ if (!node->t) {
semantic_error(scope->fctx, node,
"unable to detect block type");
return -1;
@@ -1088,8 +1034,8 @@ static int actualize_block(struct act_state *state,
/* TODO: currently defers are sort of duplicated after a return, unsure
* if they should be handled here or somewhere else */
if (state->defer_stack) {
- node->_block.defers = clone_defers(state, defers);
- if (!node->_block.defers) {
+ block_defers(node) = clone_defers(state, defers);
+ if (!block_defers(node)) {
internal_error("failed cloning defers");
return -1;
}
@@ -1101,10 +1047,10 @@ static int actualize_block(struct act_state *state,
}
static int actualize_id(struct act_state *state,
- struct scope *scope, struct ast_node *id)
+ struct scope *scope, struct ast *id)
{
UNUSED(state);
- assert(id && id->node_type == AST_ID);
+ assert(id && id->k == AST_ID);
id->scope = scope;
/** @todo vars and procs kind of override eachother, i.e.
@@ -1119,16 +1065,16 @@ static int actualize_id(struct act_state *state,
* Either add in some syntax to distinguish procedure calls and
* pointer calls or make procs and vars share the same namespace.
* */
- struct ast_node *decl = file_scope_find_var(scope, id);
+ struct ast *decl = file_scope_find_var(scope, id_str(id));
if (decl) {
- set_type(id, decl->type);
+ set_type(id, decl->t);
decl->uses++;
return 0;
}
- decl = file_scope_find_proc(scope, id);
+ decl = file_scope_find_proc(scope, id_str(id));
if (decl) {
- set_type(id, decl->type);
+ set_type(id, decl->t);
decl->uses++;
return 0;
}
@@ -1138,320 +1084,268 @@ static int actualize_id(struct act_state *state,
}
static int actualize_var(struct act_state *state,
- struct scope *scope, struct ast_node *var)
+ struct scope *scope, struct ast *var)
{
- assert(var && var->node_type == AST_VAR);
- struct ast_node *init = AST_VAR(var).init;
- struct ast_node *type = AST_VAR(var).type;
+ assert(var && var->k == AST_VAR_DEF);
+ struct ast *init = var_init(var);
+ struct type *type = var_type(var);
/* one of these must be defined, otherwise the parser fucked up */
assert(type || init);
- if (init && actualize(state, scope, init))
+ if (init && actualize_list(state, scope, init))
return -1;
- if (type && actualize(state, scope, type))
+ if (type && actualize_type_list(state, scope, type))
return -1;
- if (init && init->node_type == AST_INIT) {
- assert(!init->type);
+ if (init && init->k == AST_INIT) {
+ assert(!init->t);
set_type(init, type);
/* TODO: some kind of check_init() */
}
if (init && type) {
/* make sure the asked type and the actualized types match */
- if (!types_match(init->type, type)) {
- char *init_type = type_str(init->type);
- char *req_type = type_str(type);
- semantic_error(scope->fctx, var,
- "type mismatch (%s vs %s)",
- req_type, init_type);
- free(init_type);
- free(req_type);
+ if (!types_match(init->t, type)) {
+ type_mismatch(scope, var, init->t, type);
return -1;
}
}
- /* this is important for lowering */
- AST_VAR(var).id->scope = scope;
var->scope = scope;
if (init)
/* infer */
- set_type(var, init->type);
+ set_type(var, init->t);
if (type)
- /* TODO: should there be some default value? */
+ /* TODO: should there be some default zero value? */
/* declare */
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
* of warnings) */
- if (AST_VAR(var).id && !ast_flags(var, AST_FLAG_MEMBER))
+ if (var_id(var) && !ast_flags(var, AST_FLAG_MEMBER))
return scope_add_var(scope, var);
- /* TODO: we should make sure the type is fully qualified in bodies */
return 0;
}
-#define ENTER_ACT() \
- enum act_flags old_flags = state->flags; \
- struct ast_node *old_trait = state->cur_trait;
-
-#define EXIT_ACT(r) \
- do { \
- state->cur_trait = old_trait; \
- state->flags = old_flags; \
- return r; \
- } while (0);
-
-static enum ast_primitive id_to_primitive(struct ast_node *id)
+static int actualize_tid(struct act_state *state, struct scope *scope, struct type *t)
{
- const char *name = AST_ID(id).id;
- if (strcmp(name, "i27") == 0)
- return AST_I27;
+ UNUSED(state);
- if (strcmp(name, "i9") == 0)
- return AST_I9;
+ /* no id means void */
+ if (!t->id) {
+ replace_type(t, void_type());
+ return 0;
+ }
- if (strcmp(name, "bool") == 0)
- return AST_BOOL;
+ struct src_loc l = t->loc;
- /** @todo some better error reporting should probably be used */
- internal_error( "illegal primitive: %s\n", name);
- return AST_VOID;
-}
+ struct ast *def = file_scope_find_type(scope, t->id);
+ if (!def) {
+ type_error(scope->fctx, t, "no such type");
+ return -1;
+ }
-static int struct_is_primitive(struct ast_node *s)
-{
- struct ast_node *id = AST_STRUCT(s).id;
- const char *name = AST_ID(id).id;
- if (strcmp(name, "i27") == 0)
- return 1;
+ assert(t->n == NULL);
+ assert(def->k != AST_TRAIT_DEF);
- if (strcmp(name, "i9") == 0)
- return 1;
+ if (def->k == AST_ALIAS_DEF) {
+ replace_type(t, clone_type_list(def->t));
+ t->a = def;
+ return 0;
+ }
+ else if (def->k == AST_STRUCT_DEF) {
+ replace_type(t, clone_type_list(def->t));
+ return 0;
+ }
+ else if (def->k == AST_ENUM_DEF) {
+ replace_type(t, clone_type_list(def->t));
+ return 0;
+ }
- if (strcmp(name, "bool") == 0)
- return 1;
+ return -1;
+}
- /* special case of a special case?
- if (strcmp(name, "str"))
- return 1;
- */
+static int actualize_ptr(struct act_state *state, struct scope *scope, struct type *t)
+{
+ assert(ptr_base(t));
+ if (actualize_type(state, scope, ptr_base(t)))
+ return -1;
return 0;
}
-static int actualize_type(struct act_state *state,
- struct scope *scope, struct ast_node *type)
+static int actualize_callable(struct act_state *state, struct scope *scope, struct type *t)
{
- /* TODO: there's gotta be a better way to handle flags. Maybe macros
- * like ENTER_ACTUALIZE and EXIT_ACTUALIZE? */
- /* TODO: get rid of aliases, expand implements, fill out structures,
- * etc. */
- assert(type->node_type == AST_TYPE);
- ENTER_ACT();
+ struct type *ptypes = callable_ptypes(t);
+ struct type *rtype = callable_rtype(t);
- if (actualize(state, scope, AST_TYPE(type).next)) {
- EXIT_ACT(-1);
+ foreach_type(p, ptypes){
+ if (actualize_type(state, scope, p))
+ return -1;
}
- switch (AST_TYPE(type).kind) {
- case AST_TYPE_ID: {
- /* type IDs can really only be aliases to something else, or if
- * they're missing, void */
- if (!AST_ID_TYPE(type).id) {
- /* no ID means void */
- AST_ID_TYPE(type).id =
- gen_id(strdup("void"), NULL_LOC());
- }
-
- struct ast_node *exists = file_scope_find_type(scope,
- AST_ID_TYPE(
- type).id);
- if (!exists) {
- semantic_error(scope->fctx, type, "no such type");
- EXIT_ACT(-1);
- }
+ if (!rtype)
+ callable_rtype(t) = void_type();
- if (exists->node_type == AST_TYPE) {
- assert(AST_TYPE(exists).kind == AST_TYPE_PRIMITIVE);
- AST_TYPE(type) = AST_TYPE(exists);
- break;
- }
+ if (actualize_type(state, scope, rtype))
+ return -1;
- /*
- if (actualize(state, exists->scope, exists))
- EXIT_ACT(-1);
- */
+ return 0;
+}
- assert(AST_TYPE(type).next == NULL);
- if (exists->node_type == AST_ALIAS) {
- AST_TYPE(type).aliased = exists;
- AST_TYPE(type) = AST_TYPE(exists);
- }
- 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);
- }
- 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);
- } else {
- *type = *gen_type(AST_TYPE_STRUCT, exists,
- NULL, exists->loc);
- }
- }
- else if (exists->node_type == AST_ENUM) {
- *type = *gen_type(AST_TYPE_ENUM, exists,
- NULL, exists->loc);
- }
+static int actualize_i27(struct act_state *state, struct scope *scope, struct type *t)
+{
+ /* not much to do */
+ if (t->d)
+ return 0;
- break;
+ struct ast *def = file_scope_find_type(scope, "i27");
+ if (!def) {
+ error("missing definition of type 'i27'");
+ return NULL;
}
- 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;
+ t->d = def;
+ return 0;
+}
- case AST_TYPE_ARR:
- /* TODO: expression should be expandable to integer constant */
- semantic_info(scope->fctx, type,
- "arrays unimplemented, continuing with compilation to see what breaks");
- break;
+static int actualize_i9(struct act_state *state, struct scope *scope, struct type *t)
+{
+ /* not much to do */
+ if (t->d)
+ return 0;
- case AST_TYPE_POINTER:
- assert(AST_PTR_TYPE(type).base);
- if (actualize(state, scope, AST_PTR_TYPE(type).base))
- EXIT_ACT(-1);
- break;
+ struct ast *def = file_scope_find_type(scope, "i9");
+ if (!def) {
+ error("missing definition of type 'i9'");
+ return NULL;
+ }
- case AST_TYPE_SIGN: {
- struct ast_node *params = AST_SIGN_TYPE(type).params;
- struct ast_node *ret = AST_SIGN_TYPE(type).ret;
+ t->d = def;
+ return 0;
+}
- foreach_node(p, params){
- if (actualize(state, scope, p))
- EXIT_ACT(-1);
- }
+static int actualize_bool(struct act_state *state, struct scope *scope, struct type *t)
+{
+ /* not much to do */
+ if (t->d)
+ return 0;
- if (!ret)
- ret = AST_SIGN_TYPE(type).ret = void_type();
+ struct ast *def = file_scope_find_type(scope, "bool");
+ if (!def) {
+ error("missing definition of type 'bool'");
+ return NULL;
+ }
- if (actualize(state, scope, ret))
- EXIT_ACT(-1);
+ t->d = def;
+ return 0;
+}
- break;
- }
+static int actualize_type(struct act_state *state,
+ struct scope *scope,
+ struct type *t)
+{
+ if (!t)
+ return 0;
- case AST_TYPE_TRAIT: {
- assert(ast_flags(type, AST_FLAG_ACTUAL));
- semantic_info(scope->fctx, type,
- "FIXME skipping trait type checks");
- break;
- }
+ t->scope = scope;
- case AST_TYPE_STRUCT: {
- assert(ast_flags(type, AST_FLAG_ACTUAL));
- semantic_info(scope->fctx, type,
- "FIXME skipping struct type checks");
- break;
- }
+ if (actualize_type(state, scope, t->n))
+ return -1;
- case AST_TYPE_PRIMITIVE: {
- assert(ast_flags(type, AST_FLAG_ACTUAL));
- semantic_info(scope->fctx, type,
- "FIXME skipping primitive type checks");
- break;
- }
+ switch (t->k) {
+ case TYPE_I27: return actualize_i27(state, scope, t);
+ case TYPE_I9: return actualize_i9(state, scope, t);
+ case TYPE_BOOL: return actualize_bool(state, scope, t);
+ case TYPE_ID: return actualize_tid(state, scope, t);
+ case TYPE_PTR: return actualize_ptr(state, scope, t);
+ case TYPE_CALLABLE: return actualize_callable(state, scope, t);
+ case TYPE_VOID: return 0; /* void is by default actualized */
default:
- semantic_error(scope->fctx, type, "unimplemented type");
- EXIT_ACT(-1);
+ type_info(scope->fctx, t,
+ "unimplemented type");
+ type_info(scope->fctx, t,
+ "continuing with compilation to see what breaks");
+ return 0;
}
- /* generally speaking */
- EXIT_ACT(0);
+ return 0;
}
-static int actualize_empty(struct act_state *state,
- struct scope *scope, struct ast_node *node)
+static int actualize_type_list(struct act_state *state,
+ struct scope *scope,
+ struct type *l)
{
- UNUSED(state);
- /* TODO: converting to void is common enough that it might be worth
- * 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");
- return -1;
- }
-
- node->type = gen_type(AST_TYPE_ID, void_id, NULL, NULL_LOC());
- if (!node->type) {
- internal_error("couldn't allocate type for empty statement\n");
- return -1;
+ foreach_type(t, l) {
+ if (actualize_type(state, scope, t))
+ return -1;
}
return 0;
}
-static int integral_type(struct ast_node *type)
+static int actualize_empty(struct act_state *state,
+ struct scope *scope, struct ast *node)
{
- assert(type->node_type == AST_TYPE);
- if (AST_TYPE(type).kind != AST_TYPE_PRIMITIVE)
- return 0;
+ UNUSED(state);
+ UNUSED(scope);
+ node->t = void_type();
+ return 0;
+}
- /* here would be awesome with an enum of our base types */
- enum ast_primitive p = AST_PRIMITIVE_TYPE(type).type;
- switch (p) {
- case AST_I9: return 1;
- case AST_I27: return 1;
- default: return 0;
+static int integral_type(struct type *type)
+{
+ switch (type->k) {
+ case TYPE_I27:
+ case TYPE_I9:
+ case TYPE_BOOL:
+ return true; /* maybe? */
+ default:
}
- return 0;
+ return false;
}
-static int pointer_type(struct ast_node *type)
+static int pointer_type(struct type *type)
{
- assert(type->node_type == AST_TYPE);
- return type->_type.kind == AST_TYPE_POINTER;
+ return type->k == TYPE_PTR;
}
-static int pointer_conversion(struct ast_node *a, struct ast_node *b)
+static int pointer_conversion(struct type *a, struct type *b)
{
- assert(a->node_type == AST_TYPE);
- assert(b->node_type == AST_TYPE);
if (pointer_type(a)) {
- if (AST_TYPE(b).kind != AST_TYPE_PRIMITIVE)
+ if (!is_primitive(b))
return 0;
/* for now */
- return AST_PRIMITIVE_TYPE(b).type == AST_I27;
+ return b->k == TYPE_I27;
}
return 0;
}
-static size_t member_count(struct ast_node *exists)
+static size_t member_count(struct ast *exists)
{
- assert(exists->node_type == AST_STRUCT);
- struct ast_node *body = exists->_struct.body;
- return ast_list_len(body);
+ assert(exists->k == AST_STRUCT_DEF);
+ struct ast *body = struct_body(exists);
+
+ size_t count = 0;
+ foreach_node(n, body) {
+ if (n->k == AST_VAR_DEF)
+ count++;
+ }
+
+ return count;
}
-static struct ast_node *lookup_member_idx(struct ast_node *body,
- struct ast_node *find,
+static struct ast *lookup_member_idx(struct ast *body,
+ char *find,
size_t *idx)
{
/* micro-optimisation, likely way premature but speeds up selection
@@ -1459,27 +1353,26 @@ static struct ast_node *lookup_member_idx(struct ast_node *body,
(void)(find);
assert(idx);
size_t i = *idx;
- struct ast_node *m = body;
+ struct ast *m = body;
while (i != 0 && m) {
- m = m->next;
+ m = m->n;
i--;
}
return m;
}
-static struct ast_node *lookup_member_name(struct ast_node *body,
- struct ast_node *find,
+static struct ast *lookup_member_name(struct ast *body,
+ char *find,
size_t *idx)
{
- assert(find->node_type == AST_ID);
size_t i = 0;
- struct ast_node *m = body;
+ struct ast *m = body;
while (m) {
- assert(m->node_type == AST_VAR);
- if (same_id(find, AST_VAR(m).id))
+ assert(m->k == AST_VAR_DEF);
+ if (same_id(find, var_id(m)))
break;
- m = m->next;
+ m = m->n;
i++;
}
@@ -1489,25 +1382,25 @@ static struct ast_node *lookup_member_name(struct ast_node *body,
return m;
}
-static struct ast_node *lookup_struct_member(struct ast_node *struc,
- struct ast_node *find, size_t *idx)
+static struct ast *lookup_struct_member(struct ast *struc,
+ char *find, size_t *idx)
{
if (find)
- return lookup_member_name(struc->_struct.body, find, idx);
+ return lookup_member_name(struct_body(struc), find, idx);
- return lookup_member_idx(struc->_struct.body, find, idx);
+ return lookup_member_idx(struct_body(struc), find, idx);
}
-static struct ast_node *lookup_enum_member(struct ast_node *enu,
- struct ast_node *find)
+static struct ast *lookup_enum_member(struct ast *enu,
+ char *find)
{
size_t i = 0;
- struct ast_node *m = enu->_enum.body;
+ struct ast *m = enum_body(enu);
while (m) {
- assert(m->node_type == AST_VAL);
- if (same_id(find, AST_VAL(m).id))
+ assert(m->k == AST_VAL);
+ if (same_id(find, val_id(m)))
break;
- m = m->next;
+ m = m->n;
i++;
}
@@ -1515,7 +1408,7 @@ static struct ast_node *lookup_enum_member(struct ast_node *enu,
}
static int init_struct(struct act_state *state, struct scope *scope,
- struct ast_node *exists, struct ast_node *init)
+ struct ast *exists, struct ast *init)
{
size_t i = 0;
size_t mcount = member_count(exists);
@@ -1527,7 +1420,7 @@ static int init_struct(struct act_state *state, struct scope *scope,
return -1;
}
- struct ast_node *args = init->_init.body;
+ struct ast *args = init_body(init);
while (args) {
if (i >= mcount) {
semantic_error(scope->fctx, args,
@@ -1546,15 +1439,15 @@ static int init_struct(struct act_state *state, struct scope *scope,
if ((ret = actualize(state, scope, args)))
break;
- struct ast_node *find = NULL;
+ char *find = NULL;
if (ast_flags(args, AST_FLAG_MEMBER))
- find = args->_var.id;
+ find = var_id(args);
- struct ast_node *member =
+ struct ast *member =
lookup_struct_member(exists, find, &i);
if (!member) {
- char *sstr = type_str(exists->type);
+ char *sstr = type_str(exists->t);
semantic_error(scope->fctx, args,
"no such member in %s",
sstr);
@@ -1563,9 +1456,9 @@ static int init_struct(struct act_state *state, struct scope *scope,
break;
}
- if (!types_match(args->type, member->type)) {
- char *astr = type_str(args->type);
- char *mstr = type_str(member->type);
+ if (!types_match(args->t, member->t)) {
+ char *astr = type_str(args->t);
+ char *mstr = type_str(member->t);
semantic_error(scope->fctx, args,
"%s does not match %s", astr, mstr);
free(astr);
@@ -1575,7 +1468,7 @@ static int init_struct(struct act_state *state, struct scope *scope,
}
initd[i] = 1;
- args = args->next;
+ args = args->n;
i++;
}
@@ -1585,108 +1478,70 @@ static int init_struct(struct act_state *state, struct scope *scope,
static int actualize_struct_init_cast(struct act_state *state,
struct scope *scope,
- struct ast_node *init,
- struct ast_node *actual)
+ struct ast *init,
+ struct type *type)
{
- struct ast_node *def = AST_STRUCT_TYPE(actual).def;
+ struct ast *def = type->d;
return init_struct(state, scope, def, init);
}
static int actualize_init_cast(struct act_state *state,
- struct scope *scope, struct ast_node *init,
- struct ast_node *type)
+ struct scope *scope, struct ast *init,
+ struct type *type)
{
- if (AST_TYPE(type).kind == AST_TYPE_STRUCT)
+ if (type->k == TYPE_STRUCT)
return actualize_struct_init_cast(state, scope, init, type);
- semantic_error(scope->fctx, type,
+ type_error(scope->fctx, type,
"type is not a struct");
return -1;
}
-static int proc_pointer(struct ast_node *type)
-{
- if (type->_type.kind != AST_TYPE_POINTER)
- return 0;
-
- struct ast_node *next = type->_type.next;
- if (next->_type.kind != AST_TYPE_SIGN)
- return 0;
-
- return 1;
-}
-
-static int proc_choice(struct ast_node *expr, struct ast_node *type)
-{
- if (expr->node_type != AST_ID)
- return 0;
-
- if (!proc_pointer(type))
- return 0;
-
- return 1;
-}
-
-/* still slightly unsure about this, but hey ho */
-static int match_proc(struct act_state *state, struct scope *scope,
- struct ast_node *cast)
-{
- (void)(state);
- semantic_error(scope->fctx, cast,
- "procedure signature casts not yet implemented");
- return -1;
-}
-
static int actualize_cast(struct act_state *state,
- struct scope *scope, struct ast_node *cast)
+ struct scope *scope, struct ast *cast)
{
- assert(cast->node_type == AST_CAST);
- struct ast_node *expr = cast->_cast.expr;
- struct ast_node *type = cast->_cast.type;
+ assert(cast->k == AST_CAST);
+ struct ast *expr = cast_expr(cast);
+ struct type *type = cast_type(cast);
- if (actualize(state, scope, type))
+ if (actualize_type(state, scope, type))
return -1;
- if (proc_choice(expr, type)) {
- set_type(cast, type);
- return match_proc(state, scope, cast);
- }
-
if (actualize(state, scope, expr))
return -1;
- if (expr->node_type == AST_INIT) {
+ if (expr->k == AST_INIT) {
set_type(cast, type);
return actualize_init_cast(state, scope, expr, type);
}
- if (types_match(expr->type, type)) {
+ if (types_match(expr->t, type)) {
set_type(cast, type);
return 0;
}
- if (integral_type(expr->type) && integral_type(type)) {
+ if (integral_type(expr->t) && integral_type(type)) {
set_type(cast, type);
return 0;
}
- if (pointer_type(expr->type) && pointer_type(type)) {
+ if (pointer_type(expr->t) && pointer_type(type)) {
set_type(cast, type);
return 0;
}
- if (pointer_conversion(expr->type, type)
- || pointer_conversion(type, expr->type)) {
+ if (pointer_conversion(expr->t, type)
+ || pointer_conversion(type, expr->t)) {
set_type(cast, type);
return 0;
}
/* TODO: arrays? */
- char *left_type = type_str(expr);
+ char *left_type = type_str(expr->t);
char *right_type = type_str(type);
- semantic_error(scope->fctx, cast, "illegal cast (%s vs %s)",
+ semantic_error(scope->fctx, cast, "illegal cast: %s vs %s",
left_type, right_type);
free(left_type);
free(right_type);
@@ -1694,17 +1549,22 @@ static int actualize_cast(struct act_state *state,
}
static int actualize_const(struct act_state *state, struct scope *scope,
- struct ast_node *cons)
+ struct ast *cons)
{
UNUSED(state);
- assert(cons->node_type == AST_CONST);
- if (AST_CONST(cons).kind == AST_CONST_INTEGER)
- cons->type = i27_type(scope);
+ if (cons->k == AST_CONST_INT)
+ cons->t = i27_type(scope);
+
+ else if (cons->k == AST_CONST_CHAR)
+ cons->t = i9_type(scope);
- else if (AST_CONST(cons).kind == AST_CONST_STRING)
- cons->type = str_type(scope);
+ else if (cons->k == AST_CONST_BOOL)
+ cons->t = bool_type(scope);
- if (cons->type)
+ else if (cons->k == AST_CONST_STR)
+ cons->t = str_type(scope);
+
+ if (cons->t)
return 0;
semantic_error(scope->fctx, cons, "unimplemented constant");
@@ -1712,13 +1572,13 @@ static int actualize_const(struct act_state *state, struct scope *scope,
}
static int actualize_alias(struct act_state *state, struct scope *scope,
- struct ast_node *alias)
+ struct ast *alias)
{
/* I shall have to think about things, as currently very deeply nested
* aliases might be a bit cumbersome to work with. Still, this works
* well enough I suppose. */
- assert(alias->node_type == AST_ALIAS);
- if (actualize(state, scope, AST_ALIAS(alias).type)) {
+ assert(alias->k == AST_ALIAS_DEF);
+ if (actualize_type(state, scope, alias_type(alias))) {
/* usually we don't want to output errors upon errors, but this
* is likely a useful message as it might show where a loop is
* occuring */
@@ -1731,9 +1591,9 @@ static int actualize_alias(struct act_state *state, struct scope *scope,
}
static int actualize_defer(struct act_state *state,
- struct scope *scope, struct ast_node *node)
+ struct scope *scope, struct ast *node)
{
- struct ast_node *expr = node->_defer.expr;
+ struct ast *expr = defer_expr(node);
/* TODO: should the actualization only happen when the defers are
* called? */
if (actualize(state, scope, expr))
@@ -1742,61 +1602,54 @@ static int actualize_defer(struct act_state *state,
if (push_defer(state, expr))
return -1;
- node->type = void_type();
+ node->t = void_type();
return 0;
}
static int actualize_return(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
act_set_flags(state, ACT_HAS_RETURN);
- struct ast_node *expr = node->_return.expr;
+ struct ast *expr = return_expr(node);
if (expr) {
if (actualize(state, scope, expr))
return -1;
- set_type(node, expr->type);
+ set_type(node, expr->t);
}
else {
- node->type = void_type();
+ node->t = void_type();
}
assert(state->cur_proc);
- struct ast_node *cur_proc = state->cur_proc;
- struct ast_node *sign = AST_PROC(cur_proc).sign;
- struct ast_node *ret = AST_SIGN_TYPE(sign).ret;
- if (!types_match(node->type, ret)) {
- char *rt = type_str(ret);
- char *et = type_str(node);
- semantic_error(scope->fctx, node,
- "return type mismatch: %s", et);
-
- semantic_info(scope->fctx, ret,
- "vs %s", rt);
- free(rt);
- free(et);
+ struct ast *cur_proc = state->cur_proc;
+ struct type *rtype = proc_rtype(cur_proc);
+ if (!types_match(node->t, rtype)) {
+ /* hmm, should this be "return type mismatch? */
+ type_mismatch(scope, node, rtype, node->t);
return -1;
}
if (state->defer_stack) {
- AST_RETURN(node).defers = clone_defers(state, NULL);
- if (!node->_return.defers) {
+ return_defers(node) = clone_defers(state, NULL);
+ if (!return_defers(node)) {
internal_error("failed cloning return defers");
return -1;
}
}
+
return 0;
}
/* Still slightly unsure if this works in all cases, but a good start
* nonetheless. */
-static void actualize_goto_defer(struct ast_node *got, struct ast_node *label)
+static void actualize_goto_defer(struct ast *got, struct ast *label)
{
- struct ast_node *goto_defers = AST_GOTO(got).defers;
- struct ast_node *label_defers = AST_LABEL(label).defers;
+ struct ast *goto_defers = goto_defers(got);
+ struct ast *label_defers = label_defers(label);
/* since we're dealing with singly linked lists, keep a reference to one
* node before the current goto defer. */
- struct ast_node *prev_defer = NULL;
+ struct ast *prev_defer = NULL;
/* this goto has a defined label */
ast_set_flags(got, AST_FLAG_ACTUAL);
@@ -1808,12 +1661,12 @@ static void actualize_goto_defer(struct ast_node *got, struct ast_node *label)
/* find first common defer statement */
while (goto_len > label_len) {
prev_defer = goto_defers;
- goto_defers = goto_defers->next;
+ goto_defers = goto_defers->n;
goto_len--;
}
while (label_len > goto_len) {
- label_defers = label_defers->next;
+ label_defers = label_defers->n;
label_len--;
}
@@ -1823,15 +1676,15 @@ static void actualize_goto_defer(struct ast_node *got, struct ast_node *label)
* unlikely that goto stuff would be a major bottleneck. */
while (!equiv_nodes(goto_defers, label_defers)) {
prev_defer = goto_defers;
- label_defers = label_defers->next;
- goto_defers = goto_defers->next;
+ label_defers = label_defers->n;
+ goto_defers = goto_defers->n;
}
/* only the defers below the common defer should be executed by the goto */
if (goto_defers) {
/* fuck, I actually need the one previous to this */
- assert(prev_defer->next == goto_defers);
- prev_defer->next = NULL;
+ assert(prev_defer->n == goto_defers);
+ prev_defer->n = NULL;
}
/* nothing to do */
@@ -1839,16 +1692,16 @@ static void actualize_goto_defer(struct ast_node *got, struct ast_node *label)
static int actualize_goto(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- assert(node->node_type == AST_GOTO);
+ assert(node->k == AST_GOTO);
push_goto(state, node);
/* clone all defers as we don't know where the label might be */
- node->_goto.defers = clone_defers(state, NULL);
- node->type = void_type();
+ goto_defers(node) = clone_defers(state, NULL);
+ node->t = void_type();
- struct ast_node *label = find_label(state, node->_goto.label);
+ struct ast *label = find_label(state, goto_label(node));
/* this is a jump backwards, i.e. we can already do it */
if (label)
actualize_goto_defer(node, label);
@@ -1858,24 +1711,24 @@ static int actualize_goto(struct act_state *state, struct scope *scope,
}
static void actualize_goto_defers(struct act_state *state,
- struct ast_node *label)
+ struct ast *label)
{
struct act_stack *prev = state->goto_stack, *cur;
if (prev)
do {
cur = prev->next;
- struct ast_node *got = prev->node;
- if (equiv_nodes(AST_GOTO(got).label, label))
+ struct ast *got = prev->node;
+ if (same_id(goto_label(got), label_id(label)))
actualize_goto_defer(got, label);
} while ((prev = cur));
}
static int actualize_label(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- assert(node->node_type == AST_LABEL);
- struct ast_node *prev = find_label(state, node);
+ assert(node->k == AST_LABEL);
+ struct ast *prev = find_label(state, label_id(node));
if (prev) {
semantic_error(scope->fctx, node, "label redefined");
semantic_info(scope->fctx, prev, "previous definition");
@@ -1884,60 +1737,65 @@ static int actualize_label(struct act_state *state, struct scope *scope,
push_label(state, node);
/* clone all defers */
- node->_label.defers = clone_defers(state, NULL);
- node->type = void_type();
+ label_defers(node) = clone_defers(state, NULL);
+ node->t = void_type();
actualize_goto_defers(state, node);
return 0;
}
static int actualize_unop(struct act_state *state,
- struct scope *scope, struct ast_node *node)
+ struct scope *scope, struct ast *node)
{
- assert(node->node_type == AST_UNOP);
- struct ast_node *expr = AST_UNOP(node).expr;
+ assert(is_unop(node));
+ struct ast *expr = unop_expr(node);
if (actualize(state, scope, expr))
return -1;
/* generally speaking */
- set_type(node, expr->type);
+ set_type(node, expr->t);
- switch (node->_unop.op) {
+ switch (node->k) {
case AST_DEREF: {
- struct ast_node *type = expr->type;
- if (AST_TYPE(type).kind != AST_TYPE_POINTER) {
- /* TODO: or array */
+ struct type *type = expr->t;
+ if (type->k!= TYPE_PTR) {
+ /** @todo or array? */
+ char *tstr = type_str(type);
semantic_error(scope->fctx, expr,
- "trying to dereference something that's not a pointer");
+ "not a pointer: %s",
+ tstr);
+ free(tstr);
return -1;
}
- set_type(node, AST_PTR_TYPE(type).base);
- assert(node->type);
+ set_type(node, ptr_base(type));
+ assert(node->t);
break;
}
case AST_REF: {
- node->type = gen_type(AST_TYPE_POINTER, NULL, NULL,
- NULL_LOC());
- set_type(node->AST_TYPE(type).next, expr->type);
+ /** @todo array pointer decay? */
+ node->t = tgen_ptr(clone_type(expr->t), node->loc);
break;
}
case AST_LNOT: {
- if (AST_TYPE(expr->type).kind != AST_TYPE_PRIMITIVE) {
+ if (is_primitive(expr->t)) {
+ char *tstr = type_str(expr->t);
semantic_error(scope->fctx, node,
- "'!' only implemented for primitive types");
+ "'!' only implemented for primitive types: %s",
+ tstr);
+ free(tstr);
return -1;
}
- if (AST_PRIMITIVE_TYPE(expr->type).type == AST_VOID) {
+ if (expr->t->k == TYPE_VOID) {
semantic_error(scope->fctx, node,
"'!' not implemented for void");
return -1;
}
- node->type = bool_type(scope);
+ node->t = bool_type(scope);
break;
}
@@ -1950,79 +1808,90 @@ static int actualize_unop(struct act_state *state,
}
static int actualize_as(struct act_state *state,
- struct scope *scope, struct ast_node *as)
+ struct scope *scope, struct ast *as)
{
- assert(as->node_type == AST_AS);
- struct ast_node *type = AST_AS(as).type;
- if (actualize(state, scope, type))
+ assert(as->k == AST_AS);
+ struct type *type = as->t;
+ if (actualize_type(state, scope, type))
return -1;
set_type(as, type);
return 0;
}
-static int _replace_type_id(struct ast_node *node, void *data)
-{
- if (!node)
- return 0;
+struct replace_data {
+ char *id;
+ struct type *replacement;
+};
- struct ast_node **pair = data;
- struct ast_node *id = pair[0];
- struct ast_node *replacement = pair[1];
+static int _replace_type_id(struct type *type, void *data)
+{
+ struct replace_data *pair = data;
+ struct type *replacement = pair->replacement;
+ char *id = pair->id;
- if (node->node_type != AST_TYPE)
- goto next;
+ switch (type->k) {
+ case TYPE_ID: {
+ replace_type(type, clone_type(replacement));
+ break;
+ }
- switch (AST_TYPE(node).kind) {
- case AST_TYPE_ID: *node = *clone_ast_node(replacement); break;
- case AST_TYPE_TRAIT: {
- struct ast_node *def = AST_TRAIT_TYPE(node).def;
+ case TYPE_TRAIT: {
+ struct ast *def = type->d;
assert(def);
- struct ast_node *name = AST_TRAIT(def).id;
+
+ char *name = trait_id(def);
if (same_id(id, name))
- *node = *clone_ast_node(replacement);
+ replace_type(type, clone_type(replacement));
break;
}
- case AST_TYPE_STRUCT: {
- struct ast_node *def = AST_STRUCT_TYPE(node).def;
+ case TYPE_STRUCT: {
+ struct ast *def = type->d;
assert(def);
- struct ast_node *name = AST_STRUCT(def).id;
+ char *name = struct_id(def);
if (same_id(id, name))
- *node = *clone_ast_node(replacement);
+ replace_type(type, clone_type(replacement));
break;
}
+
default:
}
-next:
- return ast_call_on(_replace_type_id, node, data);
+ return 0;
}
-static int replace_type_id(struct ast_node *nodes, struct ast_node *id,
- struct ast_node *replacement)
+static int _replace_ast_type_id(struct ast *node, void *data)
{
- assert(replacement->node_type == AST_TYPE);
- struct ast_node *pair[2] = {id, replacement};
- return ast_call_on(_replace_type_id, nodes, pair);
+ if (!node)
+ return 0;
+
+ return type_visit_list(_replace_type_id, NULL, node->t, data);
+}
+
+static int replace_type_id(struct ast *nodes, char *id,
+ struct type *replacement)
+{
+ struct replace_data pair = {id, replacement};
+ return ast_visit(_replace_ast_type_id, NULL, nodes, &pair);
}
/* lots of overlap with actualize_struct, kind of ugly... */
static int actualize_trait(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- assert(node->node_type == AST_TRAIT);
- foreach_node(n, AST_TRAIT(node).body) {
+ assert(node->k == AST_TRAIT_DEF);
+ foreach_node(n, trait_body(node)) {
/* there's really only prodcedure body actualization left I
* guess, as type stuff was taken care of in the analysis phase
* */
- if (n->node_type != AST_PROC)
+ if (n->k != AST_PROC_DEF)
continue;
/* don't actualize prototypes, duh */
- if (!AST_PROC(n).body)
+ if (!proc_body(n))
continue;
if (actualize(state, node->scope, n))
@@ -2033,18 +1902,18 @@ static int actualize_trait(struct act_state *state, struct scope *scope,
}
static int actualize_struct(struct act_state *state,
- struct scope *scope, struct ast_node *node)
+ struct scope *scope, struct ast *node)
{
- assert(node->node_type == AST_STRUCT);
- foreach_node(n, AST_STRUCT(node).body) {
+ assert(node->k == AST_STRUCT_DEF);
+ foreach_node(n, struct_body(node)) {
/* there's really only prodcedure body actualization left I
* guess, as type stuff was taken care of in the analysis phase
* */
- if (n->node_type != AST_PROC)
+ if (n->k != AST_PROC_DEF)
continue;
/* don't actualize prototypes, duh */
- if (!AST_PROC(n).body)
+ if (!proc_body(n))
continue;
if (actualize(state, node->scope, n))
@@ -2057,23 +1926,23 @@ static int actualize_struct(struct act_state *state,
/* could maybe be renamed, but essentially dot in copper works as either
* -> or . in C, so allow structures or traits and single level pointers to
* structures or traits. */
-static int has_members(struct ast_node *type)
+static int has_members(struct type *type)
{
/* most likely */
- if (AST_TYPE(type).kind == AST_TYPE_STRUCT)
+ if (type->k == TYPE_STRUCT)
return 1;
- if (AST_TYPE(type).kind == AST_TYPE_TRAIT)
+ if (type->k == TYPE_TRAIT)
return 1;
- if (AST_TYPE(type).kind == AST_TYPE_CONSTRUCT)
+ if (type->k == TYPE_CONSTRUCT)
return 1;
return 0;
}
static int actualize_dot(struct act_state *state,
- struct scope *scope, struct ast_node *node)
+ struct scope *scope, struct ast *node)
{
/* TODO: handle enums as well, idea is something like
* enum whatever {A_FLAG}
@@ -2083,19 +1952,18 @@ static int actualize_dot(struct act_state *state,
* possibly also if the expr is of type whatever then .A_FLAG just gets
* the corresponding constant?
**/
- assert(node->node_type == AST_DOT);
- struct ast_node *expr = AST_DOT(node).expr;
+ assert(node->k == AST_DOT);
+ struct ast *expr = dot_expr(node);
if (actualize(state, scope, expr))
return -1;
- struct ast_node *id = AST_DOT(node).id;
- struct ast_node *type = expr->type;
+ char *id = dot_id(node);
+ struct type *type = expr->t;
- struct ast_node *def = NULL;
- switch (AST_TYPE(type).kind) {
- case AST_TYPE_PRIMITIVE: def = AST_PRIMITIVE_TYPE(type).def; break;
- case AST_TYPE_TRAIT: def = AST_TRAIT_TYPE(type).def; break;
- case AST_TYPE_STRUCT: def = AST_STRUCT_TYPE(type).def; break;
+ struct ast *def = NULL;
+ switch (type->k) {
+ case TYPE_TRAIT:
+ case TYPE_STRUCT: def = type->d; break;
default: {
char *tstr = type_str(type);
semantic_error(scope->fctx, node,
@@ -2106,17 +1974,17 @@ static int actualize_dot(struct act_state *state,
}
}
- struct ast_node *exists = scope_find_var(def->scope, id);
+ struct ast *exists = scope_find_var(def->scope, id);
if (exists) {
- assert(exists->type);
- set_type(node, exists->type);
+ assert(exists->t);
+ set_type(node, exists->t);
return 0;
}
exists = scope_find_proc(def->scope, id);
if (exists) {
- assert(exists->type);
- set_type(node, exists->type);
+ assert(exists->t);
+ set_type(node, exists->t);
return 0;
}
@@ -2126,42 +1994,33 @@ static int actualize_dot(struct act_state *state,
}
static int actualize_init(struct act_state *state,
- struct scope *scope, struct ast_node *node)
+ struct scope *scope, struct ast *node)
{
- assert(node->node_type == AST_INIT);
+ assert(node->k == AST_INIT);
/* for now just do the types, the named stuff will be checked later */
/* TODO: how to make sure all members are initialized? */
- int ret = 0;
- enum act_flags old_flags = state->flags;
- ret = actualize(state, scope, node->_init.body);
- state->flags = old_flags;
- return ret;
+ return actualize_list(state, scope, init_body(node));
}
static int actualize_assign(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- assert(node->node_type == AST_ASSIGN);
- struct ast_node *to = node->_assign.to;
+ assert(node->k == AST_ASSIGN);
+ struct ast *to = assign_to(node);
if (actualize(state, scope, to))
return -1;
- struct ast_node *from = node->_assign.from;
- if (actualize(state, scope, from))
+ struct ast *from = assign_from(node);
+ if (actualize_list(state, scope, from))
return -1;
- if (from->node_type == AST_INIT) {
- set_type(node, to->type);
- return actualize_init_cast(state, scope, from, to->type);
+ if (from->k == AST_INIT) {
+ set_type(node, to->t);
+ return actualize_init_cast(state, scope, from, to->t);
}
- if (!types_match(to->type, from->type)) {
- char *tostr = type_str(to->type);
- char *fromstr = type_str(from->type);
- semantic_error(scope->fctx, node, "type mismatch (%s vs %s)",
- tostr, fromstr);
- free(tostr);
- free(fromstr);
+ if (!types_match(to->t, from->t)) {
+ type_mismatch(scope, node, to->t, from->t);
return -1;
}
@@ -2172,84 +2031,77 @@ static int actualize_assign(struct act_state *state, struct scope *scope,
return -1;
}
- set_type(node, to->type);
+ set_type(node, to->t);
return 0;
}
static int actualize_fetch(struct act_state *state, struct scope *scope,
- struct ast_node *fetch)
+ struct ast *fetch)
{
- assert(fetch->node_type == AST_FETCH);
- struct ast_node *type = fetch->_fetch.type;
- if (actualize(state, scope, type))
+ assert(fetch->k == AST_FETCH);
+ struct type *type = fetch_type(fetch);
+ if (actualize_type(state, scope, type))
return -1;
- if (type->_type.kind != AST_TYPE_ENUM) {
- semantic_error(scope->fctx, type, "type is not an enum");
+ if (type->k != TYPE_ENUM) {
+ type_error(scope->fctx, type, "type is not an enum");
return -1;
}
- struct ast_node *id = fetch->_fetch.id;
- struct ast_node *def =
- file_scope_find_type(scope, AST_ID_TYPE(type).id);
+ char *id = fetch_id(fetch);
+ struct ast *def = type->d;
assert(def);
- struct ast_node *member = lookup_enum_member(def, id);
+ struct ast *member = lookup_enum_member(def, id);
if (!member) {
char *estr = type_str(type);
- semantic_error(scope->fctx, id, "no such member in enum %s");
+ semantic_error(scope->fctx, fetch, "no such member in enum %s");
free(estr);
return -1;
}
- set_type(fetch, def->type);
+ set_type(fetch, def->t);
return 0;
}
static int actualize_enum(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- assert(node->node_type == AST_ENUM);
- struct ast_node *type = node->_enum.type;
+ assert(node->k == AST_ENUM_DEF);
+ struct type *type = enum_type(node);
struct scope *enum_scope = node->scope;
/* TODO: here we could save space by choosing the smallest type that
* fits */
if (!type) {
type = i27_type(scope);
- node->_enum.type = type;
- } else if (actualize(state, enum_scope, type))
+ node->t = type;
+ } else if (actualize_type(state, enum_scope, type))
return -1;
long long counter = 0;
- node->type = type;
- struct ast_node *members = node->_enum.body;
+ node->t = type;
+ struct ast *members = enum_body(node);
while (members) {
set_type(members, type);
- if (members->_val.val) {
- struct ast_node *val = members->_val.val;
+ if (val_val(members)) {
+ struct ast *val = val_val(members);
if (actualize(state, enum_scope, val))
return -1;
- if (val->node_type != AST_CONST) {
+ if (val->k != AST_CONST_INT) {
semantic_error(scope->fctx, members,
"unable to process nonconstant expression");
return -1;
}
- if (val->_const.kind != AST_CONST_INTEGER) {
- semantic_error(scope->fctx, members,
- "not expandable to an integer constant");
- return -1;
- }
-
- counter = val->_const.integer;
+ counter = int_val(val);
}
else {
- members->_val.val = gen_int(counter, NULL_LOC());
+ val_val(members) = gen_const_int(counter, NULL_LOC());
}
- members = members->next;
+ members = members->n;
counter++;
}
@@ -2258,21 +2110,21 @@ static int actualize_enum(struct act_state *state, struct scope *scope,
}
static int actualize_if(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- assert(node->node_type == AST_IF);
- if (actualize(state, scope, AST_IF(node).cond))
+ assert(node->k == AST_IF);
+ if (actualize(state, scope, if_cond(node)))
return -1;
- if (actualize(state, scope, AST_IF(node).body))
+ if (actualize(state, scope, if_body(node)))
return -1;
- if (actualize(state, scope, AST_IF(node).els))
+ if (actualize(state, scope, if_else(node)))
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;
+ struct type *tt = ast_last(if_body(node))->t;
+ struct type *ft = ast_last(if_else(node))->t;
if (!types_match(tt, ft)) {
semantic_error(scope->fctx, node,
"mismatched if/else body values");
@@ -2283,143 +2135,124 @@ static int actualize_if(struct act_state *state, struct scope *scope,
return 0;
}
- node->type = void_type();
+ node->t = void_type();
return 0;
}
static int actualize_for(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- assert(node->node_type == AST_FOR);
- if (actualize(state, scope, AST_FOR(node).pre))
+ assert(node->k == AST_FOR);
+ if (actualize_list(state, scope, for_pre(node)))
return -1;
- if (actualize(state, scope, AST_FOR(node).post))
+ if (actualize_list(state, scope, for_post(node)))
return -1;
- if (actualize(state, scope, AST_FOR(node).cond))
+ if (actualize_list(state, scope, for_cond(node)))
return -1;
- if (actualize(state, scope, AST_FOR(node).body))
+ if (actualize_list(state, scope, for_body(node)))
return -1;
- node->type = void_type();
+ node->t = void_type();
+ return 0;
+}
+
+static int actualize_comparison(struct act_state *state, struct scope *scope, struct ast *node)
+{
+ assert(is_comparison(node));
+ struct ast *left = comparison_left(node);
+ struct ast *right = comparison_right(node);
+
+ if (actualize(state, scope, left))
+ return -1;
+
+ if (actualize(state, scope, right))
+ return -1;
+
+ if (!is_primitive(left->t)) {
+ type_error(scope->fctx, left->t, "primitive type required");
+ return -1;
+ }
+
+ if (!is_primitive(right->t)) {
+ type_error(scope->fctx, right->t, "primitive type required");
+ return -1;
+ }
+
+ if (!types_match(left->t, right->t)) {
+ type_mismatch(scope, node, left->t, right->t);
+ return -1;
+ }
+
+ set_type(node, bool_type(scope));
return 0;
}
static int actualize(struct act_state *state, struct scope *scope,
- struct ast_node *node)
+ struct ast *node)
{
- int ret = 0;
if (!node)
- return ret;
+ return 0;
if (!node->scope)
node->scope = scope;
- /* this node was already actualized, presumed to be fine */
- if (ast_flags(node, AST_FLAG_ACTUAL)) {
- return 0;
- }
-
- /* actualization started */
- ast_set_flags(node, AST_FLAG_INIT);
+ if (is_unop(node))
+ return actualize_unop(state, scope, node);
- /* actualization done for this node (optimistic) */
- ast_set_flags(node, AST_FLAG_ACTUAL);
+ if (is_binop(node))
+ return actualize_binop(state, scope, node);
- switch (node->node_type) {
- case AST_PROC:
- ret |= actualize_proc(state, scope, node);
- break;
+ if (is_comparison(node))
+ return actualize_comparison(state, scope, node);
- case AST_TRAIT: ret |= actualize_trait(state, scope, node); break;
- case AST_ALIAS: ret |= actualize_alias(state, scope, node); break;
- case AST_MACRO_CONSTRUCT: ret |= actualize_macro_construct(state, scope,
- node); break;
- case AST_MACRO_EXPAND: ret |=
- actualize_macro_expand(state, scope, node); break;
- case AST_CALL: ret |= actualize_call(state, scope, node); break;
- case AST_BINOP: ret |= actualize_binop(state, scope, node); break;
- case AST_BLOCK: ret |= actualize_block(state, scope, node); break;
- case AST_ID: ret |= actualize_id(state, scope, node); break;
- case AST_VAR: ret |= actualize_var(state, scope, node); break;
- case AST_TYPE: ret |= actualize_type(state, scope, node); break;
- case AST_EMPTY: ret |= actualize_empty(state, scope, node); break;
- case AST_CAST: ret |= actualize_cast(state, scope, node); break;
- case AST_CONST: ret |= actualize_const(state, scope, node); break;
- case AST_DEFER: ret |= actualize_defer(state, scope, node); break;
- case AST_RETURN: ret |= actualize_return(state, scope, node); break;
- case AST_GOTO: ret |= actualize_goto(state, scope, node); break;
- case AST_LABEL: ret |= actualize_label(state, scope, node); break;
- case AST_UNOP: ret |= actualize_unop(state, scope, node); break;
- case AST_AS: ret |= actualize_as(state, scope, node); break;
- case AST_STRUCT: ret |= actualize_struct(state, scope, node); break;
- case AST_DOT: ret |= actualize_dot(state, scope, node); break;
- case AST_INIT: ret |= actualize_init(state, scope, node); break;
- 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;
+ if (is_const(node))
+ return actualize_const(state, scope, node);
+ switch (node->k) {
+ case AST_PROC_DEF: return actualize_proc(state, scope, node);
+ case AST_TRAIT_DEF: return actualize_trait(state, scope, node);
+ case AST_ALIAS_DEF: return actualize_alias(state, scope, node);
+ case AST_ENUM_DEF: return actualize_enum(state, scope, node);
+ case AST_MACRO_DEF: return actualize_macro_def(state, scope, node);
+ case AST_STRUCT_DEF: return actualize_struct(state, scope, node);
+ case AST_VAR_DEF: return actualize_var(state, scope, node);
+ case AST_CALL: return actualize_call(state, scope, node);
+ case AST_BLOCK: return actualize_block(state, scope, node);
+ case AST_ID: return actualize_id(state, scope, node);
+ case AST_EMPTY: return actualize_empty(state, scope, node);
+ case AST_CAST: return actualize_cast(state, scope, node);
+ case AST_DEFER: return actualize_defer(state, scope, node);
+ case AST_RETURN: return actualize_return(state, scope, node);
+ case AST_GOTO: return actualize_goto(state, scope, node);
+ case AST_LABEL: return actualize_label(state, scope, node);
+ case AST_AS: return actualize_as(state, scope, node);
+ case AST_DOT: return actualize_dot(state, scope, node);
+ case AST_INIT: return actualize_init(state, scope, node);
+ case AST_ASSIGN: return actualize_assign(state, scope, node);
+ case AST_FETCH: return actualize_fetch(state, scope, node);
+ case AST_IF: return actualize_if(state, scope, node);
+ case AST_FOR: return actualize_for(state, scope, node);
+ case AST_MACRO_EXPAND: return actualize_macro_expand(state, scope, node);
default:
/* more like internal_error, maybe? */
semantic_error(scope->fctx, node,
"unimplemented actualization");
- break;
- }
- return ret;
-}
-
-int actualize_main(struct scope *root)
-{
- struct ast_node *main_id = gen_id(strdup("main"), NULL_LOC());
-
- struct act_state state = {0};
-
- /* skip checking signature for now */
- struct ast_node *main = file_scope_find_proc(root, main_id);
- if (!main) {
- /* libraries are not really compilable... */
- error("no main");
return -1;
}
- int ret = actualize(&state, root, main);
- destroy_act_state(&state);
- return ret;
-}
-
-void replace_type(struct ast_node *type, struct ast_node *from,
- struct ast_node *to)
-{
- if (!type)
- return;
-
- assert(type->node_type == AST_TYPE);
- assert(from->node_type == AST_TYPE);
- assert(to->node_type == AST_TYPE);
-
- if (types_match(type, from)) {
- assert(type->_type.next == NULL);
- struct ast_node *clone = clone_ast_node(to);
- *type = *clone;
- return;
- }
- replace_type(type->_type.next, from, to);
+ return 0;
}
-void replace_param_types(struct ast_node *param, struct ast_node *param_type,
- struct ast_node *arg_type)
+static int actualize_list(struct act_state *state, struct scope *scope,
+ struct ast *l)
{
- if (arg_type->_type.kind == AST_TYPE_TRAIT) {
- replace_param_types(param, param_type, arg_type);
- return;
+ foreach_node(n, l) {
+ if (actualize(state, scope, n))
+ return -1;
}
- while (param) {
- replace_type(param->type, param_type, arg_type);
- param = param->next;
- }
+ return 0;
}