diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/actualize.c | 147 | ||||
| -rw-r--r-- | src/asm.c | 18 | ||||
| -rw-r--r-- | src/ast.c | 368 | ||||
| -rw-r--r-- | src/compiler.c | 25 | ||||
| -rw-r--r-- | src/debug.c | 17 | ||||
| -rw-r--r-- | src/lexer.l | 3 | ||||
| -rw-r--r-- | src/ops.c | 120 | ||||
| -rw-r--r-- | src/parser.y | 176 | ||||
| -rw-r--r-- | src/scope.c | 709 |
9 files changed, 511 insertions, 1072 deletions
diff --git a/src/actualize.c b/src/actualize.c index 694eca9..591df1a 100644 --- a/src/actualize.c +++ b/src/actualize.c @@ -288,7 +288,7 @@ static int analyze_file_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); + ast_flags(node, AST_FLAG_PUBLIC), file); break; } @@ -329,11 +329,6 @@ static int analyze_file_visibility(struct scope *scope, struct ast_node *node) break; } - case AST_TYPE_CONSTRUCT: { - ret |= scope_add_type_construct(scope, node); - break; - } - case AST_MACRO_CONSTRUCT: { ret |= scope_add_macro(scope, node); break; @@ -377,7 +372,6 @@ static int analyze(struct scope *scope, struct ast_node *tree) int analyze_root(struct scope *scope, struct ast_node *tree) { - scope_add_defaults(scope); if (analyze(scope, tree)) return -1; @@ -410,10 +404,6 @@ int types_match(struct ast_node *a, struct ast_node *b) assert(a->node_type == AST_TYPE); assert(b->node_type == AST_TYPE); - /* typeofs match 'everything' */ - if (AST_TYPE(a).kind == AST_TYPE_TYPEOF || AST_TYPE(b).kind == AST_TYPE_TYPEOF) - return 1; - /* if the type kind doesn't match, we're done. */ if (AST_TYPE(a).kind != AST_TYPE(b).kind) return 0; @@ -423,7 +413,7 @@ int types_match(struct ast_node *a, struct ast_node *b) if (AST_TYPE(a).kind == AST_TYPE_POINTER) return types_match(AST_PTR_TYPE(a).base, - AST_PTR_TYPE(b).base); + AST_PTR_TYPE(b).base); if (AST_TYPE(a).kind == AST_TYPE_PRIMITIVE) return primitives_match(a, b); @@ -467,7 +457,7 @@ static int replace_id(struct ast_node *body, struct ast_node *id, } static int actualize_macro_construct(struct act_state *state, - struct scope *scope, struct ast_node *n) + struct scope *scope, struct ast_node *n) { UNUSED(state); /* macro bodies, arguments, etc aren't expanded upon until the macro is @@ -476,18 +466,6 @@ static int actualize_macro_construct(struct act_state *state, return scope_add_macro(scope, n); } -struct ast_node *extract_typeof(struct ast_node *type) -{ - if (!type) - return 0; - - assert(type->node_type == AST_TYPE); - if (type->_type.kind == AST_TYPE_TYPEOF) - return type; - - return extract_typeof(type->_type.next); -} - struct ast_node *extract_trait(struct ast_node *type) { if (!type) @@ -501,7 +479,7 @@ struct ast_node *extract_trait(struct ast_node *type) } static void actualize_trait_types(struct ast_node *params, - struct ast_node *args) + struct ast_node *args) { /** @todo replace trait types with arg types, should probably be merged * */ @@ -534,11 +512,12 @@ static int actualize_proc_call(struct act_state *state, } static int actualize_macro_expand(struct act_state *state, - struct scope *scope, struct ast_node *macro_expand) + struct scope *scope, + struct ast_node *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_resolve_macro(scope, id); + struct ast_node *macro = file_scope_find_macro(scope, id); if (!macro) { semantic_error(scope->fctx, macro_expand, "no such macro"); return -1; @@ -596,11 +575,16 @@ static int actualize_call(struct act_state *state, /* check that arguments exist, make sure they have types etc. */ /* TODO: procedure callbacks? */ - int ret = actualize(state, scope, call->_call.args); + int ret = actualize(state, scope, AST_CALL(call).args); if (ret) return ret; - struct ast_node *callable = file_scope_resolve_call(scope, call); + ret = actualize(state, scope, AST_CALL(call).expr); + if (ret) + return ret; + + /** @todo check if call args and expr types match */ + struct ast_node *callable = file_scope_find_proc(scope, call); if (!callable) { char *str = call_str(call); semantic_error(scope->fctx, call, "no such callable: %s", str); @@ -609,6 +593,8 @@ static int actualize_call(struct act_state *state, } assert(callable->node_type == AST_PROC); + /** @todo we should probably start with just iterating over all procs and check + * if they're valid rather than generating them on 'demand' */ return actualize_proc_call(state, scope, call, callable); } @@ -622,7 +608,7 @@ static void warn_unused_labels(struct act_state *state, struct scope *scope) struct ast_node *label = labels->node; if (!ast_flags(label, AST_FLAG_ACTUAL)) semantic_warn(scope->fctx, label, - "unused label"); + "unused label"); } while ((labels = labels->next)); } @@ -638,7 +624,7 @@ static int undefined_gotos(struct act_state *state, struct scope *scope) struct ast_node *got = gotos->node; if (!ast_flags(got, AST_FLAG_ACTUAL)) { semantic_warn(scope->fctx, got, - "undefined label"); + "undefined label"); ret = -1; } @@ -808,27 +794,27 @@ static int actualize_id(struct act_state *state, /** @todo at the moment we always assume an ID is a variable, but stuff * like function callbacks should be added in the future */ struct ast_node *decl = file_scope_find_var(scope, id); - if (!decl) { - semantic_error(scope->fctx, id, "no such object"); - return -1; + if (decl) { + id->type = decl->type; + return 0; } - if (!decl->type) { - semantic_error(scope->fctx, id, - "no type associated with object"); - return -1; + decl = file_scope_find_proc(scope, id); + if (decl) { + id->type = decl->type; + return 0; } - id->type = decl->type; - return 0; + semantic_error(scope->fctx, id, "no such object"); + return -1; } static int actualize_var(struct act_state *state, struct scope *scope, struct ast_node *var) { assert(var && var->node_type == AST_VAR); - struct ast_node *init = var->_var.init; - struct ast_node *type = var->_var.type; + struct ast_node *init = AST_VAR(var).init; + struct ast_node *type = AST_VAR(var).type; /* one of these must be defined, otherwise the parser fucked up */ assert(type || init); @@ -881,11 +867,11 @@ static int actualize_var(struct act_state *state, enum act_flags old_flags = state->flags; \ struct ast_node *old_trait = state->cur_trait; -#define EXIT_ACT(r) \ - do { \ +#define EXIT_ACT(r) \ + do { \ state->cur_trait = old_trait; \ - state->flags = old_flags; \ - return r; \ + state->flags = old_flags; \ + return r; \ } while (0); static int actualize_type(struct act_state *state, @@ -908,10 +894,12 @@ static int actualize_type(struct act_state *state, * 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()); + 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); + 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); @@ -945,26 +933,16 @@ static int actualize_type(struct act_state *state, break; } - case AST_TYPE_ARR: - /* TODO: expression should be expandable to integer constant */ + case AST_TYPE_CONSTRUCT: + semantic_info(scope->fctx, type, + "constructs unimplemented, continuing with compilation to see what breaks"); break; - case AST_TYPE_TYPEOF: { - struct ast_node *expr = AST_TYPEOF_TYPE(type).expr; - /* TODO: expressions in top-level type declarations should - * probably be checked for, as we might not want to accidentally - * actualize procedure calls? */ - if (actualize(state, scope, expr)) - EXIT_ACT(-1); - - /* TODO: for now just trust that the expression is not looped or - * anything dumb like that, but I would feel better if I figure - * out some check */ - assert(type->_type.next == NULL); - /** @todo add in some 'from' field for this situation? */ - type->type = expr->type; + 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; - } case AST_TYPE_POINTER: assert(AST_PTR_TYPE(type).base); @@ -1019,7 +997,7 @@ static int actualize_empty(struct act_state *state, return -1; } - node->type = gen_type(AST_TYPE_ID, void_id, NULL, NULL); + 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; @@ -1186,11 +1164,11 @@ static int init_struct(struct act_state *state, struct scope *scope, break; } - if (!implements(0, scope, args->type, member->type)) { + if (!types_match(args->type, member->type)) { char *astr = type_str(args->type); char *mstr = type_str(member->type); semantic_error(scope->fctx, args, - "%s does not implement %s", astr, mstr); + "%s does not match %s", astr, mstr); free(astr); free(mstr); ret = -1; @@ -1351,7 +1329,7 @@ static int actualize_alias(struct act_state *state, struct scope *scope, } static int actualize_trait(struct act_state *state, struct scope *scope, - struct ast_node *trait) + struct ast_node *trait) { assert(trait->node_type == AST_TRAIT); ast_set_flags(trait, AST_FLAG_ACTUAL); @@ -1565,8 +1543,9 @@ static int actualize_unop(struct act_state *state, } case AST_REF: { - node->type = gen_type(AST_TYPE_POINTER, NULL, NULL, NULL); - node->type->_type.next = expr->type; + node->type = gen_type(AST_TYPE_POINTER, NULL, NULL, + NULL_LOC()); + node->AST_TYPE(type).next = expr->type; break; } @@ -1613,7 +1592,8 @@ static int actualize_struct(struct act_state *state, /* cloning slightly odd, but I guess it's fine? */ struct ast_node *clone_id = clone_ast_node(node->_struct.id); - node->type = gen_type(AST_TYPE_STRUCT, clone_id, NULL, NULL); + node->type = + gen_type(AST_TYPE_STRUCT, clone_id, NULL, NULL_LOC()); ast_set_flags(node, AST_FLAG_ACTUAL); return 0; @@ -1634,6 +1614,9 @@ static int has_members(struct ast_node *type) if (AST_TYPE(type).kind == AST_TYPE_TRAIT) return 1; + if (AST_TYPE(type).kind == AST_TYPE_CONSTRUCT) + return 1; + return 0; } @@ -1708,7 +1691,8 @@ static int actualize_assign(struct act_state *state, struct scope *scope, /** @todo rvalue vs lvalue? */ if (!is_lvalue(to)) { - semantic_error(scope->fctx, node, "rvalue used where lvalue required"); + semantic_error(scope->fctx, node, + "rvalue used where lvalue required"); return -1; } @@ -1730,7 +1714,8 @@ static int actualize_fetch(struct act_state *state, struct scope *scope, } struct ast_node *id = fetch->_fetch.id; - struct ast_node *def = file_scope_find_type(scope, AST_ID_TYPE(type).id); + struct ast_node *def = + file_scope_find_type(scope, AST_ID_TYPE(type).id); assert(def); struct ast_node *member = lookup_enum_member(def, id); @@ -1806,7 +1791,8 @@ static int actualize(struct act_state *state, struct scope *scope, if (!node->scope) node->scope = scope; - if (ast_flags(node, AST_FLAG_INIT) && !ast_flags(node, AST_FLAG_ACTUAL)) { + if (ast_flags(node, + AST_FLAG_INIT) && !ast_flags(node, AST_FLAG_ACTUAL)) { semantic_error(scope->fctx, node, "detected dependency loop"); return -1; } @@ -1823,8 +1809,10 @@ static int actualize(struct act_state *state, struct scope *scope, 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_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; @@ -1866,12 +1854,11 @@ static int actualize(struct act_state *state, struct scope *scope, int actualize_main(struct scope *root) { struct ast_node *main_id = gen_id(strdup("main"), NULL_LOC()); - struct ast_node *main_call = gen_call(main_id, NULL); struct act_state state = {0}; /* skip checking signature for now */ - struct ast_node *main = file_scope_resolve_call(root, main_call); + struct ast_node *main = file_scope_find_proc(root, main_id); if (!main) { /* libraries are not really compilable... */ error("no main"); @@ -5,8 +5,10 @@ /* I guess using the zero register might be okay in some scenarios, but for now * I'll just keep it an illegal register */ -#define ASSERT_REG(x) {assert(x->kind == LOC_REG); assert(x->reg > 0 && x->reg < 81);} -#define ASSERT_MEM(x) {assert(x->kind == LOC_MEM); assert(x->reg > 0 && x->reg < 81);} +#define ASSERT_REG(x) {assert(x->kind == LOC_REG); assert( \ + x->reg > 0 && x->reg < 81);} +#define ASSERT_MEM(x) {assert(x->kind == LOC_MEM); assert( \ + x->reg > 0 && x->reg < 81);} static int print_comment(struct op *op, FILE *f) { @@ -59,6 +61,7 @@ static int print_stt(struct op *op, FILE *f) static int print_ret(struct op *op, FILE *f) { + (void)op; /* technically speaking ret takes a number of inputs, but they should be * marshaled into registers with moves etc. so don't worry about them * here */ @@ -84,16 +87,8 @@ static int print_op(struct op *op, FILE *f) return ret; } -int print_asm(struct ops *ops, const char *output) +int print_asm(struct ops *ops, FILE *f) { - FILE *f = fopen(output, "w"); - - /* main should probably be mangled here as well */ - fprintf(f, "jal x21, main\n"); - /* tell simulator to turn off (very much temp) */ - fprintf(f, "li x1, 3\n"); - fprintf(f, "csrrw mpower, x0, x1\n"); - int ret = 0; struct op *op = ops->base; while (op) { @@ -103,6 +98,5 @@ int print_asm(struct ops *ops, const char *output) op = op->next; } - fclose(f); return ret; } @@ -31,9 +31,9 @@ static void destroy_ast_node(struct ast_node *node) switch (node->node_type) { case AST_ID: free((void *)AST_ID(node).id); break; case AST_CONST: - if (AST_CONST(node).kind == AST_CONST_STRING) - free((void *)AST_CONST(node).str); - break; + if (AST_CONST(node).kind == AST_CONST_STRING) + free((void *)AST_CONST(node).str); + break; default: } @@ -59,7 +59,9 @@ static struct ast_node *create_ast_node() else if (ast_nodes.n >= ast_nodes.s) { ast_nodes.s *= 2; - ast_nodes.v = realloc(ast_nodes.v, ast_nodes.s * sizeof(struct ast_node *)); + ast_nodes.v = + realloc(ast_nodes.v, + ast_nodes.s * sizeof(struct ast_node *)); } struct ast_node *n = calloc(1, sizeof(struct ast_node)); @@ -69,11 +71,11 @@ static struct ast_node *create_ast_node() /** @todo alloc should maybe also keep track of all nodes in a vector or * something and mass free all AST at a time to keep my sanity */ -#define ALLOC_NODE(n, type) \ - struct ast_node *n = create_ast_node(); \ - if (!n) { \ - fprintf(stderr, "failed allocating" type "\n"); \ - return NULL; \ +#define ALLOC_NODE(n, type) \ + struct ast_node *n = create_ast_node(); \ + if (!n) { \ + fprintf(stderr, "failed allocating" type "\n"); \ + return NULL; \ } #define DESTROY_LIST(x) \ @@ -86,7 +88,8 @@ static struct ast_node *create_ast_node() } while ((prev = cur)); \ } -struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx, struct src_loc loc) +struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx, + struct src_loc loc) { ALLOC_NODE(n, "arr_access"); n->node_type = AST_ARR_ACCESS; @@ -96,7 +99,8 @@ struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx, str return n; } -struct ast_node *gen_macro_expand(struct ast_node *id, struct ast_node *args, struct src_loc loc) +struct ast_node *gen_macro_expand(struct ast_node *id, struct ast_node *args, + struct src_loc loc) { ALLOC_NODE(n, "macro_expand"); n->node_type = AST_MACRO_EXPAND; @@ -106,23 +110,9 @@ struct ast_node *gen_macro_expand(struct ast_node *id, struct ast_node *args, st return n; } -struct ast_node *gen_type_construct(struct ast_node *id, - struct ast_node *params, - struct ast_node *body, - struct src_loc loc) -{ - ALLOC_NODE(n, "type_construct"); - n->node_type = AST_TYPE_CONSTRUCT; - AST_TYPE_CONSTRUCT(n).id = id; - AST_TYPE_CONSTRUCT(n).params = params; - AST_TYPE_CONSTRUCT(n).body = body; - n->loc = loc; - return n; -} - struct ast_node *gen_type_expand(struct ast_node *id, - struct ast_node *args, - struct src_loc loc) + struct ast_node *args, + struct src_loc loc) { ALLOC_NODE(n, "type_expand"); n->node_type = AST_TYPE_EXPAND; @@ -134,8 +124,8 @@ struct ast_node *gen_type_expand(struct ast_node *id, struct ast_node *gen_binop(enum ast_binops op, struct ast_node *left, - struct ast_node *right, - struct src_loc loc) + struct ast_node *right, + struct src_loc loc) { ALLOC_NODE(n, "binop"); n->node_type = AST_BINOP; @@ -156,13 +146,14 @@ struct ast_node *gen_unop(enum ast_unops op, struct ast_node *expr) return n; } -struct ast_node *gen_call(struct ast_node *id, struct ast_node *args) +struct ast_node *gen_call(struct ast_node *expr, struct ast_node *args, + struct src_loc loc) { ALLOC_NODE(n, "call"); n->node_type = AST_CALL; - n->_call.id = id; - n->_call.args = args; - n->loc = id->loc; + AST_CALL(n).expr = expr; + AST_CALL(n).args = args; + n->loc = loc; return n; } @@ -251,12 +242,13 @@ struct ast_node *gen_goto(struct ast_node *label) return n; } -struct ast_node *gen_dot(struct ast_node *expr, struct ast_node *id) +struct ast_node *gen_dot(struct ast_node *expr, struct ast_node *id, struct src_loc loc) { ALLOC_NODE(n, "dot"); n->node_type = AST_DOT; - n->_dot.expr = expr; - n->_dot.id = id; + AST_DOT(n).expr = expr; + AST_DOT(n).id = id; + n->loc = loc; return n; } @@ -289,8 +281,8 @@ struct ast_node *gen_fetch(struct ast_node *id, struct ast_node *type) } struct ast_node *gen_macro_construct(struct ast_node *id, - struct ast_node *params, - struct ast_node *body) + struct ast_node *params, + struct ast_node *body) { ALLOC_NODE(n, "macro_construct"); n->node_type = AST_MACRO_CONSTRUCT; @@ -347,13 +339,15 @@ struct ast_node *gen_primitive(enum ast_primitive type, struct src_loc loc) } struct ast_node *gen_type(enum ast_type_kind kind, - struct ast_node *t0, + struct ast_node *t0, struct ast_node *t1, - struct ast_node *t2) + struct src_loc loc) { ALLOC_NODE(n, "type"); n->node_type = AST_TYPE; AST_TYPE(n).kind = kind; + n->loc = loc; + switch (kind) { case AST_TYPE_TRAIT: AST_TRAIT_TYPE(n).def = t0; @@ -363,15 +357,16 @@ struct ast_node *gen_type(enum ast_type_kind kind, AST_ID_TYPE(n).id = t0; break; + case AST_TYPE_CONSTRUCT: + AST_CONSTRUCT_TYPE(n).id = t0; + AST_CONSTRUCT_TYPE(n).args = t1; + break; + case AST_TYPE_ARR: AST_ARR_TYPE(n).size = t0; AST_ARR_TYPE(n).base = t1; break; - case AST_TYPE_TYPEOF: - AST_TYPEOF_TYPE(n).expr = t0; - break; - case AST_TYPE_POINTER: AST_PTR_TYPE(n).base = t0; break; @@ -438,17 +433,14 @@ void destroy_defer(struct ast_node *defer) } struct ast_node *gen_var(struct ast_node *id, struct ast_node *type, - struct ast_node *init) + struct ast_node *init, struct src_loc loc) { ALLOC_NODE(n, "var"); n->node_type = AST_VAR; - n->_var.id = id; - n->_var.type = type; - n->_var.init = init; - if (id) - n->loc = id->loc; - else - n->loc = type->loc; + AST_VAR(n).id = id; + AST_VAR(n).type = type; + AST_VAR(n).init = init; + n->loc = loc; return n; } @@ -521,13 +513,15 @@ struct ast_node *gen_alias(struct ast_node *id, struct ast_node *type) return n; } -struct ast_node *gen_trait(struct ast_node *id, struct ast_node *body) +struct ast_node *gen_trait(struct ast_node *id, struct ast_node *params, + struct ast_node *body, struct src_loc loc) { ALLOC_NODE(n, "trait"); n->node_type = AST_TRAIT; - n->_trait.id = id; - n->_trait.body = body; - n->loc = id->loc; + AST_TRAIT(n).id = id; + AST_TRAIT(n).params = params; + AST_TRAIT(n).body = body; + n->loc = loc; return n; } @@ -777,8 +771,8 @@ static void __dump_ast(int depth, struct ast_node *node) dump_flags(node); putchar('\n'); - dump_ast(depth + 1, node->_call.id); - dump_ast(depth + 1, node->_call.args); + dump_ast(depth + 1, AST_CALL(node).expr); + dump_ast(depth + 1, AST_CALL(node).args); dump(depth, "}\n"); break; @@ -894,7 +888,8 @@ static void __dump_ast(int depth, struct ast_node *node) switch (node->_type.kind) { case AST_TYPE_PRIMITIVE: - printf(" PRIMITIVE %s\n", primitive_str(AST_PRIMITIVE_TYPE(node).type)); + printf(" PRIMITIVE %s\n", + primitive_str(AST_PRIMITIVE_TYPE(node).type)); break; case AST_TYPE_TRAIT: @@ -919,11 +914,6 @@ static void __dump_ast(int depth, struct ast_node *node) dump_ast(depth + 1, AST_PTR_TYPE(node).base); break; - case AST_TYPE_TYPEOF: - printf(" TYPEOF\n"); - dump_ast(depth + 1, AST_TYPEOF_TYPE(node).expr); - break; - case AST_TYPE_STRUCT: printf(" STRUCT\n"); /* oh yeah, struc is at least right now just an ID that @@ -1073,7 +1063,8 @@ static void __dump_ast(int depth, struct ast_node *node) dump(depth, "{CONST:"); dump_flags(node); switch (node->_const.kind) { - case AST_CONST_INTEGER: printf(" %lli", AST_CONST(node).integer); + case AST_CONST_INTEGER: printf(" %lli", + AST_CONST(node).integer); break; case AST_CONST_STRING: printf(" \"%s\"", AST_CONST(node).str); break; @@ -1131,24 +1122,16 @@ struct ast_node *clone_ast_node(struct ast_node *node) switch (node->node_type) { case AST_ARR_ACCESS: new = gen_arr_access( - clone_ast_node(AST_ARR_ACCESS(node).base), - clone_ast_node(AST_ARR_ACCESS(node).idx), - node->loc); - break; - - case AST_TYPE_CONSTRUCT: - new = gen_type_construct( - clone_ast_node(AST_TYPE_CONSTRUCT(node).id), - clone_ast_node(AST_TYPE_CONSTRUCT(node).params), - clone_ast_node(AST_TYPE_CONSTRUCT(node).body), - node->loc); + clone_ast_node(AST_ARR_ACCESS(node).base), + clone_ast_node(AST_ARR_ACCESS(node).idx), + node->loc); break; case AST_TYPE_EXPAND: new = gen_type_expand( - clone_ast_node(AST_TYPE_EXPAND(node).id), - clone_ast_node(AST_TYPE_EXPAND(node).args), - node->loc); + clone_ast_node(AST_TYPE_EXPAND(node).id), + clone_ast_node(AST_TYPE_EXPAND(node).args), + node->loc); break; case AST_FETCH: @@ -1167,8 +1150,9 @@ struct ast_node *clone_ast_node(struct ast_node *node) case AST_SIZEOF: new = gen_sizeof(clone_ast_node(node->_sizeof.expr)); break; - case AST_DOT: new = gen_dot(clone_ast_node(node->_dot.expr), - clone_ast_node(node->_dot.id)); + case AST_DOT: new = gen_dot(clone_ast_node(AST_DOT(node).expr), + clone_ast_node(AST_DOT(node).id), + node->loc); break; case AST_AS: new = gen_as(clone_ast_node(node->_as.type)); @@ -1183,31 +1167,32 @@ struct ast_node *clone_ast_node(struct ast_node *node) case AST_BINOP: new = gen_binop(node->binop.op, clone_ast_node(node->binop.left), clone_ast_node(node->binop.right), - node->loc); + node->loc); break; case AST_UNOP: new = gen_unop(node->_unop.op, clone_ast_node(node->_unop.expr)); break; - case AST_CALL: new = gen_call(clone_ast_node(node->_call.id), - clone_ast_node(node->_call.args)); + case AST_CALL: new = gen_call(clone_ast_node(AST_CALL(node).expr), + clone_ast_node(AST_CALL(node).args), + node->loc); break; case AST_DEFER: new = gen_defer(clone_ast_node(node->_defer.expr)); break; case AST_MACRO_CONSTRUCT: new = gen_macro_construct( - clone_ast_node(AST_MACRO_CONSTRUCT(node).id), - clone_ast_node(AST_MACRO_CONSTRUCT(node).params), - clone_ast_node(AST_MACRO_CONSTRUCT(node).body)); - break; + clone_ast_node(AST_MACRO_CONSTRUCT(node).id), + clone_ast_node(AST_MACRO_CONSTRUCT(node).params), + clone_ast_node(AST_MACRO_CONSTRUCT(node).body)); + break; case AST_MACRO_EXPAND: new = gen_macro_expand( - clone_ast_node(AST_MACRO_EXPAND(node).id), - clone_ast_node(AST_MACRO_EXPAND(node).args), - node->loc); - break; + clone_ast_node(AST_MACRO_EXPAND(node).id), + clone_ast_node(AST_MACRO_EXPAND(node).args), + node->loc); + break; case AST_CAST: new = gen_cast(clone_ast_node(node->_cast.expr), clone_ast_node(node->_cast.type)); @@ -1216,26 +1201,14 @@ struct ast_node *clone_ast_node(struct ast_node *node) case AST_PROC: new = gen_proc(clone_ast_node(node->_proc.id), clone_ast_node(node->_proc.sign), clone_ast_node(node->_proc.body), - node->loc); + node->loc); break; - case AST_VAR: { - /* I don't like how messy this is, should maybe try and come up - * with something better */ - struct ast_node *type = NULL; - if (node->type) - type = clone_ast_node(node->type); - else - type = clone_ast_node(node->_var.type); - - new = gen_var(clone_ast_node(node->_var.id), - type, - clone_ast_node(node->_var.init)); - /* vars always reference the type associated with them? */ - if (node->type) - new->type = type; + case AST_VAR: new = gen_var(clone_ast_node(AST_VAR(node).id), + clone_ast_node(AST_VAR(node).type), + clone_ast_node(AST_VAR(node).init), + node->loc); break; - } case AST_FOR: new = gen_for(clone_ast_node(node->_for.pre), clone_ast_node(node->_for.cond), @@ -1258,60 +1231,55 @@ struct ast_node *clone_ast_node(struct ast_node *node) * correctly... */ switch (node->_type.kind) { case AST_TYPE_PRIMITIVE: - new = gen_primitive(AST_PRIMITIVE_TYPE(node).type, node->loc); + new = gen_primitive(AST_PRIMITIVE_TYPE( + node).type, node->loc); break; case AST_TYPE_TRAIT: new = gen_type(AST_TYPE_TRAIT, AST_TRAIT_TYPE(node).def, - NULL, - NULL); + NULL, + node->loc); break; case AST_TYPE_ID: new = gen_type(AST_TYPE_ID, clone_ast_node(AST_ID_TYPE(node).id), NULL, - NULL); + node->loc); break; case AST_TYPE_ARR: new = gen_type(AST_TYPE_ARR, clone_ast_node(AST_ARR_TYPE(node).size), clone_ast_node(AST_ARR_TYPE(node).base), - NULL); - break; - - case AST_TYPE_TYPEOF: - new = gen_type(AST_TYPE_TYPEOF, - clone_ast_node(AST_TYPEOF_TYPE(node).expr), - NULL, - NULL); + node->loc); break; case AST_TYPE_POINTER: - new = gen_type(AST_TYPE_POINTER, AST_PTR_TYPE(node).base, NULL, NULL); + new = gen_type(AST_TYPE_POINTER, AST_PTR_TYPE(node).base, + NULL, + node->loc); break; case AST_TYPE_STRUCT: new = gen_type(AST_TYPE_STRUCT, clone_ast_node(AST_STRUCT_TYPE(node).def), - NULL, - NULL); + NULL, node->loc); break; case AST_TYPE_ENUM: new = gen_type(AST_TYPE_ENUM, clone_ast_node(AST_ENUM_TYPE(node).def), - NULL, - NULL); + NULL, + node->loc); break; case AST_TYPE_SIGN: new = gen_type(AST_TYPE_SIGN, clone_ast_node(AST_SIGN_TYPE(node).params), clone_ast_node(AST_SIGN_TYPE(node).ret), - NULL); + node->loc); break; } @@ -1386,8 +1354,10 @@ struct ast_node *clone_ast_node(struct ast_node *node) break; case AST_TRAIT: - new = gen_trait(clone_ast_node(node->_trait.id), - clone_ast_node(node->_trait.body)); + new = gen_trait(clone_ast_node(AST_TRAIT(node).id), + clone_ast_node(AST_TRAIT(node).params), + clone_ast_node(AST_TRAIT(node).body), + node->loc); break; case AST_IF: @@ -1506,10 +1476,10 @@ static int identical_unop(int exact, struct ast_node *a, struct ast_node *b) static int identical_call(int exact, struct ast_node *a, struct ast_node *b) { - if (!identical_ast_nodes(exact, a->_call.id, b->_call.id)) + if (!identical_ast_nodes(exact, AST_CALL(a).expr, AST_CALL(b).expr)) return 0; - if (!identical_ast_nodes(exact, a->_call.args, b->_call.args)) + if (!identical_ast_nodes(exact, AST_CALL(a).args, AST_CALL(b).args)) return 0; return 1; @@ -1531,23 +1501,31 @@ static int identical_defer(int exact, struct ast_node *a, struct ast_node *b) return identical_ast_nodes(exact, a->_defer.expr, b->_defer.expr); } -static int identical_macro_construct(int exact, struct ast_node *a, struct ast_node *b) +static int identical_macro_construct(int exact, struct ast_node *a, + struct ast_node *b) { - if (!identical_ast_nodes(exact, AST_MACRO_CONSTRUCT(a).id, AST_MACRO_CONSTRUCT(b).id)) + if (!identical_ast_nodes(exact, AST_MACRO_CONSTRUCT(a).id, + AST_MACRO_CONSTRUCT(b).id)) return 0; - if (!identical_ast_nodes(exact, AST_MACRO_CONSTRUCT(a).params, AST_MACRO_CONSTRUCT(b).params)) + if (!identical_ast_nodes(exact, AST_MACRO_CONSTRUCT(a).params, + AST_MACRO_CONSTRUCT(b).params)) return 0; - return identical_ast_nodes(exact, AST_MACRO_CONSTRUCT(a).body, AST_MACRO_CONSTRUCT(b).body); + return identical_ast_nodes(exact, AST_MACRO_CONSTRUCT( + a).body, + AST_MACRO_CONSTRUCT(b).body); } -static int identical_macro_expand(int exact, struct ast_node *a, struct ast_node *b) +static int identical_macro_expand(int exact, struct ast_node *a, + struct ast_node *b) { - if (!identical_ast_nodes(exact, a->_macro_expand.id, b->_macro_expand.id)) + if (!identical_ast_nodes(exact, a->_macro_expand.id, + b->_macro_expand.id)) return 0; - if (!identical_ast_nodes(exact, a->_macro_expand.args, b->_macro_expand.args)) + if (!identical_ast_nodes(exact, a->_macro_expand.args, + b->_macro_expand.args)) return 0; return 1; @@ -1627,29 +1605,27 @@ static int identical_type_id(int exact, struct ast_node *a, struct ast_node *b) static int identical_type_arr(int exact, struct ast_node *a, struct ast_node *b) { - if (!identical_ast_nodes(exact, AST_ARR_TYPE(a).size, AST_ARR_TYPE(b).size)) + if (!identical_ast_nodes(exact, AST_ARR_TYPE(a).size, + AST_ARR_TYPE(b).size)) return 0; - return identical_ast_nodes(exact, AST_ARR_TYPE(a).base, AST_ARR_TYPE(b).base); + return identical_ast_nodes(exact, AST_ARR_TYPE(a).base, AST_ARR_TYPE( + b).base); } -static int identical_type_trait(int exact, struct ast_node *a, struct ast_node *b) +static int identical_type_trait(int exact, struct ast_node *a, + struct ast_node *b) { - return identical_ast_nodes(exact, AST_TRAIT_TYPE(a).def, AST_TRAIT_TYPE(b).def); + return identical_ast_nodes(exact, AST_TRAIT_TYPE(a).def, + AST_TRAIT_TYPE(b).def); } -static int identical_type_primitive(int exact, struct ast_node *a, struct ast_node *b) +static int identical_type_primitive(int exact, struct ast_node *a, + struct ast_node *b) { return AST_PRIMITIVE_TYPE(a).type == AST_PRIMITIVE_TYPE(b).type; } -static int identical_type_typeof(int exact, struct ast_node *a, - struct ast_node *b) -{ - return identical_ast_nodes(exact, AST_TYPEOF_TYPE(a).expr, - AST_TYPEOF_TYPE(b).expr); -} - static int identical_type_sign(int exact, struct ast_node *a, struct ast_node *b) { @@ -1657,19 +1633,22 @@ static int identical_type_sign(int exact, struct ast_node *a, AST_SIGN_TYPE(b).params)) return 0; - return identical_ast_nodes(exact, AST_SIGN_TYPE(a).ret, AST_SIGN_TYPE(b).ret); + return identical_ast_nodes(exact, AST_SIGN_TYPE(a).ret, AST_SIGN_TYPE( + b).ret); } static int identical_type_struct(int exact, struct ast_node *a, struct ast_node *b) { - return identical_ast_nodes(exact, AST_STRUCT_TYPE(a).def, AST_STRUCT_TYPE(b).def); + return identical_ast_nodes(exact, AST_STRUCT_TYPE( + a).def, AST_STRUCT_TYPE(b).def); } static int identical_type_enum(int exact, struct ast_node *a, struct ast_node *b) { - return identical_ast_nodes(exact, AST_ENUM_TYPE(a).def, AST_ENUM_TYPE(b).def); + return identical_ast_nodes(exact, AST_ENUM_TYPE(a).def, AST_ENUM_TYPE( + b).def); } static int identical_type(int exact, struct ast_node *a, struct ast_node *b) @@ -1679,12 +1658,12 @@ static int identical_type(int exact, struct ast_node *a, struct ast_node *b) int ret = 0; switch (a->_type.kind) { - case AST_TYPE_PRIMITIVE: ret = identical_type_primitive(exact, a, b); break; + case AST_TYPE_PRIMITIVE: ret = identical_type_primitive(exact, a, b); + break; case AST_TYPE_ENUM: ret = identical_type_enum(exact, a, b); break; case AST_TYPE_TRAIT: ret = identical_type_trait(exact, a, b); break; case AST_TYPE_ID: ret = identical_type_id(exact, a, b); break; case AST_TYPE_ARR: ret = identical_type_arr(exact, a, b); break; - case AST_TYPE_TYPEOF: ret = identical_type_typeof(exact, a, b); break; case AST_TYPE_SIGN: ret = identical_type_sign(exact, a, b); break; case AST_TYPE_STRUCT: ret = identical_type_struct(exact, a, b); break; case AST_TYPE_POINTER: break; @@ -1850,31 +1829,26 @@ static int identical_fetch(int exact, struct ast_node *a, struct ast_node *b) return 1; } -static int identical_type_expand(int exact, struct ast_node *a, struct ast_node *b) -{ - if (!identical_ast_nodes(exact, AST_TYPE_EXPAND(a).id, AST_TYPE_EXPAND(b).id)) - return 0; - - return identical_ast_nodes(exact, AST_TYPE_EXPAND(a).args, AST_TYPE_EXPAND(b).args); -} - -static int identical_type_construct(int exact, struct ast_node *a, struct ast_node *b) +static int identical_type_expand(int exact, struct ast_node *a, + struct ast_node *b) { - if (!identical_ast_nodes(exact, AST_TYPE_CONSTRUCT(a).id, AST_TYPE_CONSTRUCT(b).id)) - return 0; - - if (!identical_ast_nodes(exact, AST_TYPE_CONSTRUCT(a).params, AST_TYPE_CONSTRUCT(b).params)) + if (!identical_ast_nodes(exact, AST_TYPE_EXPAND(a).id, + AST_TYPE_EXPAND(b).id)) return 0; - return identical_ast_nodes(exact, AST_TYPE_CONSTRUCT(a).body, AST_TYPE_CONSTRUCT(b).body); + return identical_ast_nodes(exact, AST_TYPE_EXPAND( + a).args, AST_TYPE_EXPAND(b).args); } -static int identical_arr_access(int exact, struct ast_node *a, struct ast_node *b) +static int identical_arr_access(int exact, struct ast_node *a, + struct ast_node *b) { - if (!identical_ast_nodes(exact, AST_ARR_ACCESS(a).base, AST_ARR_ACCESS(b).base)) + if (!identical_ast_nodes(exact, AST_ARR_ACCESS(a).base, + AST_ARR_ACCESS(b).base)) return 0; - if (!identical_ast_nodes(exact, AST_ARR_ACCESS(a).idx, AST_ARR_ACCESS(b).idx)) + if (!identical_ast_nodes(exact, AST_ARR_ACCESS(a).idx, + AST_ARR_ACCESS(b).idx)) return 0; return 1; @@ -1913,7 +1887,6 @@ int identical_ast_nodes(int exact, struct ast_node *a, struct ast_node *b) int ret = 0; switch (a->node_type) { case AST_ARR_ACCESS: ret = identical_arr_access(exact, a, b); break; - case AST_TYPE_CONSTRUCT: ret = identical_type_construct(exact, a, b); break; case AST_TYPE_EXPAND: ret = identical_type_expand(exact, a, b); break; case AST_FETCH: ret = identical_fetch(exact, a, b); break; case AST_ASSIGN: ret = identical_assign(exact, a, b); break; @@ -1928,7 +1901,8 @@ int identical_ast_nodes(int exact, struct ast_node *a, struct ast_node *b) case AST_CALL: ret = identical_call(exact, a, b); break; case AST_CAST: ret = identical_cast(exact, a, b); break; case AST_DEFER: ret = identical_defer(exact, a, b); break; - case AST_MACRO_CONSTRUCT: ret = identical_macro_construct(exact, a, b); break; + case AST_MACRO_CONSTRUCT: ret = identical_macro_construct(exact, a, b); + break; case AST_MACRO_EXPAND: ret = identical_macro_expand(exact, a, b); break; case AST_PROC: ret = identical_proc(exact, a, b); break; case AST_VAR: ret = identical_var(exact, a, b); break; @@ -2068,7 +2042,7 @@ static int call_on_alias(int (*call)(struct ast_node *, } static int call_on_trait(int (*call)(struct ast_node *, - void *), struct ast_node *node, void *data) + void *), struct ast_node *node, void *data) { int ret = 0; ret |= call(node->_trait.id, data); @@ -2134,7 +2108,7 @@ static int call_on_case(int (*call)(struct ast_node *, } static int call_on_type_trait(int (*call)(struct ast_node *, - void *), struct ast_node *node, void *data) + void *), struct ast_node *node, void *data) { int ret = 0; ret |= call(AST_TRAIT_TYPE(node).def, data); @@ -2153,12 +2127,6 @@ static int call_on_type_arr(int (*call)(struct ast_node *, return call(AST_ARR_TYPE(node).size, data); } -static int call_on_type_typeof(int (*call)(struct ast_node *, - void *), struct ast_node *node, void *data) -{ - return call(AST_TYPEOF_TYPE(node).expr, data); -} - static int call_on_type_struct(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) { @@ -2193,8 +2161,8 @@ static int call_on_type(int (*call)(struct ast_node *, case AST_TYPE_TRAIT: ret = call_on_type_trait(call, node, data); break; case AST_TYPE_ID: ret = call_on_type_id(call, node, data); break; case AST_TYPE_ARR: ret = call_on_type_arr(call, node, data); break; - case AST_TYPE_TYPEOF: ret = call_on_type_typeof(call, node, data); break; - case AST_TYPE_STRUCT: ret = call_on_type_struct(call, node, data); break; + case AST_TYPE_STRUCT: ret = call_on_type_struct(call, node, data); + break; case AST_TYPE_SIGN: ret = call_on_type_sign(call, node, data); break; case AST_TYPE_POINTER: break; case AST_TYPE_PRIMITIVE: break; @@ -2234,13 +2202,13 @@ static int call_on_call(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) { int ret = 0; - ret |= call(node->_call.id, data); - ret |= call(node->_call.args, data); + ret |= call(AST_CALL(node).expr, data); + ret |= call(AST_CALL(node).args, data); return ret; } static int call_on_macro_construct(int (*call)(struct ast_node *, - void *), struct ast_node *node, void *data) + void *), struct ast_node *node, void *data) { int ret = 0; ret |= call(AST_MACRO_CONSTRUCT(node).id, data); @@ -2274,7 +2242,8 @@ static int call_on_fetch(int (*call)(struct ast_node *, return ret; } -static int call_on_macro_expand(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) +static int call_on_macro_expand(int (*call)(struct ast_node *, + void *), struct ast_node *node, void *data) { int ret = 0; ret |= call(node->_macro_expand.id, data); @@ -2282,17 +2251,8 @@ static int call_on_macro_expand(int (*call)(struct ast_node *, void *), struct a return ret; } -static int call_on_type_construct(int (*call)(struct ast_node *, void *), struct ast_node *type_construct, void *data) -{ - int ret = 0; - /* pretty verbose, hmm */ - ret |= call(AST_TYPE_CONSTRUCT(type_construct).id, data); - ret |= call(AST_TYPE_CONSTRUCT(type_construct).params, data); - ret |= call(AST_TYPE_CONSTRUCT(type_construct).body, data); - return ret; -} - -static int call_on_type_expand(int (*call)(struct ast_node *, void *), struct ast_node *type_expand, void *data) +static int call_on_type_expand(int (*call)(struct ast_node *, + void *), struct ast_node *type_expand, void *data) { int ret = 0; ret |= call(AST_TYPE_EXPAND(type_expand).id, data); @@ -2316,8 +2276,8 @@ int ast_call_on(int (*call)(struct ast_node *, switch (node->node_type) { case AST_ARR_ACCESS: - case AST_TYPE_CONSTRUCT: ret = call_on_type_construct(call, node, data); break; - case AST_TYPE_EXPAND: ret = call_on_type_expand(call, node, data); break; + case AST_TYPE_EXPAND: ret = call_on_type_expand(call, node, data); + break; case AST_FETCH: ret = call_on_fetch(call, node, data); break; case AST_ASSIGN: ret = call_on_assign(call, node, data); break; case AST_INIT: ret = call_on_init(call, node, data); break; @@ -2344,8 +2304,10 @@ int ast_call_on(int (*call)(struct ast_node *, case AST_BINOP: ret = call_on_binop(call, node, data); break; case AST_UNOP: ret = call_on_unop(call, node, data); break; case AST_CALL: ret = call_on_call(call, node, data); break; - case AST_MACRO_CONSTRUCT: ret = call_on_macro_construct(call, node, data); break; - case AST_MACRO_EXPAND: ret = call_on_macro_expand(call, node, data); break; + case AST_MACRO_CONSTRUCT: ret = + call_on_macro_construct(call, node, data); break; + case AST_MACRO_EXPAND: ret = call_on_macro_expand(call, node, data); + break; case AST_PROC: ret = call_on_proc(call, node, data); break; case AST_BLOCK: ret = call_on_block(call, node, data); break; case AST_EMBED: break; diff --git a/src/compiler.c b/src/compiler.c index a096878..5845283 100644 --- a/src/compiler.c +++ b/src/compiler.c @@ -103,7 +103,6 @@ static int process(struct scope **parent, int public, const char *file) scope->fctx.fbuf = buf; scope->fctx.fname = strdup(file); - scope->actuals = create_actuals(); scope_set_flags(scope, SCOPE_FILE); if (*parent) @@ -173,31 +172,21 @@ int compile(const char *input, const char *output) { return ret; } - ret = actualize_main(root); - if (ret) { + if ((ret = actualize_main(root))) { destroy_scope(root); destroy_ast_nodes(); error("compilation of %s stopped due to errors", input); return ret; } - struct ops *ops = create_ops(); - ret = lower_ops(root, ops); - destroy_scope(root); - destroy_ast_nodes(); - - if (ret) { - destroy_ops(ops); - error("compilation of %s stopped due to errors", input); - return ret; - } - - ret = alloc_regs(ops); - if (ret) { - destroy_ops(ops); + if ((ret = lower_ops(root, output))) { + destroy_scope(root); + destroy_ast_nodes(); error("compilation of %s stopped due to errors", input); return ret; } - return print_asm(ops, output); + destroy_scope(root); + destroy_ast_nodes(); + return 0; } diff --git a/src/debug.c b/src/debug.c index b110b9b..2c873a2 100644 --- a/src/debug.c +++ b/src/debug.c @@ -225,14 +225,9 @@ static void _type_str(FILE *fp, struct ast_node *type) break; } - case AST_TYPE_TYPEOF: { - fprintf(fp, "(typeof)"); - break; - } - case AST_TYPE_PRIMITIVE: { fprintf(fp, "%s", primitive_str(AST_PRIMITIVE_TYPE(type).type)); - break; + break; } default: @@ -271,11 +266,13 @@ char *type_str(struct ast_node *node) */ static void _call_str(FILE *f, struct ast_node *call) { - struct ast_node *id = call->_call.id; - const char *id_str = id->_id.id; - fprintf(f, "%s", id_str); + struct ast_node *expr = AST_CALL(call).expr; + if (expr->node_type == AST_ID) { + const char *id_str = AST_ID(expr).id; + fprintf(f, "%s", id_str); + } - struct ast_node *args = call->_call.args; + struct ast_node *args = AST_CALL(call).args; fprintf(f, "("); while (args) { diff --git a/src/lexer.l b/src/lexer.l index a446c49..c819328 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -39,7 +39,7 @@ HEXF [+-]?0[xX][0-9a-fA-F]+([pP][+-]?[0-9]+) DECF [+-]?[0-9]+[.]([eE]?[+-]?[0-9]+)?[fF]? ID [_a-zA-Z][_a-zA-Z0-9]* -APPLY {ID}[[:space:]]*! +APPLY {ID}! STRING \"(\\.|[^"\\])*\" @@ -151,7 +151,6 @@ STRING \"(\\.|[^"\\])*\" "struct" {return STRUCT;} "typedef" {return TYPEDEF;} "import" {return IMPORT;} -"typeof" {return TYPEOF;} "sizeof" {return SIZEOF;} "embed" {return EMBED;} "if" {return IF;} @@ -43,7 +43,7 @@ static size_t trivial_type_width(struct ast_node *type) return 3; } -struct ops *create_ops() +static struct ops *create_ops() { struct ops *ops = calloc(1, sizeof(struct ops)); @@ -56,15 +56,22 @@ struct ops *create_ops() return ops; } -void destroy_ops(struct ops *ops) +static void destroy_ops(struct ops *ops) { if (!ops) return; - struct op *base = ops->base; - while (base) { - struct op *prev = base; - base = base->next; + struct op *op = ops->base; + while (op) { + struct op *prev = op; + op = op->next; + + switch (prev->opcode) { + case OP_COMMENT: free((void *)prev->string); break; + case OP_LABEL: free((void *)prev->string); break; + default: + } + free(prev); } @@ -143,9 +150,9 @@ static int lower_var(struct ast_node *n, struct ops *ops) * immediately run out of registers? */ struct ast_node *type = d->type; if (AST_TYPE(type).kind != AST_TYPE_PRIMITIVE - && AST_TYPE(type).kind != AST_TYPE_POINTER) { + && AST_TYPE(type).kind != AST_TYPE_POINTER) { semantic_error(n->scope->fctx, n, - "only trivial type lowering implemented"); + "only trivial type lowering implemented"); return -1; } @@ -177,7 +184,8 @@ static int lower_cast(struct ast_node *n, struct ops *ops) static int lower_const(struct ast_node *n, struct ops *ops) { if (AST_CONST(n).kind != AST_CONST_INTEGER) { - semantic_error(n->scope->fctx, n, "only integer constant lowering implemented"); + semantic_error(n->scope->fctx, n, + "only integer constant lowering implemented"); return -1; } @@ -209,7 +217,8 @@ static int lower_assign(struct ast_node *n, struct ops *ops) static int lower_unop(struct ast_node *n, struct ops *ops) { if (AST_UNOP(n).op != AST_DEREF) { - semantic_error(n->scope->fctx, n, "unop lowering not implemented"); + semantic_error(n->scope->fctx, n, + "unop lowering not implemented"); return -1; } @@ -281,8 +290,8 @@ static int lower_op(struct ast_node *n, struct ops *ops) case AST_ID: ret = lower_id(n, ops); break; case AST_RETURN: ret = lower_ret(n, ops); break; default: - semantic_error(n->scope->fctx, n, "unimplemented lowering"); - return -1; + semantic_error(n->scope->fctx, n, "unimplemented lowering"); + return -1; } if (ret) @@ -353,21 +362,6 @@ static void print_ops(struct ops *ops) } } -int lower_ops(struct scope *root, struct ops *ops) -{ - for (struct actual *a = root->actuals; a; a = a->next) { - assert(a->node); - int ret = lower_op(a->node, ops); - if (ret) - return ret; - } - - printf("Lowered ops before lifetime analysis:\n"); - print_ops(ops); - - return 0; -} - static enum opcode st_opc(struct loc *loc) { switch (loc->width) { @@ -395,8 +389,9 @@ static int realize_moves(struct ops *ops) /* completely arbitrary and *will* have to be made better in the near * future */ static const size_t tmp_reg = 9; + struct op *prev = NULL; struct op *op = ops->base; - for (; op; op = op->next) { + for (; op; prev = op, op = op->next) { if (op->opcode != OP_MV) { continue; } @@ -407,12 +402,18 @@ static int realize_moves(struct ops *ops) assert(i->next == NULL); if (i->kind == LOC_REG && o->kind == LOC_REG) { - continue; - } else if (i->kind == LOC_REG && o->kind == LOC_MEM) { + /* if move is between the same register, skip it */ + if (i->reg == o->reg && prev) + prev->next = op->next; + + } + else if (i->kind == LOC_REG && o->kind == LOC_MEM) { op->opcode = st_opc(o); - } else if (i->kind == LOC_MEM && o->kind == LOC_REG) { + } + else if (i->kind == LOC_MEM && o->kind == LOC_REG) { op->opcode = ld_opc(i); - } else if (i->kind == LOC_MEM && o->kind == LOC_MEM) { + } + else if (i->kind == LOC_MEM && o->kind == LOC_MEM) { op->opcode = ld_opc(i); /* our input/output are references, so call this before * setting registers for our original operation. Also, @@ -428,12 +429,59 @@ static int realize_moves(struct ops *ops) return 0; } -int alloc_regs(struct ops *ops) +static int alloc_regs(struct ops *ops) { /** @todo analyze lifetime, for now just convert moves to correct ldst * etc. */ - int ret = realize_moves(ops); - printf("Lowered ops after lifetime analysis:\n"); - print_ops(ops); + /** @todo lifetime analysis could be done by looping over all ops, and + * when we encounter a virtual register we haven't seen before, add it + * to a list. When we encounter it used again, extend its lifetime to + * wherever we are in the function. */ + return realize_moves(ops); +} + +int lower_ops(struct scope *root, const char *fname) +{ + FILE *f = fopen(fname, "w"); + + /* main should probably be mangled here as well */ + fprintf(f, "jal x21, main\n"); + /* tell simulator to turn off (very much temp) */ + fprintf(f, "li x1, 3\n"); + fprintf(f, "csrrw mpower, x0, x1\n"); + + /* this can potentially be parallelized in the future */ + int ret = 0; + for (struct actual *a = root->actuals; a; a = a->next) { + assert(a->node); + + struct ops *ops = create_ops(); + if ((ret = lower_op(a->node, ops))) { + destroy_ops(ops); + break; + } + + printf("Lowered ops before lifetime analysis:\n"); + print_ops(ops); + + if ((ret = alloc_regs(ops))) { + destroy_ops(ops); + break; + } + + printf("Lowered ops after lifetime analysis:\n"); + print_ops(ops); + + if ((ret = print_asm(ops, f))) { + /* kind of silly as of now but eh */ + destroy_ops(ops); + break; + } + + destroy_ops(ops); + } + + fclose(f); return ret; } + diff --git a/src/parser.y b/src/parser.y index 4def5fd..1d09856 100644 --- a/src/parser.y +++ b/src/parser.y @@ -44,9 +44,6 @@ %token SEMICOLON ";" %token COLON ":" %token BANG "!" -/* still not sure if this should be just typeof, would be slower to type I guess */ -%token TYPEOF "typeof" -/* typeof does sort of fit into sizeof, hmmm */ %token SIZEOF "sizeof" %token STAR "*" %token DIV "/" @@ -119,7 +116,7 @@ %left "<<" ">>" %left "+" "-" %left "*" "/" "%" -%left "as" "sizeof" "typeof" +%left "as" "sizeof" %right "'" "!" "~" %left "." "=>" "(" ")" %left "::" @@ -129,12 +126,12 @@ %nterm <node> while do_while statement statements body references macro %nterm <node> exprs if for case cases switch const %nterm <node> func_sign type var_decl var -%nterm <node> var_init proc trait_elem trait_elems +%nterm <node> var_init proc %nterm <node> alias trait enum_val enums enum top unit id -%nterm <node> embed param_decl members struct_elem +%nterm <node> embed param_decl members %nterm <node> top_if const_if const_for defer goto assign %nterm <node> construct construct_args construct_arg -%nterm <node> statelet apply +%nterm <node> statelet apply types %nterm <node> tagged_struct anon_struct tagged_union anon_union @@ -143,11 +140,15 @@ %nterm <node> macro_expand type_expand -%nterm <node> type_construct type_params type_param +%nterm <node> type_params type_param /* array stuff */ %nterm <node> arr arr_inits arr_init +/* optional stuff */ +%nterm <node> opt_args opt_exprs proc_decl member opt_members +%nterm <node> opt_statements opt_types + %{ /** Modifies the signature of yylex to fit our parser better. */ @@ -278,8 +279,12 @@ unop | "*" expr { $$ = gen_unop(AST_DEREF, $2); } arr_init - : "=>" const_expr "..." const_expr "=" arg { $$ = gen_var($2, $4, $6); } - | "=>" const_expr "=" arg { $$ = gen_var($2, NULL, $4); } + : "=>" const_expr "..." const_expr "=" arg { + $$ = gen_var($2, $4, $6, src_loc(@$)); + } + | "=>" const_expr "=" arg { + $$ = gen_var($2, NULL, $4, src_loc(@$)); + } | arg arr_inits @@ -302,7 +307,7 @@ args | arg param_decl - : type { $$ = gen_var(NULL, $1, NULL); } + : type { $$ = gen_var(NULL, $1, NULL, src_loc(@$)); } | var_decl decls @@ -366,15 +371,15 @@ const_expr /* TODO: concatenate multiple strings together? Or is that the lexer's job? */ expr - : expr "." id { $$ = gen_dot($1, $3); } + : expr "." id { $$ = gen_dot($1, $3, src_loc(@$)); } | "..." id { $$ = $2; } | INT { $$ = gen_int($1); } | STRING { $$ = gen_string(clone_string($1)); } | "(" expr ")" { $$ = $2; } - | expr "(" args ")" { $$ = gen_call($1, $3); } - | expr "(" ")" { $$ = gen_call($1, NULL); } + | expr "(" args ")" { $$ = gen_call($1, $3, src_loc(@$)); } + | expr "(" ")" { $$ = gen_call($1, NULL, src_loc(@$)); } | expr "[" expr "]" { $$ = gen_arr_access($1, $3, src_loc(@$)); /** @todo add arr access */} | "(" var_init ")" { $$ = $2; } | "sizeof" expr { $$ = gen_sizeof($2); } @@ -404,16 +409,14 @@ goto statelet : "return" args { $$ = gen_return($2); } | "return" { $$ = gen_return(NULL); } - | "break" { $$ = gen_ctrl(AST_CTRL_BREAK, src_loc(yylloc)); } - | "continue" { $$ = gen_ctrl(AST_CTRL_CONTINUE, src_loc(yylloc)); } + | "break" { $$ = gen_ctrl(AST_CTRL_BREAK, src_loc(@$)); } + | "continue" { $$ = gen_ctrl(AST_CTRL_CONTINUE, src_loc(@$)); } | trait | import | alias | exprs - | const | goto | var - | ";" { $$ = gen_empty(); } | error { /* TODO: figure out how to destroy any and all possible ast nodes we * may have generated up until the error */ @@ -439,8 +442,10 @@ statement | for | defer | if + | const | enum | macro + | ";" { $$ = gen_empty(); } | id ":" { $$ = gen_label($1); } statements @@ -448,10 +453,12 @@ statements | statement | statelet +opt_statements + : statements + | {$$ = NULL;} body - : "{" statements "}" { $$ = gen_block($2); } - | "{" "}" { $$ = gen_block(gen_empty()); } + : "{" opt_statements "}" { $$ = gen_block($2); } references : id "," references { $$ = $1; $$->next = $3; } @@ -481,7 +488,7 @@ exprs construct_arg : "." id "=" expr { - $$ = gen_var($2, NULL, $4); + $$ = gen_var($2, NULL, $4, src_loc(@$)); ast_set_flags($$, AST_FLAG_MEMBER); } @@ -497,9 +504,17 @@ if | "if" expr body "else" body { $$ = gen_if($2, $3, $5); } | "if" expr body "else" if { $$ = gen_if($2, $3, $5); } -/* todo how about leaving out some parts? */ +opt_args + : args + | {$$ = NULL;} + +opt_exprs + : exprs + | {$$ = NULL;} + for - : "for" arg ";" expr ";" expr body { $$ = gen_for($2, $4, $6, $7); } + : "for" opt_args ";" opt_exprs ";" exprs body { $$ = gen_for($2, $4, $6, $7); } + | "for" opt_args ";" opt_exprs ";" body {} case : "case" const_expr ":" statements { @@ -509,6 +524,8 @@ case $$ = gen_case($2, $4); } | "default" ":" statements { + /* default seems like it would be useful as something other than + * a keyword... */ $$ = gen_case(NULL, $3); } @@ -550,29 +567,26 @@ const func_sign : "(" decls "=>" type ")" { - $$ = gen_type(AST_TYPE_SIGN, $2, $4, NULL); + $$ = gen_type(AST_TYPE_SIGN, $2, $4, src_loc(@$)); } - | "(" decls ")" { $$ = gen_type(AST_TYPE_SIGN, $2, NULL, NULL); } - | "(" decls "=>" ")" { $$ = gen_type(AST_TYPE_SIGN, $2, NULL, NULL); } - | "(" "=>" type ")" { $$ = gen_type(AST_TYPE_SIGN, NULL, $3, NULL); } - | "(" "=>" ")" { $$ = gen_type(AST_TYPE_SIGN, NULL, NULL, NULL); } - | "(" ")" { $$ = gen_type(AST_TYPE_SIGN, NULL, NULL, NULL); } + | "(" decls ")" { $$ = gen_type(AST_TYPE_SIGN, $2, NULL, src_loc(@$)); } + | "(" decls "=>" ")" { $$ = gen_type(AST_TYPE_SIGN, $2, NULL, src_loc(@$)); } + | "(" "=>" type ")" { $$ = gen_type(AST_TYPE_SIGN, NULL, $3, src_loc(@$)); } + | "(" "=>" ")" { $$ = gen_type(AST_TYPE_SIGN, NULL, NULL, src_loc(@$)); } + | "(" ")" { $$ = gen_type(AST_TYPE_SIGN, NULL, NULL, src_loc(@$)); } type - : id { $$ = gen_type(AST_TYPE_ID, $1, NULL, NULL); } + : id { $$ = gen_type(AST_TYPE_ID, $1, NULL, src_loc(@$)); } | "^" func_sign { /* still not entirely sold on this signature, but it's not terrible I * guess */ - $$ = gen_type(AST_TYPE_POINTER, $2, NULL, NULL); + $$ = gen_type(AST_TYPE_POINTER, $2, NULL, src_loc(@$)); } | "*" type { - $$ = gen_type(AST_TYPE_POINTER, $2, NULL, NULL); + $$ = gen_type(AST_TYPE_POINTER, $2, NULL, src_loc(@$)); } | "[" const_expr "]" type { - $$ = gen_type(AST_TYPE_ARR, $2, $4, NULL); - } - | "typeof" expr { - $$ = gen_type(AST_TYPE_TYPEOF, $2, NULL, NULL); + $$ = gen_type(AST_TYPE_ARR, $2, $4, src_loc(@$)); } | "const" type { $$ = $2; @@ -581,32 +595,37 @@ type $$ = $2; ast_set_flags($$, AST_FLAG_MUTABLE); } | anon_struct - /* syntactic sugar for struct {union {...} } */ | anon_union - /* syntactic sugar for anon_struct */ - | type_expand + | apply "[" opt_types "]" { + $$ = gen_type(AST_TYPE_CONSTRUCT, $1, $3, src_loc(@$)); + } types - : type "," types + : type "," types { $$ = $1; $$->next = $3; } | type -/* vec![int] is effectively struct {vec![int]} */ +opt_types + : types + | { $$ = NULL; } + type_expand - : apply "[" types "]" - /* legal, but weird */ - | apply "[" "]" + : apply "[" opt_types "]" { $$ = gen_type_expand($1, $3, src_loc(@$)); } var_decl - : type id { $$ = gen_var($2, $1, NULL); } + : type id { $$ = gen_var($2, $1, NULL, src_loc(@$)); } var_init : var_decl "=" arg { $$ = $1; $$->_var.init = $3; } - | "const" id "=" arg { $$ = gen_var($2, NULL, $4); } + | "const" id "=" arg { $$ = gen_var($2, NULL, $4, src_loc(@$)); } | "mut" id "=" arg { - $$ = gen_var($2, NULL, $4); + $$ = gen_var($2, NULL, $4, src_loc(@$)); ast_set_flags($$, AST_FLAG_MUTABLE); } +proc_decl + : id func_sign { + $$ = gen_proc($1, $2, NULL, src_loc(@$)); + } proc : id func_sign body { $$ = gen_proc($1, $2, $3, src_loc(@$)); @@ -619,74 +638,55 @@ proc ast_set_flags($$, AST_FLAG_EXTERN); } -struct_elem - : var_decl - | type_expand +member + : var_decl ";" + | type_expand ";" + | proc_decl ";" + | id ";" + | proc ; members - : struct_elem ";" members { $$ = $1; $1->next = $3; } - | struct_elem ";" + : member members { $$ = $1; $1->next = $2; } + | member + +opt_members + : members + | {$$ = NULL;} tagged_union - : "union" id "{" members "}" { + : "union" id "{" opt_members "}" { /* essentially struct {union{members}} */ $$ = gen_struct($2, NULL, $4); } anon_union - : "union" "{" members "}" { $$ = gen_struct(NULL, NULL, $3); } + : "union" "{" opt_members "}" { $$ = gen_struct(NULL, NULL, $3); } macro_expand - : apply "(" ")" { $$ = gen_macro_expand($1, NULL, src_loc(@$)); } - | apply "(" args ")" { $$ = gen_macro_expand($1, $3, src_loc(@$)); } + : apply "(" opt_args ")" { $$ = gen_macro_expand($1, $3, src_loc(@$)); } tagged_struct - : "struct" id "{" members "}" { + : "typedef" id "{" opt_members "}" { $$ = gen_struct($2, NULL, $4); } anon_struct - : "struct" "{" members "}" { $$ = gen_struct(NULL, NULL, $3); } - -trait_elem - : id /* trait */ - | id func_sign { $$ = gen_proc($1, $2, NULL, src_loc(@$)); } /* proc */ - | var_decl /* member */ - | type_expand /* type construction */ - -trait_elems - : trait_elem ";" trait_elems { $$ = $1; $1->next = $3; } - | trait_elem ";" - | trait_elem + : "typedef" "{" opt_members "}" { $$ = gen_struct(NULL, NULL, $3); } alias : "typedef" id type { $$ = gen_alias($2, $3); } -/* we'll parse the arg list later in the AST and check that each node is of some - * specific type */ -trait - : "typedef" id "{" trait_elems "}" { - $$ = gen_trait($2, $4); - } - | "typedef" id "{" "}" { - /* should match anything, but doesn't implement anything */ - $$ = gen_trait($2, NULL); - } - type_param - : id id { $$ = gen_var($2, $1, NULL); } + : id id { $$ = gen_var($2, $1, NULL, src_loc(@$)); } type_params : type_param "," type_params { $$ = $1; $1->next = $3; } | type_param -type_construct - : "typedef" id "[" type_params "]" "{" members "}" { - $$ = gen_type_construct($2, $4, $7, src_loc(@$)); - } - | "typedef" id "[" "]" "{" members "}" { - $$ = gen_type_construct($2, NULL, $6, src_loc(@$)); +trait + : "typedef" id "[" type_params "]" "{" opt_members "}" { + $$ = gen_trait($2, $4, $7, src_loc(@$)); } enum_val @@ -726,7 +726,6 @@ top | proc | tagged_struct | tagged_union - | type_construct | macro { $$ = $1; } | top_if { $$ = $1; ast_set_flags($$, AST_FLAG_CONST); } | import { $$ = $1; } @@ -735,7 +734,6 @@ top | "pub" enum { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); } | "pub" tagged_struct { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); } | "pub" tagged_union { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); } - | "pub" type_construct { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); } | "pub" proc { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); } | "pub" macro { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); } | "pub" import { $$ = $2; ast_set_flags($2, AST_FLAG_PUBLIC); } diff --git a/src/scope.c b/src/scope.c index 6c94aec..329b5f1 100644 --- a/src/scope.c +++ b/src/scope.c @@ -17,158 +17,6 @@ #include <ek/scope.h> #include <ek/actualize.h> -static struct ast_node *match_proc(struct scope *scope, - struct ast_node *id, - struct ast_node *args); - -static struct ast_node *match_macro(struct scope *scope, - struct ast_node *id, struct ast_node *args); - -static struct param_node *find_matching_param(struct resolve_node *node, - struct ast_node *type) -{ - struct param_node *param = node->params; - while (param) { - if (types_match(type, param->type)) - return param; - - param = param->next; - } - - return NULL; -} - -static int traits_resolve(struct ast_node *arg_type, struct ast_node *param_type) -{ - /** @todo are more checks required? arg_type should already be in - * `as`-form*/ - return AST_TRAIT_TYPE(arg_type).def == AST_TRAIT_TYPE(param_type).def; -} - -static int types_resolve(struct ast_node *arg_type, struct ast_node *param_type) -{ - /* untyped resolves all */ - if (!param_type) - return 1; - - /* if arg is specifying to be matches as `as`, then do it */ - if (AST_TYPE(arg_type).as) - return types_resolve(AST_TYPE(arg_type).as, param_type); - - if (AST_TYPE(param_type).kind == AST_TYPE_TRAIT) - return traits_resolve(arg_type, param_type); - - /* typeof is matched later */ - if (AST_TYPE(param_type).kind == AST_TYPE_TYPEOF) - return 1; - - return types_match(arg_type, param_type); -} - -static struct param_node *find_resolving_param(struct resolve_node *node, - struct ast_node *type) -{ - struct param_node *param = node->params; - while (param) { - if (types_resolve(type, param->type)) - return param; - - param = param->next; - } - - return NULL; -} - -static struct resolve_node *insert_resolve(struct resolve_node *node, - struct ast_node *type) -{ - struct param_node *new = calloc(1, sizeof(struct param_node)); - if (!new) { - return NULL; - } - new->type = type; - - struct resolve_node *next = calloc(1, sizeof(struct resolve_node)); - if (!next) { - free(new); - return NULL; - } - new->resolved = next; - - if (!node->params) { - node->params = new; - return next; - } - - new->next = node->params; - node->params = new; - - return next; -} - -static int add_next_resolve(struct scope *scope, struct ast_node *resolve, - struct resolve_node *node, struct ast_node *params) -{ - assert(node); - - /* TODO: variadics in macros? */ - /* we've run out of params, check if this is a suitable node */ - if (!params) { - /* node is already occupied, error on ambiguous definition */ - if (node->resolved) { - semantic_error(scope->fctx, resolve, "ambiguous resolution"); - semantic_error(scope->fctx, node->resolved, "matches here"); - return -1; - } - - node->resolved = resolve; - return 0; - } - - assert(params->node_type == AST_VAR); - struct param_node *match = find_matching_param(node, params->type); - if (match) - return add_next_resolve(scope, resolve, - match->resolved, - params->next); - - /** @todo referential stuff, should only one be allowed per slot or - * something? */ - struct resolve_node *next = insert_resolve(node, params->type); - if (!next) - return -1; - - return add_next_resolve(scope, resolve, next, params->next); -} - -static int add_resolve(struct scope *scope, struct resolve *resolve, - struct ast_node *proc) -{ - struct ast_node *sign = AST_PROC(proc).sign; - struct ast_node *params = AST_SIGN_TYPE(sign).params; - return add_next_resolve(scope, proc, resolve->root, params); -} - -static struct ast_node *resolve(struct scope *scope, - struct resolve_node *node, - struct ast_node *args) -{ - assert(node); - /* check for no parameters case */ - if (!args) { - if (node->resolved) - return node->resolved; - - return NULL; - } - - struct param_node *found = find_resolving_param(node, args->type); - if (found) - return resolve(scope, found->resolved, args->next); - - return NULL; -} - struct scope *create_scope() { /* if I ever try making the parser multithreaded, this should be atomic. */ @@ -184,17 +32,6 @@ struct scope *create_scope() return scope; } -struct actual *create_actuals() -{ - struct actual *actuals = calloc(1, sizeof(struct actual)); - if (!actuals) { - internal_error("ran out of memory allocating actuals"); - return NULL; - } - - return actuals; -} - void destroy_visible(struct scope *scope, struct visible *visible) { struct visible *prev = visible, *cur; @@ -206,63 +43,16 @@ void destroy_visible(struct scope *scope, struct visible *visible) } while ((prev = cur)); } -void destroy_actuals(struct actual *actuals) -{ - struct actual *prev = actuals, *cur; - if (prev) - do { - cur = prev->next; - free(prev); - } while ((prev = cur)); -} - -void destroy_resolve_node(struct resolve_node *); - -void destroy_param_nodes(struct param_node *param) -{ - if (!param) - return; - - destroy_resolve_node(param->resolved); - destroy_param_nodes(param->next); - free(param); -} - -void destroy_resolve_node(struct resolve_node *resolve) -{ - if (!resolve) - return; - - destroy_param_nodes(resolve->params); - free(resolve); -} - -void destroy_resolve(struct resolve *resolve) -{ - struct resolve *prev = resolve, *cur; - if (prev) - do { - cur = prev->next; - destroy_resolve_node(prev->root); - free(prev); - } while ((prev = cur)); -} - void destroy_scope(struct scope *scope) { if (!scope) return; if (scope_flags(scope, SCOPE_FILE)) { - destroy_actuals(scope->actuals); free((void *)scope->fctx.fbuf); free((void *)scope->fctx.fname); } - destroy_resolve(scope->proc_resolve); - destroy_resolve(scope->macro_resolve); - destroy_resolve(scope->type_construct_resolve); - destroy_visible(scope, scope->vars); destroy_visible(scope, scope->types); @@ -297,7 +87,8 @@ static struct visible *create_visible(struct ast_node *id, return visible; } -struct visible *create_type(struct scope *scope, struct ast_node *id, struct ast_node *type) +struct visible *create_type(struct scope *scope, struct ast_node *id, + struct ast_node *type) { struct visible *n = create_visible(id, type); if (!n) @@ -305,10 +96,12 @@ struct visible *create_type(struct scope *scope, struct ast_node *id, struct ast n->next = scope->types; scope->types = n; + return n; } -struct visible *create_var(struct scope *scope, struct ast_node *id, struct ast_node *var) +struct visible *create_var(struct scope *scope, struct ast_node *id, + struct ast_node *var) { struct visible *n = create_visible(id, var); if (!n) @@ -316,6 +109,33 @@ struct visible *create_var(struct scope *scope, struct ast_node *id, struct ast_ n->next = scope->vars; scope->vars = n; + + return n; +} + +struct visible *create_macro(struct scope *scope, struct ast_node *id, + struct ast_node *macro) +{ + struct visible *n = create_visible(id, macro); + if (!n) + return NULL; + + n->next = scope->macros; + scope->macros = n; + + return n; +} + +struct visible *create_proc(struct scope *scope, struct ast_node *id, + struct ast_node *proc) +{ + struct visible *n = create_visible(id, proc); + if (!n) + return NULL; + + n->next = scope->procs; + scope->procs = n; + return n; } @@ -329,13 +149,15 @@ int scope_add_var(struct scope *scope, struct ast_node *var) } create_var(scope, AST_VAR(var).id, var); - if (scope_flags(scope, SCOPE_FILE) && ast_flags(var, AST_FLAG_PUBLIC)) + if (scope->parent && + scope_flags(scope, SCOPE_FILE) && ast_flags(var, AST_FLAG_PUBLIC)) return scope_add_var(scope->parent, var); return 0; } -int scope_add_type(struct scope *scope, struct ast_node *id, struct ast_node *type) +int scope_add_type(struct scope *scope, struct ast_node *id, + struct ast_node *type) { struct ast_node *exists = file_scope_find_type(scope, id); if (exists) { @@ -345,333 +167,74 @@ int scope_add_type(struct scope *scope, struct ast_node *id, struct ast_node *ty } create_type(scope, id, type); - if (scope_flags(scope, SCOPE_FILE) && ast_flags(type, AST_FLAG_PUBLIC)) + if (scope->parent && + scope_flags(scope, SCOPE_FILE) && ast_flags(type, AST_FLAG_PUBLIC)) return scope_add_type(scope->parent, id, type); return 0; } -static void remove_implementation(struct ast_node *trait, - struct ast_node *type) -{ - assert(trait->node_type == AST_TRAIT); - struct trait_implemented *prev = trait->_trait.impl_by, *cur; - if (prev) - do { - cur = prev->next; - if (!cur) - break; - - if (identical_ast_nodes(0, cur->type, type)) { - struct trait_implemented *next = cur->next; - prev->next = next; - free(cur); - return; - } - } while ((prev = cur)); -} - -static int implements_proc(enum match_flags flags, struct scope *scope, - struct ast_node *arg_type, - struct ast_node *param_type, struct ast_node *proc) -{ - (void)(flags); - (void)(scope); - (void)(arg_type); - (void)(param_type); - assert(proc->node_type == AST_PROC); - /** @todo implement */ - return 0; -} - -static int implements_var(enum match_flags flags, struct scope *scope, - struct ast_node *arg_type, - struct ast_node *param_type, struct ast_node *var) -{ - (void)(flags); - (void)(scope); - (void)(arg_type); - (void)(param_type); - assert(var->node_type == AST_VAR); - /** @todo implement */ - return 0; -} - -static int implements_trait(enum match_flags flags, struct scope *scope, - struct ast_node *arg_type, - struct ast_node *param_type) -{ - assert(AST_TYPE(param_type).kind == AST_TYPE_TRAIT); - struct ast_node *trait = AST_TRAIT_TYPE(param_type).def; - struct ast_node *body = AST_TRAIT(trait).body; - - /* if the body is empty, match */ - struct ast_node *elem = body; - if (!elem) - return 1; - - /* this is somewhat ugly, hmmm */ - do { - if (elem->node_type == AST_VAR) { - if (implements_var(flags, scope, arg_type, - param_type, - elem)) - continue; - - char *type = type_str(arg_type); - struct ast_node *id = elem->_proc.id; - semantic_error(scope->fctx, elem, - "%s does not have member %s", - type, id->_id.id); - free(type); - goto not_implemented; - } - - else if (elem->node_type == AST_PROC) { - if (implements_proc(flags, scope, arg_type, - param_type, - elem)) - continue; - - char *type = type_str(arg_type); - struct ast_node *id = elem->_proc.id; - semantic_error(scope->fctx, elem, - "%s does not implement %s", - type, id->_id.id); - free(type); - goto not_implemented; - } - - else { - semantic_error(scope->fctx, elem, - "illegal trait element"); - goto not_implemented; - } - } while ((elem = elem->next)); - - return 1; - -not_implemented: - remove_implementation(trait, arg_type); - return 0; -} - -static int implements_typeof(enum match_flags flags, struct scope *scope, - struct ast_node *arg_type, - struct ast_node *param_type) -{ - internal_error("typeof implementation unimplemented"); - return implements(flags, scope, arg_type, param_type); -} - -int implements(enum match_flags flags, struct scope *scope, - struct ast_node *arg_type, struct ast_node *param_type) -{ - /* if both types are null, they are uninitialized and we'll assume they - * don't implement eachother. This essentially means that during the - * analysis phase everything is added to the procs */ - if (!arg_type && !param_type) - return 0; - - /* slight hack: macro arguments also don't have a type, so they will - * also 'implement' type */ - if (!param_type) - return 1; - - /* at this point, we should always have some type for the argument */ - assert(arg_type); - - if (AST_TYPE(param_type).kind == AST_TYPE_TYPEOF) - return implements_typeof(flags, scope, arg_type, param_type); - - if (AST_TYPE(param_type).kind == AST_TYPE_TRAIT) - return implements_trait(flags, scope, arg_type, param_type); - - return types_match(arg_type, param_type); -} - -static int match_actual_params(enum match_flags flags, struct scope *scope, - struct ast_node *args, struct ast_node *params) -{ - /** @todo essentially just iterate over the parameters, right? */ - return 0; -} - -static struct ast_node *match_resolve(struct scope *scope, - struct resolve *s, - struct ast_node *id, - struct ast_node *args) -{ - while (s) { - /** @todo linear search, a hashmap would be faster */ - if (identical_ast_nodes(0, s->id, id)) - return resolve(scope, s->root, args); - - s = s->next; - } - - return NULL; -} - -static struct ast_node *match_macro(struct scope *scope, - struct ast_node *id, - struct ast_node *args) -{ - return match_resolve(scope, scope->macro_resolve, id, args); -} - -static struct ast_node *match_proc(struct scope *scope, - struct ast_node *id, - struct ast_node *args) -{ - return match_resolve(scope, scope->proc_resolve, id, args); -} - -static struct ast_node *match_type_construct(struct scope *scope, - struct ast_node *id, - struct ast_node *args) -{ - return match_resolve(scope, scope->type_construct_resolve, id, args); -} - - -static int add_proc_resolve(struct scope *scope, struct ast_node *proc) -{ - if (!scope->proc_resolve) { - scope->proc_resolve = calloc(1, sizeof(struct resolve)); - } - - struct resolve *resolve = scope->proc_resolve; - while (resolve) { - if (identical_ast_nodes(0, resolve->id, proc->_proc.id)) - return add_resolve(scope, resolve, proc); - - resolve = resolve->next; - } - - resolve = calloc(1, sizeof(struct resolve)); - resolve->root = calloc(1, sizeof(struct resolve_node)); - resolve->id = clone_ast_node(proc->_proc.id); - resolve->next = scope->proc_resolve; - scope->proc_resolve = resolve; - - return add_resolve(scope, resolve, proc); -} - -static int add_macro_resolve(struct scope *scope, struct ast_node *macro) -{ - if (!scope->macro_resolve) { - scope->macro_resolve = calloc(1, sizeof(struct resolve)); - } - - struct resolve *resolve = scope->macro_resolve; - while (resolve) { - if (identical_ast_nodes(0, resolve->id, AST_MACRO_CONSTRUCT(macro).id)) - return add_resolve(scope, resolve, macro); - - resolve = resolve->next; - } - - resolve = calloc(1, sizeof(struct resolve)); - resolve->root = calloc(1, sizeof(struct resolve_node)); - resolve->id = clone_ast_node(AST_MACRO_CONSTRUCT(macro).id); - resolve->next = scope->macro_resolve; - scope->macro_resolve = resolve; - - return add_resolve(scope, resolve, macro); -} - int scope_add_macro(struct scope *scope, struct ast_node *macro) { assert(macro->node_type == AST_MACRO_CONSTRUCT); - struct ast_node *id = AST_MACRO_CONSTRUCT(macro).id; - struct ast_node *params = AST_MACRO_CONSTRUCT(macro).params; - - struct ast_node *exists = match_macro(scope, id, params);; + struct ast_node *exists = file_scope_find_macro(scope, AST_MACRO_CONSTRUCT( + macro).id); if (exists) { semantic_error(scope->fctx, macro, "macro redefined"); semantic_info(scope->fctx, exists, "previously here"); return -1; } - add_macro_resolve(scope, macro); - - if (scope_flags(scope, SCOPE_FILE) && ast_flags(macro, AST_FLAG_PUBLIC)) + /* always add to scope, do resolve checking later */ + create_macro(scope, AST_MACRO_CONSTRUCT(macro).id, macro); + if (scope->parent && + scope_flags(scope, SCOPE_FILE) && ast_flags(macro, AST_FLAG_PUBLIC)) return scope_add_macro(scope->parent, macro); return 0; } -int add_type_construct_resolve(struct scope *scope, struct ast_node *type_construct) -{ - if (!scope->type_construct_resolve) { - scope->type_construct_resolve = calloc(1, sizeof(struct resolve)); - } - - struct resolve *resolve = scope->type_construct_resolve; - while (resolve) { - if (identical_ast_nodes(0, resolve->id, AST_TYPE_CONSTRUCT(type_construct).id)) - return add_resolve(scope, resolve, type_construct); - - resolve = resolve->next; - } - - resolve = calloc(1, sizeof(struct resolve)); - resolve->root = calloc(1, sizeof(struct resolve_node)); - resolve->id = clone_ast_node(AST_TYPE_CONSTRUCT(type_construct).id); - resolve->next = scope->type_construct_resolve; - scope->type_construct_resolve = resolve; - - return add_resolve(scope, resolve, type_construct); -} - int scope_add_proc(struct scope *scope, struct ast_node *proc) { assert(proc->node_type == AST_PROC); - - struct ast_node *id = AST_PROC(proc).id; - struct ast_node *sign = AST_PROC(proc).sign; - struct ast_node *params = AST_SIGN_TYPE(sign).params; - - struct ast_node *exists = match_proc(scope, id, params); - + struct ast_node *exists = + file_scope_find_proc(scope, AST_PROC(proc).id); if (exists) { semantic_error(scope->fctx, proc, "proc redefined"); semantic_info(scope->fctx, exists, "previously here"); return -1; } - - add_proc_resolve(scope, proc); - - if (scope_flags(scope, SCOPE_FILE) && ast_flags(proc, AST_FLAG_PUBLIC)) + /* always add to scope, do resolve checking later */ + create_proc(scope, AST_PROC(proc).id, proc); + if (scope->parent && + scope_flags(scope, SCOPE_FILE) && ast_flags(proc, AST_FLAG_PUBLIC)) return scope_add_proc(scope->parent, proc); return 0; } -int scope_add_type_construct(struct scope *scope, struct ast_node *type_construct) +int scope_add_trait(struct scope *scope, struct ast_node *trait) { - assert(type_construct->node_type == AST_TYPE_CONSTRUCT); - - struct ast_node *id = AST_TYPE_CONSTRUCT(type_construct).id; - struct ast_node *params = AST_TYPE_CONSTRUCT(type_construct).params; + assert(trait->node_type == AST_TRAIT); - struct ast_node *exists = match_type_construct(scope, id, params); + struct ast_node *id = AST_TRAIT(trait).id; + struct ast_node *exists = file_scope_find_type(scope, id); if (exists) { - semantic_error(scope->fctx, type_construct, "type construct redefined"); + semantic_error(scope->fctx, trait, "type redefined"); semantic_info(scope->fctx, exists, "previously here"); return -1; } - add_type_construct_resolve(scope, type_construct); - - if (scope_flags(scope, SCOPE_FILE) && ast_flags(type_construct, AST_FLAG_PUBLIC)) - return scope_add_type_construct(scope->parent, type_construct); + create_type(scope, id, trait); + if (scope->parent && + scope_flags(scope, SCOPE_FILE) && ast_flags(trait, AST_FLAG_PUBLIC)) + return scope_add_trait(scope->parent, trait); return 0; } -static struct ast_node *scope_find_visible(struct visible *v, struct ast_node *id) +static struct ast_node *scope_find_visible(struct visible *v, + struct ast_node *id) { if (!v) return NULL; @@ -708,134 +271,71 @@ struct ast_node *file_scope_find_type(struct scope *scope, return NULL; } -struct ast_node *scope_find_var(struct scope *scope, struct ast_node *var) +struct ast_node *scope_find_macro(struct scope *scope, struct ast_node *macro) { - return scope_find_visible(scope->vars, var); + return scope_find_visible(scope->macros, macro); } -struct ast_node *file_scope_find_var(struct scope *scope, struct ast_node *var) +struct ast_node *file_scope_find_macro(struct scope *scope, + struct ast_node *macro) { - assert(var->node_type == AST_ID); + assert(macro->node_type == AST_ID); if (!scope) return NULL; - struct ast_node *found = scope_find_var(scope, var); + struct ast_node *found = scope_find_macro(scope, macro); if (found) return found; if (!scope_flags(scope, SCOPE_FILE)) - return file_scope_find_var(scope->parent, var); + return file_scope_find_macro(scope->parent, macro); return NULL; } -struct ast_node *scope_resolve_macro(struct scope *scope, struct ast_node *macro) -{ - assert(macro->node_type == AST_MACRO_EXPAND); - struct ast_node *id = macro->_macro_expand.id; - struct ast_node *args = macro->_macro_expand.args; - return match_macro(scope, id, args); -} - -struct ast_node *scope_resolve_proc(struct scope *scope, struct ast_node *call) +struct ast_node *scope_find_proc(struct scope *scope, struct ast_node *proc) { - assert(call->node_type == AST_CALL); - struct ast_node *id = call->_call.id; - struct ast_node *args = call->_call.args; - return match_proc(scope, id, args); + return scope_find_visible(scope->procs, proc); } -struct ast_node *scope_resolve_actual(struct scope *scope, - struct ast_node *call) +struct ast_node *file_scope_find_proc(struct scope *scope, + struct ast_node *proc) { - assert(call->node_type == AST_CALL); - struct actual *prev = scope->actuals, *cur; - - if (prev) - do { - cur = prev->next; - struct ast_node *actual = prev->node; - if (!actual) - continue; - - if (!identical_ast_nodes(0, actual->_proc.id, - call->_call.id)) - continue; - - assert(!ast_flags(actual, AST_FLAG_VARIADIC)); - /* could also check that arguments aren't traits */ - struct ast_node *args = AST_CALL(call).args; - struct ast_node *sign = AST_PROC(actual).sign; - struct ast_node *params = AST_SIGN_TYPE(sign).params; - if (match_actual_params(0, scope, args, params)) - return actual; - - } while ((prev = cur)); - - return NULL; -} + assert(proc->node_type == AST_ID); + if (!scope) + return NULL; -struct ast_node *scope_resolve_call(struct scope *scope, struct ast_node *call) -{ - assert(call->node_type == AST_CALL); - /* unsure if actual should be here or somewhere else but eh */ - struct ast_node *found = scope_resolve_actual(scope, call); + struct ast_node *found = scope_find_proc(scope, proc); if (found) return found; - found = scope_resolve_proc(scope, call); - if (found) - return found; + if (!scope_flags(scope, SCOPE_FILE)) + return file_scope_find_proc(scope->parent, proc); return NULL; } -struct ast_node *file_scope_resolve_call(struct scope *scope, - struct ast_node *call) +struct ast_node *scope_find_var(struct scope *scope, struct ast_node *var) { - struct ast_node *found = scope_resolve_call(scope, call); - if (found) - return found; - - if (!scope_flags(scope, SCOPE_FILE)) - return file_scope_resolve_call(scope->parent, call); - - return NULL; + return scope_find_visible(scope->vars, var); } -struct ast_node *file_scope_resolve_macro(struct scope *scope, struct ast_node *macro) +struct ast_node *file_scope_find_var(struct scope *scope, struct ast_node *var) { - struct ast_node *found = scope_resolve_macro(scope, macro); + assert(var->node_type == AST_ID); + if (!scope) + return NULL; + + struct ast_node *found = scope_find_var(scope, var); if (found) return found; if (!scope_flags(scope, SCOPE_FILE)) - return file_scope_resolve_macro(scope->parent, macro); + return file_scope_find_var(scope->parent, var); return NULL; } -/* this might be useful somewhere else as well */ -static enum ast_primitive default_types[] = {AST_VOID, AST_I9, AST_I27}; -static const char *default_names[] = {"void", "i9", "i27"}; - -/* TODO: add error checking */ -int scope_add_defaults(struct scope *root) -{ - for (size_t i = 0; - i < sizeof(default_types) / sizeof(default_types[0]); - ++i) { - struct ast_node *n = gen_id(strdup(default_names[i]), NULL_LOC()); - struct ast_node *a = gen_primitive(default_types[i], NULL_LOC()); - if (!a) - return -1; - - scope_add_type(root, n, a); - } - - return 0; -} - void scope_add_scope(struct scope *parent, struct scope *child) { assert(parent); @@ -874,38 +374,3 @@ int scope_add_actual(struct scope *scope, struct ast_node *node) { return add_actual(scope->actuals, node); } - -static struct ast_node *find_actual(struct actual *actuals, - struct ast_node *node) -{ - assert(node->node_type == AST_ID); - - if (!actuals) - return NULL; - - do { - struct ast_node *actual = actuals->node; - if (identical_ast_nodes(0, actual->_proc.id, node)) - return actual; - - } while ((actuals = actuals->next)); - - return NULL; -} - -struct ast_node *scope_find_actual(struct scope *scope, struct ast_node *node) -{ - return find_actual(scope->actuals, node); -} - -struct scope *create_temp_scope(struct scope *parent) -{ - struct scope *scope = create_scope(); - if (!scope) { - internal_error("failed allocating temp scope"); - } - - scope->parent = parent; - scope->fctx = parent->fctx; - return scope; -} |
