diff options
| -rw-r--r-- | include/ek/ast.h | 99 | ||||
| -rw-r--r-- | include/ek/debug.h | 1 | ||||
| -rw-r--r-- | include/ek/scope.h | 67 | ||||
| -rw-r--r-- | src/actualize.c | 264 | ||||
| -rw-r--r-- | src/ast.c | 459 | ||||
| -rw-r--r-- | src/debug.c | 10 | ||||
| -rw-r--r-- | src/lexer.l | 2 | ||||
| -rw-r--r-- | src/parser.y | 204 | ||||
| -rw-r--r-- | src/scope.c | 651 |
9 files changed, 665 insertions, 1092 deletions
diff --git a/include/ek/ast.h b/include/ek/ast.h index feece73..421d247 100644 --- a/include/ek/ast.h +++ b/include/ek/ast.h @@ -10,6 +10,8 @@ * Abstract syntax tree handling. */ +#define AST_GET(x, y) x->x.y + /** Binary operands, that is they take two arguments and produce a result. */ enum ast_binops { /** Add, \c + */ @@ -22,16 +24,8 @@ enum ast_binops { AST_DIV, /** Remainder, \c % */ AST_REM, - /** Bitwise exclusive or, \c ^ */ - AST_XOR, - /** Raise to power \c ^^ (likely not necessary) */ - AST_POW, - /** Bitwise and, \c & */ - AST_AND, /** Logical and, \c && */ AST_LAND, - /** Bitwise or, \c | */ - AST_OR, /** Logical or, \c ||*/ AST_LOR, /** Left shift (logical), \c << @todo add arithmetic shifts? */ @@ -48,12 +42,6 @@ enum ast_binops { AST_ASSIGN_DIV, /** Assigning remainder, \c %= */ AST_ASSIGN_REM, - /** Assigning bitwise and, \c &= */ - AST_ASSIGN_AND, - /** Assigning bitwise or, \c |= */ - AST_ASSIGN_OR, - /** Assigning bitwise exclusive or, \c ^= */ - AST_ASSIGN_XOR, /** Assigning logical left shift, \c >>= */ AST_ASSIGN_LSHIFT, /** Assigning logical right shift, \c <<= */ @@ -82,10 +70,10 @@ enum ast_unops { AST_REF, /** Dereferencing, \c ' */ AST_DEREF, - /** Bitwise negation, i.e. inverting bits, \c ~ */ - AST_NOT }; +#define NULL_LOC() ((struct src_loc){0, 0, 0, 0}) + /** Represents a source location, spanning over some bit of code. */ struct src_loc { /** First line of interesting text. */ @@ -110,8 +98,9 @@ enum ast_node_type { AST_INIT, /** Assignment. */ AST_ASSIGN, - /** Call. We don't know to what yet: macro, array or procedure.*/ + /** Call procedure. */ AST_CALL, + AST_ARR_ACCESS, /** Sizeof. */ AST_SIZEOF, /** Cast. */ @@ -119,10 +108,10 @@ enum ast_node_type { /** Defer. */ AST_DEFER, /** Macro definition. */ - AST_MACRO, - AST_MACRO_EXPANSION, - /** Reference to previous expression, i.e. \c @ */ - AST_LAST, + AST_MACRO_CONSTRUCT, + AST_MACRO_EXPAND, + AST_TYPE_CONSTRUCT, + AST_TYPE_EXPAND, /** Procedure definition. */ AST_PROC, /** Goto. */ @@ -162,8 +151,6 @@ enum ast_node_type { AST_IMPORT, /** Enum definition. */ AST_ENUM, - /** Union definition. */ - AST_UNION, /** Enum constant value. */ AST_VAL, /** Switch. */ @@ -310,6 +297,11 @@ struct ast_label { struct ast_node *defers; }; +struct ast_arr_access { + struct ast_node *base; + struct ast_node *idx; +}; + /** Goto node. */ struct ast_goto { /** Name of label to jump to. */ @@ -394,7 +386,7 @@ struct ast_defer { }; /** Macro definition. */ -struct ast_macro { +struct ast_macro_construct { /** Name of macro. */ struct ast_node *id; /** Parameters macro takes. */ @@ -403,7 +395,18 @@ struct ast_macro { struct ast_node *body; }; -struct ast_macro_expansion { +struct ast_macro_expand { + struct ast_node *id; + struct ast_node *args; +}; + +struct ast_type_construct { + struct ast_node *id; + struct ast_node *params; + struct ast_node *body; +}; + +struct ast_type_expand { struct ast_node *id; struct ast_node *args; }; @@ -648,16 +651,6 @@ struct ast_struct { struct ast_node *body; }; -/** Union definition. */ -struct ast_union { - /** Name of union. */ - struct ast_node *id; - /** List of type parameters, if any. */ - struct ast_node *generics; - /** Body. */ - struct ast_node *body; -}; - /** Enum member constant value. */ struct ast_val { /** Name of member. */ @@ -741,8 +734,9 @@ struct ast_node { /** Data relevant to kind. */ union { + struct ast_arr_access arr_access; /** Binary operation. */ - struct ast_binop _binop; + struct ast_binop binop; /** Unary operation. */ struct ast_unop _unop; /** Call. */ @@ -750,8 +744,10 @@ struct ast_node { /** Cast. */ struct ast_cast _cast; /** Macro definition. */ - struct ast_macro _macro; - struct ast_macro_expansion _macro_expansion; + struct ast_macro_construct _macro; + struct ast_macro_expand _macro_expand; + struct ast_type_construct type_construct; + struct ast_type_expand type_expand; /** Procedure definition. */ struct ast_proc _proc; /** Goto. */ @@ -794,8 +790,6 @@ struct ast_node { struct ast_enum _enum; /** Structure definition. */ struct ast_struct _struct; - /** Union definition. */ - struct ast_union _union; /** Enum value. */ struct ast_val _val; /** Switch case. */ @@ -819,6 +813,8 @@ struct ast_node { }; }; +struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx, struct src_loc loc); + /** * Generate binary operation node. * @@ -828,7 +824,9 @@ struct ast_node { * @return Corresponding AST node. */ struct ast_node *gen_binop(enum ast_binops op, - struct ast_node *left, struct ast_node *right); + struct ast_node *left, + struct ast_node *right, + struct src_loc loc); /** * Generate unary operation. @@ -854,7 +852,7 @@ struct ast_node *gen_call(struct ast_node *id, struct ast_node *args); * @param id ID. * @return Corresponding AST node. */ -struct ast_node *gen_id(const char *id); +struct ast_node *gen_id(const char *id, struct src_loc loc); /** * Generate constant integer. @@ -947,9 +945,22 @@ struct ast_node *gen_ctrl(enum ast_ctrl_kind kind, struct src_loc loc); * @param body Macro body. * @return Corresponding AST node. */ -struct ast_node *gen_macro(struct ast_node *id, struct ast_node *params, +struct ast_node *gen_macro_construct(struct ast_node *id, struct ast_node *params, struct ast_node *body); +struct ast_node *gen_macro_expand(struct ast_node *id, struct ast_node *args); + +struct ast_node *gen_type_construct(struct ast_node *id, + struct ast_node *params, + struct ast_node *body, + struct src_loc loc); + +/** @todo change args to type type when I figure out how it should be + * constructed */ +struct ast_node *gen_type_expand(struct ast_node *id, + struct ast_node *args, + struct src_loc loc); + /** * Generate if. * @@ -1079,8 +1090,6 @@ struct ast_node *gen_alias(struct ast_node *id, struct ast_node *type); */ struct ast_node *gen_trait(struct ast_node *id, struct ast_node *body); -struct ast_node *gen_macro_expansion(struct ast_node *id, struct ast_node *args); - /** * Generate import; * diff --git a/include/ek/debug.h b/include/ek/debug.h index d222cf4..588fc6b 100644 --- a/include/ek/debug.h +++ b/include/ek/debug.h @@ -121,6 +121,7 @@ void semantic_error(struct file_ctx ctx, struct ast_node *node, const char *fmt, * @param fmt Format string. Follows standard printf() formatting. */ void internal_error(const char *fmt, ...); +void internal_warn(const char *fmt, ...); /** Issue categorization. */ enum issue_level { diff --git a/include/ek/scope.h b/include/ek/scope.h index 422af0f..020aaaa 100644 --- a/include/ek/scope.h +++ b/include/ek/scope.h @@ -75,13 +75,13 @@ struct actual { * matched against this resolution tree to know * which callable to choose. */ -struct callable { - /** Resolve tree of callable. */ - struct proc_node *root; - /** AST node ID of callable. */ +struct resolve { + /** Resolve tree of resolve. */ + struct resolve_node *root; + /** AST node ID of resolve. */ struct ast_node *id; - /** Next callable node. */ - struct callable *next; + /** Next resolve node. */ + struct resolve *next; }; /** A parameter node in the procedure resolution tree. */ @@ -89,7 +89,7 @@ struct param_node { /** Parameter type. */ struct ast_node *type; /** Fully resolved procedure if there is no next node. */ - struct proc_node *proc; + struct resolve_node *resolved; /** Next parameter node in current parameter slot. */ struct param_node *next; }; @@ -134,27 +134,12 @@ struct param_node { * do_stuff(some_struct(u8)){} // ERR * @endverbatim */ -struct proc_node { - /** List of primitive types of the current parameter slot. */ - struct param_node *primitives; - /** - * Referential type for parameter slot. - * Each parameter slot only allows a single referential type, because - * it would be too difficult to check if a reference is identical - * to another. Some special cases are somewhat trivially checked, but - * I haven't been able to come up with a generic enough check. - */ - struct param_node *referential; - - /** - * Fallback generic type for parameter slot. - * Each parameter slot only allows a single generic type, because - * it would be too difficult to check if two types have overlap. - */ - struct param_node *fallback; +struct resolve_node { + /** List of parameters of the current parameter slot. */ + struct param_node *params; /** Next procedure with parameter slot. */ - struct ast_node *proc; + struct ast_node *resolved; }; @@ -197,8 +182,6 @@ struct scope { /** { types */ /** Enums visible in scope. */ struct visible *enums; - /** Unions visible in scope. */ - struct visible *unions; /** Structs visible in scope. */ struct visible *structs; @@ -213,14 +196,15 @@ struct scope { struct visible *builtins; /** - * Templates visible in scope. + * Traits visible in scope. * @todo choose common terminology, sometimes the same thing is referred * to as interfaces, sometimes templates, sometimes just type. */ struct visible *traits; /** } */ - /** { Callables, incl. variables. */ + struct visible *type_constructs; + /** * Variables visible in scope. * @note Only some variables are callable, namely array variables. @@ -231,19 +215,10 @@ struct scope { struct visible *macros; /** Procedures visible in scope. */ struct visible *procs; - /** } */ - /** { callables */ - /** - * Anything callable. - * @note currently each type of callable is first - * collected into its corresponding visible list, - * \p vars, \p macros or \p procs, but after the initial - * program analysis they are merged together to create a callable - * resolve tree. - */ - struct callable *callable; - /** } */ + struct resolve *proc_resolve; + struct resolve *macro_resolve; + struct resolve *type_construct_resolve; }; /** Flags for matching objects during search. */ @@ -428,7 +403,9 @@ int scope_add_alias(struct scope *scope, struct ast_node *alias); * @param type_template Template to add to scope. * @return \c 0 when succesful, non-zero otherwise. */ -int scope_add_template(struct scope *scope, struct ast_node *type_template); +int scope_add_trait(struct scope *scope, struct ast_node *trait); + +int scope_add_type_construct(struct scope *scope, struct ast_node *type_construct); /** * Add an already allocated visible variable node to scope. @@ -546,7 +523,7 @@ struct ast_node *scope_find_alias(struct scope *scope, struct ast_node *id); * @return Pointer to the AST node corresponding to \p id if found, * otherwise \c NULL. */ -struct ast_node *scope_find_template(struct scope *scope, struct ast_node *id); +struct ast_node *scope_find_trait(struct scope *scope, struct ast_node *id); /** * Find anything with ID visible to \p scope. @@ -617,7 +594,7 @@ struct ast_node *file_scope_find_alias(struct scope *scope, * @return Pointer to the AST node corresponding to \p id if found, * otherwise \c NULL. */ -struct ast_node *file_scope_find_template(struct scope *scope, +struct ast_node *file_scope_find_trait(struct scope *scope, struct ast_node *id); /** diff --git a/src/actualize.c b/src/actualize.c index 3a381e0..7a9e13d 100644 --- a/src/actualize.c +++ b/src/actualize.c @@ -74,7 +74,7 @@ static struct ast_node *void_type() return NULL; } - struct ast_node *void_id = gen_id(void_str); + struct ast_node *void_id = gen_id(void_str, NULL_LOC()); if (!void_id) { internal_error("couldn't allocate void id"); free(void_str); @@ -100,7 +100,7 @@ static struct ast_node *i64_type() return NULL; } - struct ast_node *i64_id = gen_id(i64_str); + struct ast_node *i64_id = gen_id(i64_str, NULL_LOC()); if (!i64_id) { internal_error("couldn't allocate i64 id"); free(i64_str); @@ -344,11 +344,6 @@ static int analyze_file_visibility(struct scope *scope, struct ast_node *node) break; } - case AST_UNION: { - ret |= scope_add_type(scope, node); - break; - } - case AST_ENUM: { ret |= scope_add_type(scope, node); break; @@ -360,11 +355,16 @@ static int analyze_file_visibility(struct scope *scope, struct ast_node *node) } case AST_TRAIT: { - ret |= scope_add_type(scope, node); + ret |= scope_add_trait(scope, node); + break; + } + + case AST_TYPE_CONSTRUCT: { + ret |= scope_add_type_construct(scope, node); break; } - case AST_MACRO: { + case AST_MACRO_CONSTRUCT: { ret |= scope_add_macro(scope, node); break; } @@ -406,70 +406,12 @@ static int analyze(struct scope *scope, struct ast_node *tree) return 0; } -/* I would be more happy with a system where proc signatures are actualized - * on demand, but the current scope implementation doesn't work that well for it. - * Relatively straight forward to implement some kind of actualization - * forwarding, the main issue is detecting duplicates. */ -static int analyze_procs(struct scope *scope) -{ - struct visible *procs = scope->procs; - /* - struct act_state state = {0}; - act_set_flags(&state, ACT_ONLY_TYPES); - if (procs) - do { - if (procs->owner != scope) - goto skip_actualize; - - struct ast_node *proc = procs->node; - if (actualize(&state, scope, proc)) - return -1; - - skip_actualize: - procs = procs->next; - } while (procs); - */ - - /* reinsert procs with actualized signatures, should make sure we don't - * have duplicates after all aliases etc. have been eliminated */ - procs = scope->procs; - if (procs) - do { - struct visible *next = procs->next; - if (procs->owner != scope) { - /* this is a reference, ignore it */ - free(procs); - goto skip_add; - } - if (scope_add_existing_proc(scope, procs)) { - return -1; - } - -skip_add: - procs = next; - } while (procs); - - /* repeat for all child scopes */ - struct scope *child = scope->children; - while (child) { - if (analyze_procs(child)) - return -1; - - child = child->next; - } - - return 0; -} - int analyze_root(struct scope *scope, struct ast_node *tree) { scope_add_defaults(scope); if (analyze(scope, tree)) return -1; - if (analyze_procs(scope)) - return -1; - return 0; } @@ -683,14 +625,14 @@ static int replace_id(struct ast_node *body, struct ast_node *id, return ast_call_on(_replace_id, body, pair); } -static int actualize_macro(struct act_state *state, - struct scope *scope, struct ast_node *macro) +static int actualize_macro_construct(struct act_state *state, + struct scope *scope, struct ast_node *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(macro && macro->node_type == AST_MACRO); - return scope_add_macro(scope, macro); + assert(n && n->node_type == AST_MACRO_CONSTRUCT); + return scope_add_macro(scope, n); } struct ast_node *extract_typeof(struct ast_node *type) @@ -833,7 +775,7 @@ static int actualize_macro_call(struct act_state *state, struct scope *scope, struct ast_node *call, struct ast_node *macro) { - assert(call->node_type == AST_CALL && macro->node_type == AST_MACRO); + assert(call->node_type == AST_CALL && macro->node_type == AST_MACRO_EXPAND); if (ast_flags(macro, AST_FLAG_VARIADIC)) { semantic_error(scope->fctx, macro, "variadic macros not yet implemented"); @@ -929,7 +871,7 @@ get_callable: if (callable->node_type == AST_PROC) return actualize_proc_call(state, scope, call, callable); - if (callable->node_type == AST_MACRO) + if (callable->node_type == AST_MACRO_EXPAND) return actualize_macro_call(state, scope, call, callable); /* TODO: add lambdas and arrays */ @@ -1050,8 +992,8 @@ static int actualize_binop(struct act_state *state, { assert(binop && binop->node_type == AST_BINOP); - struct ast_node *left = binop->_binop.left; - struct ast_node *right = binop->_binop.right; + struct ast_node *left = binop->binop.left; + struct ast_node *right = binop->binop.right; int ret = 0; ret |= actualize(state, scope, left); @@ -1253,7 +1195,7 @@ static int actualize_type(struct act_state *state, struct ast_node *id = type->_type.id; if (!id) /* no ID means void */ - type->_type.id = gen_id(strdup("void")); + type->_type.id = gen_id(strdup("void"), NULL_LOC()); type->loc = id->loc; @@ -1263,11 +1205,6 @@ static int actualize_type(struct act_state *state, EXIT_ACT(-1); } - /* this could be more clear, maybe add into the parser some kind - * of meta class for traitd types? */ - if (exists->node_type == AST_UNION) - type->_type.kind = AST_TYPE_UNION; - /* nothing to do, except maybe check that types are actually * identical? */ if (exists->node_type == AST_TYPE) @@ -1276,8 +1213,7 @@ static int actualize_type(struct act_state *state, assert(exists->node_type == AST_ALIAS || exists->node_type == AST_TRAIT || exists->node_type == AST_STRUCT - || exists->node_type == AST_ENUM - || exists->node_type == AST_UNION); + || exists->node_type == AST_ENUM); /* actualize whatever type we have on demand, either alias or * trait */ if (!ast_flags(exists, AST_FLAG_ACTUAL)) @@ -1311,11 +1247,6 @@ static int actualize_type(struct act_state *state, type->_type.enu.id = clone_ast_node(exists->_enum.id); type->_type.enu.type = exists->_enum.type; } - else if (exists->node_type == AST_UNION) { - type->_type.kind = AST_TYPE_UNION; - type->_type.unio.id = clone_ast_node(exists->_union.id); - type->_type.unio.impls = NULL; - } if (ast_flags(exists, AST_FLAG_GENERIC)) ast_set_flags(type, AST_FLAG_GENERIC); @@ -1364,60 +1295,11 @@ static int actualize_type(struct act_state *state, break; } - case AST_TYPE_UNION: case AST_TYPE_STRUCT: { assert(ast_flags(type, AST_FLAG_ACTUAL)); break; } - case AST_TYPE_GENERIC: { - struct ast_node *id = type->_type.generic.id; - struct ast_node *exists = file_scope_resolve_type(scope, id); - if (!exists) { - semantic_error(scope->fctx, type, "no such type"); - EXIT_ACT(-1); - } - - if (exists->node_type != AST_UNION && - exists->node_type != AST_STRUCT) { - semantic_error(scope->fctx, type, - "type not struct or union"); - EXIT_ACT(-1); - } - - if (!ast_flags(exists, AST_FLAG_ACTUAL)) - if (actualize(state, exists->scope, exists)) - EXIT_ACT(-1); - - struct ast_node *types = type->_type.generic.args; - if (actualize(state, scope, types)) - EXIT_ACT(-1); - - while (types) { - if (!primitive_type(types)) { - semantic_error(scope->fctx, types, - "only primitive types allowed in trait initialization"); - EXIT_ACT(-1); - } - - if (act_flags(state, ACT_REQUIRE_FULLY_QUALIFIED)) { - if (!fully_qualified(types)) { - semantic_error(scope->fctx, types, - "context requires fully qualified types"); - EXIT_ACT(-1); - } - } - types = types->next; - } - - if (exists->node_type == AST_UNION) - type->_type.kind = AST_TYPE_UNION; - else - type->_type.kind = AST_TYPE_STRUCT; - - break; - } - default: semantic_error(scope->fctx, type, "unimplemented type"); EXIT_ACT(-1); @@ -1434,7 +1316,7 @@ static int actualize_empty(struct act_state *state, 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")); + 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; @@ -1578,16 +1460,6 @@ static struct ast_node *lookup_struct_member(struct ast_node *struc, return lookup_member_idx(struc->_struct.body, find, idx); } -static struct ast_node *lookup_union_member(struct ast_node *unio, - struct ast_node *find) -{ - if (find) - return lookup_member_name(unio->_union.body, find, NULL); - - size_t idx = 0; - return lookup_member_idx(unio->_union.body, find, &idx); -} - static struct ast_node *lookup_enum_member(struct ast_node *enu, struct ast_node *find) { @@ -1604,50 +1476,6 @@ static struct ast_node *lookup_enum_member(struct ast_node *enu, return m; } -static int init_union(struct act_state *state, struct scope *scope, - struct ast_node *exists, struct ast_node *init) -{ - struct ast_node *arg = init->_init.body; - if (arg->next) { - semantic_error(scope->fctx, arg->next, - "multiple arguments in union initialization not allowed"); - return -1; - } - - if (actualize(state, scope, arg)) - return -1; - - struct ast_node *member = NULL; - if (ast_flags(arg, AST_FLAG_MEMBER)) { - member = lookup_union_member(exists, arg->_var.id); - } - else { - /* pick first element in body */ - member = exists->_union.body; - } - - if (!member) { - char *sstr = type_str(exists->type); - semantic_error(scope->fctx, arg, - "no such member in %s", - sstr); - free(sstr); - return -1; - } - - if (!implements(0, scope, arg->type, member->type)) { - char *mstr = type_str(member->type); - char *astr = type_str(arg->type); - semantic_error(scope->fctx, arg, "%s does not implement %s", - astr, mstr); - free(mstr); - free(astr); - return -1; - } - - return 0; -} - static int init_struct(struct act_state *state, struct scope *scope, struct ast_node *exists, struct ast_node *init) { @@ -1757,19 +1585,6 @@ static int actualize_struct_init_cast(struct act_state *state, return init_struct(state, scope, exists, init); } -static int actualize_union_init_cast(struct act_state *state, - struct scope *scope, - struct ast_node *init, - struct ast_node *actual) -{ - struct ast_node *id = actual->_type.unio.id; - struct ast_node *exists = file_scope_resolve_type(scope, id); - assert(exists); - assert(ast_flags(exists, AST_FLAG_ACTUAL)); - - return init_union(state, scope, exists, init); -} - static int actualize_init_cast(struct act_state *state, struct scope *scope, struct ast_node *init, struct ast_node *type) @@ -1777,11 +1592,9 @@ static int actualize_init_cast(struct act_state *state, struct ast_node *actual = actual_type(type); if (actual->_type.kind == AST_TYPE_STRUCT) return actualize_struct_init_cast(state, scope, init, actual); - if (actual->_type.kind == AST_TYPE_UNION) - return actualize_union_init_cast(state, scope, init, actual); semantic_error(scope->fctx, type, - "type is not a struct or union"); + "type is not a struct"); return -1; } @@ -1881,7 +1694,7 @@ static int actualize_const(struct act_state *state, struct scope *scope, assert(cons->node_type == AST_CONST); if (cons->_const.kind == AST_CONST_INTEGER) { /* error checking would be doog */ - cons->type = gen_type(AST_TYPE_ID, gen_id(strdup("i64")), + cons->type = gen_type(AST_TYPE_ID, gen_id(strdup("i64"), NULL_LOC()), NULL, NULL); scope_add_scratch(scope, cons->type); return 0; @@ -2204,36 +2017,6 @@ static int actualize_struct(struct act_state *state, return 0; } -static int actualize_union(struct act_state *state, - struct scope *scope, struct ast_node *node) -{ - assert(node->node_type == AST_UNION); - ast_set_flags(node, AST_FLAG_INIT); - struct ast_node *generics = node->_union.generics; - struct scope *union_scope = create_scope(); - if (!union_scope) - return -1; - - scope_add_scope(node->scope, union_scope); - if (generics) - ast_set_flags(node, AST_FLAG_GENERIC); - - if (actualize(state, union_scope, generics)) - return -1; - - struct ast_node *body = node->_union.body; - if (actualize(state, union_scope, body)) - return -1; - - /* cloning slightly odd, but I guess it's fine? */ - struct ast_node *clone_id = clone_ast_node(node->_union.id); - node->type = gen_type(AST_TYPE_UNION, clone_id, NULL, NULL); - scope_add_scratch(scope, node->type); - - ast_set_flags(node, AST_FLAG_ACTUAL); - return 0; -} - /* 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. */ @@ -2429,7 +2212,7 @@ 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: ret |= actualize_macro(state, scope, node); break; + case AST_MACRO_CONSTRUCT: ret |= actualize_macro_construct(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; @@ -2446,7 +2229,6 @@ static int actualize(struct act_state *state, struct scope *scope, 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_UNION: ret |= actualize_union(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; @@ -34,69 +34,104 @@ } while ((prev = cur)); \ } -static struct src_loc loc_span(struct ast_node *left, struct ast_node *right) +struct ast_node *gen_arr_access(struct ast_node *base, struct ast_node *idx, struct src_loc loc) { - struct src_loc loc = {0}; - if (!left && !right) - return loc; + ALLOC_NODE(n, "arr_access"); + n->node_type = AST_ARR_ACCESS; + n->arr_access.base = base; + n->arr_access.idx = idx; + n->loc = loc; + return n; +} + +void destroy_arr_access(struct ast_node *arr_access) +{ + assert(arr_access->node_type == AST_ARR_ACCESS); + destroy_ast_node(AST_GET(arr_access, base)); + destroy_ast_node(AST_GET(arr_access, idx)); + free(arr_access); +} - if (!left && right) - return right->loc; +struct ast_node *gen_macro_expand(struct ast_node *id, struct ast_node *args) +{ + ALLOC_NODE(n, "macro_expand"); + n->node_type = AST_MACRO_EXPAND; + n->_macro_expand.id = id; + n->_macro_expand.args = args; + n->loc = id->loc; + return n; +} - if (left && !right) - return left->loc; +void destroy_macro_expand(struct ast_node *n) +{ + assert(n->node_type == AST_MACRO_EXPAND); + destroy_ast_node(n->_macro_expand.id); + destroy_ast_node(n->_macro_expand.args); + free(n); +} - /* this might eventually be a good thing to do, - * but right now I'm still having issues with initializing all nodes - * with some kind of even slightly accurate location - assert(left->loc.first_line); - assert(left->loc.first_col); - assert(right->loc.last_line); - assert(right->loc.last_col); - */ +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; + n->type_construct.id = id; + n->type_construct.params = params; + n->type_construct.body = body; + n->loc = loc; + return n; +} - loc.first_line = left->loc.first_line; - loc.first_col = left->loc.first_col; - loc.last_line = right->loc.last_line; - loc.last_col = right->loc.last_col; - return loc; +void destroy_type_construct(struct ast_node *type_construct) +{ + destroy_ast_node(AST_GET(type_construct, id)); + destroy_ast_node(AST_GET(type_construct, params)); + destroy_ast_node(AST_GET(type_construct, body)); + free(type_construct); } -struct ast_node *gen_macro_expansion(struct ast_node *id, struct ast_node *args) +struct ast_node *gen_type_expand(struct ast_node *id, + struct ast_node *args, + struct src_loc loc) { - ALLOC_NODE(n, "macro_expansion"); - n->node_type = AST_MACRO_EXPANSION; - n->_macro_expansion.id = id; - n->_macro_expansion.args = args; - n->loc = id->loc; + ALLOC_NODE(n, "type_expand"); + n->node_type = AST_TYPE_EXPAND; + n->type_expand.id = id; + n->type_expand.args = args; + n->loc = loc; return n; } -void destroy_macro_expansion(struct ast_node *macro_expansion) +void destroy_type_expand(struct ast_node *n) { - assert(macro_expansion->node_type == AST_MACRO_EXPANSION); - destroy_ast_node(macro_expansion->_macro_expansion.id); - destroy_ast_node(macro_expansion->_macro_expansion.args); - free(macro_expansion); + assert(n->node_type == AST_TYPE_EXPAND); + destroy_ast_node(n->type_expand.args); + free((void *)n->type_expand.id); + free(n); } + struct ast_node *gen_binop(enum ast_binops op, - struct ast_node *left, struct ast_node *right) + struct ast_node *left, + struct ast_node *right, + struct src_loc loc) { ALLOC_NODE(n, "binop"); n->node_type = AST_BINOP; - n->_binop.op = op; - n->_binop.left = left; - n->_binop.right = right; - n->loc = loc_span(left, right); + n->binop.op = op; + n->binop.left = left; + n->binop.right = right; + n->loc = loc; return n; } void destroy_binop(struct ast_node *binop) { assert(binop->node_type == AST_BINOP); - destroy_ast_node(binop->_binop.left); - destroy_ast_node(binop->_binop.right); + destroy_ast_node(binop->binop.left); + destroy_ast_node(binop->binop.right); free(binop); } @@ -135,12 +170,12 @@ void destroy_call(struct ast_node *call) free(call); } -struct ast_node *gen_id(const char *id) +struct ast_node *gen_id(const char *id, struct src_loc loc) { ALLOC_NODE(n, "id"); n->node_type = AST_ID; n->_id.id = id; - /* assume the parser populates location data */ + n->loc = loc; return n; } @@ -157,7 +192,6 @@ struct ast_node *gen_assign(struct ast_node *to, struct ast_node *from) n->node_type = AST_ASSIGN; n->_assign.to = to; n->_assign.from = from; - n->loc = loc_span(to, from); return n; } @@ -359,11 +393,12 @@ static void destroy_fetch(struct ast_node *fetch) free(fetch); } -struct ast_node *gen_macro(struct ast_node *id, struct ast_node *params, +struct ast_node *gen_macro_construct(struct ast_node *id, + struct ast_node *params, struct ast_node *body) { - ALLOC_NODE(n, "body"); - n->node_type = AST_MACRO; + ALLOC_NODE(n, "macro_construct"); + n->node_type = AST_MACRO_CONSTRUCT; n->_macro.id = id; n->_macro.params = params; n->_macro.body = body; @@ -371,9 +406,9 @@ struct ast_node *gen_macro(struct ast_node *id, struct ast_node *params, return n; } -void destroy_macro(struct ast_node *macro) +void destroy_macro_construct(struct ast_node *macro) { - assert(macro->node_type == AST_MACRO); + assert(macro->node_type == AST_MACRO_CONSTRUCT); destroy_ast_node(macro->_macro.id); DESTROY_LIST(macro->_macro.params); DESTROY_LIST(macro->_macro.body); @@ -388,7 +423,6 @@ struct ast_node *gen_if(struct ast_node *cond, struct ast_node *body, n->_if.cond = cond; n->_if.body = body; n->_if.els = els; - n->loc = loc_span(cond, els); return n; } @@ -494,16 +528,9 @@ struct ast_node *gen_type(enum ast_type_kind kind, struct ast_node *id, case AST_TYPE_PROC: n->_type.proc.params = expr; n->_type.proc.ret = ret; - n->loc = loc_span(expr, ret); break; case AST_TYPE_UNION: - n->_type.unio.id = id; - n->_type.unio.impls = expr; - n->loc = id->loc; - - break; - case AST_TYPE_STRUCT: n->_type.struc.id = id; n->_type.struc.impls = expr; @@ -519,7 +546,6 @@ struct ast_node *gen_type(enum ast_type_kind kind, struct ast_node *id, case AST_TYPE_SIGN: n->_type.sign.params = expr; n->_type.sign.ret = ret; - n->loc = loc_span(expr, ret); break; } @@ -566,16 +592,12 @@ void destroy_type(struct ast_node *type) destroy_ast_node(type->_type.proc.ret); break; + case AST_TYPE_UNION: case AST_TYPE_STRUCT: destroy_ast_node(type->_type.struc.id); DESTROY_LIST(type->_type.struc.impls); break; - case AST_TYPE_UNION: - destroy_ast_node(type->_type.unio.id); - DESTROY_LIST(type->_type.unio.impls); - break; - case AST_TYPE_ENUM: destroy_ast_node(type->_type.enu.id); destroy_ast_node(type->_type.enu.type); @@ -596,10 +618,6 @@ struct ast_node *gen_block(struct ast_node *body) ALLOC_NODE(n, "block"); n->node_type = AST_BLOCK; n->_block.body = body; - - struct ast_node *first = body; - struct ast_node *last = ast_last_node(body); - n->loc = loc_span(first, last); return n; } @@ -727,30 +745,6 @@ void destroy_struct(struct ast_node *struc) free(struc); } -struct ast_node *gen_union(struct ast_node *id, - struct ast_node *generics, struct ast_node *body) -{ - ALLOC_NODE(n, "union"); - n->node_type = AST_UNION; - n->_union.id = id; - n->_union.generics = generics; - n->_union.body = body; - if (id) - n->loc = id->loc; - else - n->loc = body->loc; - return n; -} - -void destroy_union(struct ast_node *unio) -{ - assert(unio->node_type == AST_UNION); - destroy_ast_node(unio->_union.id); - DESTROY_LIST(unio->_union.generics); - DESTROY_LIST(unio->_union.body); - free(unio); -} - struct ast_node *gen_enum(struct ast_node *id, struct ast_node *type, struct ast_node *body) { @@ -779,7 +773,6 @@ struct ast_node *gen_cast(struct ast_node *expr, struct ast_node *type) n->node_type = AST_CAST; n->_cast.expr = expr; n->_cast.type = type; - n->loc = loc_span(expr, type); return n; } @@ -898,20 +891,6 @@ void destroy_empty(struct ast_node *empty) free(empty); } -struct ast_node *gen_last() -{ - ALLOC_NODE(n, "last"); - n->node_type = AST_LAST; - /* TODO: location */ - return n; -} - -void destroy_last(struct ast_node *last) -{ - assert(last->node_type == AST_LAST); - free(last); -} - void destroy_ast_node(struct ast_node *node) { if (!node) @@ -920,8 +899,9 @@ void destroy_ast_node(struct ast_node *node) assert(node->node_type); switch (node->node_type) { + case AST_TYPE_EXPAND: destroy_type_expand(node); break; + case AST_TYPE_CONSTRUCT: destroy_type_construct(node); break; case AST_FETCH: destroy_fetch(node); break; - case AST_UNION: destroy_union(node); break; case AST_ASSIGN: destroy_assign(node); break; case AST_INIT: destroy_init(node); break; case AST_SIZEOF: destroy_sizeof(node); break; @@ -930,8 +910,8 @@ void destroy_ast_node(struct ast_node *node) case AST_UNOP: destroy_unop(node); break; case AST_CALL: destroy_call(node); break; case AST_CAST: destroy_cast(node); break; - case AST_MACRO: destroy_macro(node); break; - case AST_MACRO_EXPANSION: destroy_macro_expansion(node); break; + case AST_MACRO_CONSTRUCT: destroy_macro_construct(node); break; + case AST_MACRO_EXPAND: destroy_macro_expand(node); break; case AST_PROC: destroy_proc(node); break; case AST_GOTO: destroy_goto(node); break; case AST_LABEL: destroy_label(node); break; @@ -957,7 +937,7 @@ void destroy_ast_node(struct ast_node *node) case AST_ID: destroy_id(node); break; case AST_AS: destroy_as(node); break; case AST_EMPTY: destroy_empty(node); break; - case AST_LAST: destroy_last(node); break; + case AST_ARR_ACCESS: destroy_arr_access(node); break; } } @@ -994,10 +974,6 @@ static const char *binop_symbol(int op) case AST_MUL: return "*"; case AST_DIV: return "/"; case AST_REM: return "%"; - case AST_XOR: return "^"; - case AST_POW: return "^^"; - case AST_AND: return "&"; - case AST_OR: return "|"; case AST_LOR: return "||"; case AST_LAND: return "&&"; case AST_LSHIFT: return "<<"; @@ -1007,9 +983,6 @@ static const char *binop_symbol(int op) case AST_ASSIGN_MUL: return "*="; case AST_ASSIGN_DIV: return "/="; case AST_ASSIGN_REM: return "%="; - case AST_ASSIGN_AND: return "&="; - case AST_ASSIGN_OR: return "|="; - case AST_ASSIGN_XOR: return "^="; case AST_ASSIGN_LSHIFT: return "<<="; case AST_ASSIGN_RSHIFT: return ">>="; case AST_LT: return "<"; @@ -1029,8 +1002,7 @@ static const char *unop_symbol(int op) case AST_NEG: return "-"; case AST_LNOT: return "!"; case AST_REF: return "&"; - case AST_DEREF: return "'"; - case AST_NOT: return "~"; + case AST_DEREF: return "*"; } return "UNKNOWN"; @@ -1093,18 +1065,6 @@ static void __dump_ast(int depth, struct ast_node *node) dump(depth, "}\n"); break; - case AST_UNION: - dump(depth, "{UNION:"); - dump_flags(node); - putchar('\n'); - - dump_ast(depth + 1, node->_union.id); - dump_ast(depth + 1, node->_union.generics); - dump_ast(depth + 1, node->_union.body); - - dump(depth, "}\n"); - break; - case AST_ASSIGN: dump(depth, "{ASSIGN:"); dump_flags(node); @@ -1171,10 +1131,10 @@ static void __dump_ast(int depth, struct ast_node *node) case AST_BINOP: dump(depth, "{BINOP:"); dump_flags(node); - printf(" %s\n", binop_symbol(node->_binop.op)); + printf(" %s\n", binop_symbol(node->binop.op)); - dump_ast(depth + 1, node->_binop.left); - dump_ast(depth + 1, node->_binop.right); + dump_ast(depth + 1, node->binop.left); + dump_ast(depth + 1, node->binop.right); dump(depth, "}\n"); break; @@ -1221,8 +1181,8 @@ static void __dump_ast(int depth, struct ast_node *node) dump(depth, "}\n"); break; - case AST_MACRO: - dump(depth, "{MACRO:"); + case AST_MACRO_CONSTRUCT: + dump(depth, "{MACRO_CONSTRUCT:"); dump_flags(node); putchar('\n'); @@ -1233,13 +1193,13 @@ static void __dump_ast(int depth, struct ast_node *node) dump(depth, "}\n"); break; - case AST_MACRO_EXPANSION: - dump(depth, "{MACRO_EXPANSION:"); + case AST_MACRO_EXPAND: + dump(depth, "{MACRO_EXPAND:"); dump_flags(node); putchar('\n'); - dump_ast(depth + 1, node->_macro_expansion.id); - dump_ast(depth + 1, node->_macro_expansion.args); + dump_ast(depth + 1, node->_macro_expand.id); + dump_ast(depth + 1, node->_macro_expand.args); dump(depth, "}\n"); break; @@ -1361,6 +1321,8 @@ static void __dump_ast(int depth, struct ast_node *node) dump_ast(depth + 1, node->_type.proc.ret); break; + /* not really but y'know */ + case AST_TYPE_UNION: case AST_TYPE_STRUCT: printf(" STRUCT\n"); /* oh yeah, struc is at least right now just an ID that @@ -1375,12 +1337,6 @@ static void __dump_ast(int depth, struct ast_node *node) dump_ast(depth + 1, node->_type.enu.type); break; - case AST_TYPE_UNION: - printf(" UNION\n"); - dump_ast(depth + 1, node->_type.unio.id); - dump_ast(depth + 1, node->_type.unio.impls); - break; - case AST_TYPE_SIGN: printf(" SIGN\n"); dump_ast(depth + 1, node->_type.sign.params); dump_ast(depth + 1, node->_type.sign.ret); @@ -1392,12 +1348,6 @@ static void __dump_ast(int depth, struct ast_node *node) dump(depth, "}\n"); break; - case AST_LAST: - dump(depth, "{LAST:"); - dump_flags(node); - printf("}\n"); - break; - case AST_EMPTY: dump(depth, "{EMPTY:"); dump_flags(node); @@ -1553,6 +1503,9 @@ static void __dump_ast(int depth, struct ast_node *node) dump(depth, "}\n"); break; + + default: + dump(depth, "{UNIMP}\n"); } } @@ -1577,17 +1530,30 @@ struct ast_node *clone_ast_node(struct ast_node *node) assert(node->node_type); struct ast_node *new = NULL; switch (node->node_type) { + case AST_ARR_ACCESS: + new = gen_arr_access(clone_ast_node(node->arr_access.base), + clone_ast_node(node->arr_access.idx), + node->loc); + break; + + case AST_TYPE_CONSTRUCT: + new = gen_type_construct(clone_ast_node(node->type_construct.id), + clone_ast_node(node->type_construct.params), + clone_ast_node(node->type_construct.body), + node->loc); + break; + + case AST_TYPE_EXPAND: + new = gen_type_expand(clone_ast_node(node->type_expand.id), + clone_ast_node(node->type_expand.args), + node->loc); + break; + case AST_FETCH: new = gen_fetch(clone_ast_node(node->_fetch.id), clone_ast_node(node->_fetch.type)); break; - case AST_UNION: - new = gen_union(clone_ast_node(node->_union.id), - clone_ast_node(node->_union.generics), - clone_ast_node(node->_union.body)); - break; - case AST_ASSIGN: new = gen_assign(clone_ast_node(node->_assign.to), clone_ast_node(node->_assign.from)); @@ -1612,9 +1578,10 @@ struct ast_node *clone_ast_node(struct ast_node *node) case AST_LABEL: new = gen_label(clone_ast_node(node->_label.id)); break; - case AST_BINOP: new = gen_binop(node->_binop.op, - clone_ast_node(node->_binop.left), - clone_ast_node(node->_binop.right)); + case AST_BINOP: new = gen_binop(node->binop.op, + clone_ast_node(node->binop.left), + clone_ast_node(node->binop.right), + node->loc); break; case AST_UNOP: new = gen_unop(node->_unop.op, @@ -1628,13 +1595,14 @@ struct ast_node *clone_ast_node(struct ast_node *node) case AST_DEFER: new = gen_defer(clone_ast_node(node->_defer.expr)); break; - case AST_MACRO: new = gen_macro(clone_ast_node(node->_macro.id), + case AST_MACRO_CONSTRUCT: new = gen_macro_construct( + clone_ast_node(node->_macro.id), clone_ast_node(node->_macro.params), clone_ast_node(node->_macro.body)); break; - case AST_MACRO_EXPANSION: new = gen_macro_expansion(clone_ast_node(node->_macro_expansion.id), - clone_ast_node(node->_macro_expansion.args)); + case AST_MACRO_EXPAND: new = gen_macro_expand(clone_ast_node(node->_macro_expand.id), + clone_ast_node(node->_macro_expand.args)); break; case AST_CAST: new = gen_cast(clone_ast_node(node->_cast.expr), @@ -1712,6 +1680,7 @@ struct ast_node *clone_ast_node(struct ast_node *node) /* ditto, should actual be cloned? */ node->_type.trait.actual); break; + case AST_TYPE_ID: new = gen_type(AST_TYPE_ID, clone_ast_node(node->_type.id), @@ -1734,6 +1703,7 @@ struct ast_node *clone_ast_node(struct ast_node *node) new = gen_type(AST_TYPE_POINTER, NULL, NULL, NULL); break; + case AST_TYPE_UNION: case AST_TYPE_STRUCT: new = gen_type(AST_TYPE_STRUCT, clone_ast_node(node->_type.struc.id), @@ -1748,13 +1718,6 @@ struct ast_node *clone_ast_node(struct ast_node *node) NULL); break; - case AST_TYPE_UNION: - new = gen_type(AST_TYPE_UNION, - clone_ast_node(node->_type.unio.id), - clone_ast_node(node->_type.unio.impls), - NULL); - break; - case AST_TYPE_PROC: new = gen_type(AST_TYPE_PROC, NULL, clone_ast_node(node->_type.proc.params), @@ -1830,17 +1793,13 @@ struct ast_node *clone_ast_node(struct ast_node *node) break; case AST_ID: - new = gen_id(strdup(node->_id.id)); + new = gen_id(strdup(node->_id.id), node->loc); break; case AST_EMPTY: new = gen_empty(); break; - case AST_LAST: - new = gen_last(); - break; - case AST_ALIAS: new = gen_alias(clone_ast_node(node->_alias.id), clone_ast_node(node->_alias.type)); @@ -1893,20 +1852,6 @@ static int identical_scope(void *left, void *right) return left == right; } -static int identical_union(int exact, struct ast_node *a, struct ast_node *b) -{ - if (!identical_ast_nodes(exact, a->_union.id, b->_union.id)) - return 0; - - if (!identical_ast_nodes(exact, a->_union.generics, b->_union.generics)) - return 0; - - if (!identical_ast_nodes(exact, a->_union.body, b->_union.body)) - return 0; - - return 1; -} - static int identical_assign(int exact, struct ast_node *a, struct ast_node *b) { if (!identical_ast_nodes(exact, a->_assign.to, a->_assign.to)) @@ -1956,13 +1901,13 @@ static int identical_label(int exact, struct ast_node *a, struct ast_node *b) static int identical_binop(int exact, struct ast_node *a, struct ast_node *b) { - if (a->_binop.op != b->_binop.op) + if (a->binop.op != b->binop.op) return 0; - if (!identical_ast_nodes(exact, a->_binop.left, b->_binop.left)) + if (!identical_ast_nodes(exact, a->binop.left, b->binop.left)) return 0; - if (!identical_ast_nodes(exact, a->_binop.right, b->_binop.right)) + if (!identical_ast_nodes(exact, a->binop.right, b->binop.right)) return 0; return 1; @@ -2006,7 +1951,7 @@ 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(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, a->_macro.id, b->_macro.id)) return 0; @@ -2020,6 +1965,17 @@ static int identical_macro(int exact, struct ast_node *a, struct ast_node *b) return 1; } +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)) + return 0; + + if (!identical_ast_nodes(exact, a->_macro_expand.args, b->_macro_expand.args)) + return 0; + + return 1; +} + static int identical_proc(int exact, struct ast_node *a, struct ast_node *b) { if (!identical_ast_nodes(exact, a->_proc.id, b->_proc.id)) @@ -2170,19 +2126,6 @@ static int identical_type_struct(int exact, struct ast_node *a, return 1; } -static int identical_type_union(int exact, struct ast_node *a, - struct ast_node *b) -{ - if (!identical_ast_nodes(exact, a->_type.unio.id, b->_type.unio.id)) - return 0; - - if (!identical_ast_nodes(1, a->_type.unio.impls, - b->_type.unio.impls)) - return 0; - - return 1; -} - static int identical_type_enum(int exact, struct ast_node *a, struct ast_node *b) { @@ -2241,8 +2184,8 @@ static int identical_type(int exact, struct ast_node *a, struct ast_node *b) case AST_TYPE_TYPEOF: ret = identical_type_typeof(exact, a, b); break; case AST_TYPE_PROC: ret = identical_type_proc(exact, a, b); break; case AST_TYPE_SIGN: ret = identical_type_sign(exact, a, b); break; + case AST_TYPE_UNION: case AST_TYPE_STRUCT: ret = identical_type_struct(exact, a, b); break; - case AST_TYPE_UNION: ret = identical_type_union(exact, a, b); break; case AST_TYPE_POINTER: break; } @@ -2416,6 +2359,42 @@ 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, a->type_expand.id, b->type_expand.id)) + return 0; + + if (!identical_ast_nodes(exact, a->type_expand.args, b->type_expand.args)) + return 0; + + return 1; +} + +static int identical_type_construct(int exact, struct ast_node *a, struct ast_node *b) +{ + if (!identical_ast_nodes(exact, a->type_construct.id, b->type_construct.id)) + return 0; + + if (!identical_ast_nodes(exact, a->type_construct.params, b->type_construct.params)) + return 0; + + if (!identical_ast_nodes(exact, a->type_construct.body, b->type_construct.body)) + return 0; + + return 1; +} + +static int identical_arr_access(int exact, struct ast_node *a, struct ast_node *b) +{ + if (!identical_ast_nodes(exact, a->arr_access.base, b->arr_access.base)) + return 0; + + if (!identical_ast_nodes(exact, a->arr_access.idx, b->arr_access.idx)) + return 0; + + return 1; +} + /* sort of unfortnate that we can't just do a direct memcmp... */ int identical_ast_nodes(int exact, struct ast_node *a, struct ast_node *b) { @@ -2448,8 +2427,10 @@ 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_UNION: ret = identical_union(exact, a, b); break; case AST_ASSIGN: ret = identical_assign(exact, a, b); break; case AST_INIT: ret = identical_init(exact, a, b); break; case AST_SIZEOF: ret = identical_sizeof(exact, a, b); break; @@ -2462,8 +2443,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: ret = identical_macro(exact, a, b); break; - case AST_MACRO_EXPANSION: ret = identical_macro(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; case AST_FOR: ret = identical_for(exact, a, b); break; @@ -2485,7 +2466,6 @@ int identical_ast_nodes(int exact, struct ast_node *a, struct ast_node *b) case AST_TRAIT: ret = identical_trait(exact, a, b); break; case AST_IF: ret = identical_if(exact, a, b); break; case AST_EMPTY: break; - case AST_LAST: break; } if (ret == 0) @@ -2506,16 +2486,6 @@ int ast_flags(struct ast_node *node, enum ast_flag flags) return node->flags & flags; } -static int call_on_union(int (*call)(struct ast_node *, - void *), struct ast_node *node, void *data) -{ - int ret = 0; - ret |= call(node->_union.id, data); - ret |= call(node->_union.generics, data); - ret |= call(node->_union.body, data); - return ret; -} - static int call_on_assign(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) { @@ -2714,15 +2684,6 @@ static int call_on_type_typeof(int (*call)(struct ast_node *, return call(node->_type.typeo.expr, data); } -static int call_on_type_union(int (*call)(struct ast_node *, - void *), struct ast_node *node, void *data) -{ - int ret = 0; - ret |= call(node->_type.unio.id, data); - ret |= call(node->_type.unio.impls, data); - return ret; -} - static int call_on_type_struct(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) { @@ -2795,7 +2756,7 @@ static int call_on_type(int (*call)(struct ast_node *, 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_UNION: ret = call_on_type_union(call, node, data); break; + case AST_TYPE_UNION: case AST_TYPE_STRUCT: ret = call_on_type_struct(call, node, data); break; case AST_TYPE_PROC: ret = call_on_type_proc(call, node, data); break; @@ -2823,8 +2784,8 @@ static int call_on_binop(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) { int ret = 0; - ret |= call(node->_binop.left, data); - ret |= call(node->_binop.right, data); + ret |= call(node->binop.left, data); + ret |= call(node->binop.right, data); return ret; } @@ -2843,7 +2804,7 @@ static int call_on_call(int (*call)(struct ast_node *, return ret; } -static int call_on_macro(int (*call)(struct ast_node *, +static int call_on_macro_construct(int (*call)(struct ast_node *, void *), struct ast_node *node, void *data) { int ret = 0; @@ -2878,11 +2839,28 @@ static int call_on_fetch(int (*call)(struct ast_node *, return ret; } -static int call_on_macro_expansion(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); + ret |= call(node->_macro_expand.args, data); + return ret; +} + +static int call_on_type_construct(int (*call)(struct ast_node *, void *), struct ast_node *type_construct, void *data) +{ + int ret = 0; + ret |= call(AST_GET(type_construct, id), data); + ret |= call(AST_GET(type_construct, params), data); + ret |= call(AST_GET(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) { int ret = 0; - ret |= call(node->_macro_expansion.id, data); - ret |= call(node->_macro_expansion.args, data); + ret |= call(AST_GET(type_expand, id), data); + ret |= call(AST_GET(type_expand, args), data); return ret; } @@ -2901,8 +2879,10 @@ int ast_call_on(int (*call)(struct ast_node *, return ret; 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_FETCH: ret = call_on_fetch(call, node, data); break; - case AST_UNION: ret = call_on_union(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; case AST_SIZEOF: ret = call_on_sizeof(call, node, data); break; @@ -2928,11 +2908,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: ret = call_on_macro(call, node, data); break; - case AST_MACRO_EXPANSION: ret = call_on_macro_expansion(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_LAST: break; case AST_EMBED: break; case AST_CTRL: break; case AST_IMPORT: break; diff --git a/src/debug.c b/src/debug.c index ee410be..2b993bf 100644 --- a/src/debug.c +++ b/src/debug.c @@ -169,6 +169,16 @@ void internal_error(const char *fmt, ...) va_end(args); } +void internal_warn(const char *fmt, ...) +{ + va_list args; + va_start(args, fmt); + fprintf(stderr, "internal warning: "); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); +} + /** * Workhorse for type_str(). * diff --git a/src/lexer.l b/src/lexer.l index 50e7c1e..bcfa5be 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -211,7 +211,7 @@ STRING \"(\\.|[^"\\])*\" . { struct src_issue issue; issue.level = SRC_ERROR; - issue.loc = to_src_loc(yylloc); + issue.loc = src_loc(*yylloc); issue.fctx.fbuf = parser->buf; issue.fctx.fname = parser->fname; src_issue(issue, "Unexpected token: %s", yytext); diff --git a/src/parser.y b/src/parser.y index 8f5886c..236a106 100644 --- a/src/parser.y +++ b/src/parser.y @@ -142,7 +142,9 @@ /* constant operations */ %nterm <node> const_expr const_unop const_binop -%nterm <node> macro_expand +%nterm <node> macro_expand type_expand + +%nterm <node> type_construct type_params type_param /* array stuff */ %nterm <node> arr arr_inits arr_init @@ -189,7 +191,7 @@ static int next_interesting_feature(YYSTYPE *yylval, YYLTYPE *yylloc, * @param yylloc Bison location info. * @return Internal location info. */ -static struct src_loc to_src_loc(YYLTYPE *yylloc); +static struct src_loc src_loc(YYLTYPE yylloc); /** * Print parsing error. @@ -227,15 +229,11 @@ static const char *clone_string(const char *s); %start input; %% id - : ID { - $$ = gen_id(strdup($1)); - $$->loc = to_src_loc(&yylloc); - } + : ID {$$ = gen_id(strdup($1), src_loc(@$));} apply : APPLY { - $$ = gen_id(strdup($1)); - $$->loc = to_src_loc(&yylloc); + $$ = gen_id(strdup($1), src_loc(@$)); } var @@ -252,37 +250,36 @@ assign : expr "=" expr { $$ = gen_assign($1, $3); } binop - : expr "+" expr { $$ = gen_binop(AST_ADD, $1, $3); } - | expr "-" expr { $$ = gen_binop(AST_SUB, $1, $3); } - | expr "*" expr { $$ = gen_binop(AST_MUL, $1, $3); } - | expr "/" expr { $$ = gen_binop(AST_DIV, $1, $3); } - | expr "%" expr { $$ = gen_binop(AST_REM, $1, $3); } - | expr "<<" expr { $$ = gen_binop(AST_LSHIFT, $1, $3); } - | expr ">>" expr { $$ = gen_binop(AST_RSHIFT, $1, $3); } - | expr "+=" expr { $$ = gen_binop(AST_ASSIGN_ADD, $1, $3); } - | expr "-=" expr { $$ = gen_binop(AST_ASSIGN_SUB, $1, $3); } - | expr "*=" expr { $$ = gen_binop(AST_ASSIGN_MUL, $1, $3); } - | expr "/=" expr { $$ = gen_binop(AST_ASSIGN_DIV, $1, $3); } - | expr "%=" expr { $$ = gen_binop(AST_ASSIGN_REM, $1, $3); } + : expr "+" expr { $$ = gen_binop(AST_ADD, $1, $3, src_loc(@$)); } + | expr "-" expr { $$ = gen_binop(AST_SUB, $1, $3, src_loc(@$)); } + | expr "*" expr { $$ = gen_binop(AST_MUL, $1, $3, src_loc(@$)); } + | expr "/" expr { $$ = gen_binop(AST_DIV, $1, $3, src_loc(@$)); } + | expr "%" expr { $$ = gen_binop(AST_REM, $1, $3, src_loc(@$)); } + | expr "<<" expr { $$ = gen_binop(AST_LSHIFT, $1, $3, src_loc(@$)); } + | expr ">>" expr { $$ = gen_binop(AST_RSHIFT, $1, $3, src_loc(@$)); } + | expr "+=" expr { $$ = gen_binop(AST_ASSIGN_ADD, $1, $3, src_loc(@$)); } + | expr "-=" expr { $$ = gen_binop(AST_ASSIGN_SUB, $1, $3, src_loc(@$)); } + | expr "*=" expr { $$ = gen_binop(AST_ASSIGN_MUL, $1, $3, src_loc(@$)); } + | expr "/=" expr { $$ = gen_binop(AST_ASSIGN_DIV, $1, $3, src_loc(@$)); } + | expr "%=" expr { $$ = gen_binop(AST_ASSIGN_REM, $1, $3, src_loc(@$)); } | expr "<<=" expr { - $$ = gen_binop(AST_ASSIGN_LSHIFT, $1, $3); + $$ = gen_binop(AST_ASSIGN_LSHIFT, $1, $3, src_loc(@$)); } | expr ">>=" expr { - $$ = gen_binop(AST_ASSIGN_RSHIFT, $1, $3); + $$ = gen_binop(AST_ASSIGN_RSHIFT, $1, $3, src_loc(@$)); } - | expr "<" expr { $$ = gen_binop(AST_LT, $1, $3); } - | expr ">" expr { $$ = gen_binop(AST_GT, $1, $3); } - | expr "<=" expr { $$ = gen_binop(AST_LE, $1, $3); } - | expr ">=" expr { $$ = gen_binop(AST_GE, $1, $3); } - | expr "!=" expr { $$ = gen_binop(AST_NE, $1, $3); } - | expr "==" expr { $$ = gen_binop(AST_EQ, $1, $3); } + | expr "<" expr { $$ = gen_binop(AST_LT, $1, $3, src_loc(@$)); } + | expr ">" expr { $$ = gen_binop(AST_GT, $1, $3, src_loc(@$)); } + | expr "<=" expr { $$ = gen_binop(AST_LE, $1, $3, src_loc(@$)); } + | expr ">=" expr { $$ = gen_binop(AST_GE, $1, $3, src_loc(@$)); } + | expr "!=" expr { $$ = gen_binop(AST_NE, $1, $3, src_loc(@$)); } + | expr "==" expr { $$ = gen_binop(AST_EQ, $1, $3, src_loc(@$)); } unop : "-" expr { $$ = gen_unop(AST_NEG, $2); } | "!" expr { $$ = gen_unop(AST_LNOT, $2); } | "&" expr { $$ = gen_unop(AST_REF, $2); } | "*" expr { $$ = gen_unop(AST_DEREF, $2); } - | "~" expr { $$ = gen_unop(AST_NOT, $2); } arr_init : "=>" const_expr "..." const_expr "=" arg { $$ = gen_var($2, $4, $6); } @@ -320,24 +317,49 @@ defer : "defer" body { $$ = gen_defer($2); } const_binop - : const_expr "+" const_expr { $$ = gen_binop(AST_ADD, $1, $3); } - | const_expr "-" const_expr { $$ = gen_binop(AST_SUB, $1, $3); } - | const_expr "*" const_expr { $$ = gen_binop(AST_MUL, $1, $3); } - | const_expr "/" const_expr { $$ = gen_binop(AST_DIV, $1, $3); } - | const_expr "%" const_expr { $$ = gen_binop(AST_REM, $1, $3); } - | const_expr "<<" const_expr { $$ = gen_binop(AST_LSHIFT, $1, $3); } - | const_expr ">>" const_expr { $$ = gen_binop(AST_RSHIFT, $1, $3); } - | const_expr "<" const_expr { $$ = gen_binop(AST_LT, $1, $3); } - | const_expr ">" const_expr { $$ = gen_binop(AST_GT, $1, $3); } - | const_expr "<=" const_expr { $$ = gen_binop(AST_LE, $1, $3); } - | const_expr ">=" const_expr { $$ = gen_binop(AST_GE, $1, $3); } - | const_expr "!=" const_expr { $$ = gen_binop(AST_NE, $1, $3); } - | const_expr "==" const_expr { $$ = gen_binop(AST_EQ, $1, $3); } + : const_expr "+" const_expr { + $$ = gen_binop(AST_ADD, $1, $3, src_loc(@$)); + } + | const_expr "-" const_expr { + $$ = gen_binop(AST_SUB, $1, $3, src_loc(@$)); + } + | const_expr "*" const_expr { + $$ = gen_binop(AST_MUL, $1, $3, src_loc(@$)); + } + | const_expr "/" const_expr { + $$ = gen_binop(AST_DIV, $1, $3, src_loc(@$)); + } + | const_expr "%" const_expr { + $$ = gen_binop(AST_REM, $1, $3, src_loc(@$)); + } + | const_expr "<<" const_expr { + $$ = gen_binop(AST_LSHIFT, $1, $3, src_loc(@$)); + } + | const_expr ">>" const_expr { + $$ = gen_binop(AST_RSHIFT, $1, $3, src_loc(@$)); + } + | const_expr "<" const_expr { + $$ = gen_binop(AST_LT, $1, $3, src_loc(@$)); + } + | const_expr ">" const_expr { + $$ = gen_binop(AST_GT, $1, $3, src_loc(@$)); + } + | const_expr "<=" const_expr { + $$ = gen_binop(AST_LE, $1, $3, src_loc(@$)); + } + | const_expr ">=" const_expr { + $$ = gen_binop(AST_GE, $1, $3, src_loc(@$)); + } + | const_expr "!=" const_expr { + $$ = gen_binop(AST_NE, $1, $3, src_loc(@$)); + } + | const_expr "==" const_expr { + $$ = gen_binop(AST_EQ, $1, $3, src_loc(@$)); + } const_unop : "-" const_expr { $$ = gen_unop(AST_NEG, $2); } | "!" const_expr { $$ = gen_unop(AST_LNOT, $2); } - | "~" const_expr { $$ = gen_unop(AST_NOT, $2); } const_expr : "(" const_expr ")" { $$ = $2; } @@ -351,16 +373,16 @@ const_expr expr : expr "." id { $$ = gen_dot($1, $3); } | "..." id { $$ = $2; } - | INT { $$ = gen_int($1); $$->loc = to_src_loc(&yylloc); } - | FLOAT { $$ = gen_float($1); $$->loc = to_src_loc(&yylloc); } + | INT { $$ = gen_int($1); $$->loc = src_loc(@$); } + | FLOAT { $$ = gen_float($1); $$->loc = src_loc(@$); } | STRING { $$ = gen_string(clone_string($1)); - $$->loc = to_src_loc(&yylloc); + $$->loc = src_loc(@$); } | "(" expr ")" { $$ = $2; } | expr "(" args ")" { $$ = gen_call($1, $3); } | expr "(" ")" { $$ = gen_call($1, NULL); } - | expr "[" expr "]" { $$ = gen_call($1, $3); /** @todo add arr access */} + | expr "[" expr "]" { $$ = gen_arr_access($1, $3, src_loc(@$)); /** @todo add arr access */} | "(" var_init ")" { $$ = $2; } | "sizeof" expr { $$ = gen_sizeof($2); } | expr "as" type { $$ = gen_cast($1, $3); } @@ -389,8 +411,8 @@ goto statelet : "return" args { $$ = gen_return($2); } | "return" { $$ = gen_return(NULL); } - | "break" { $$ = gen_ctrl(AST_CTRL_BREAK, to_src_loc(&yylloc)); } - | "continue" { $$ = gen_ctrl(AST_CTRL_CONTINUE, to_src_loc(&yylloc)); } + | "break" { $$ = gen_ctrl(AST_CTRL_BREAK, src_loc(yylloc)); } + | "continue" { $$ = gen_ctrl(AST_CTRL_CONTINUE, src_loc(yylloc)); } | trait | import | alias @@ -443,21 +465,20 @@ references | "..." id { $$ = $2; ast_set_flags($$, AST_FLAG_VARIADIC); } | id -/* TODO: rethink how macros play into everyting */ macro : "define" id "(" references ")" body { - $$ = gen_macro($2, $4, $6); + $$ = gen_macro_construct($2, $4, $6); ast_set_flags($6, AST_FLAG_UNHYGIENIC); } | "define" id "(" references "..." id ")" body { /* TODO: the location data of the variadic ID is way off */ ast_append($4, $6); - $$ = gen_macro($2, $4, $8); + $$ = gen_macro_construct($2, $4, $8); ast_set_flags($$, AST_FLAG_VARIADIC); ast_set_flags($8, AST_FLAG_UNHYGIENIC); } | "define" id "(" ")" body { - $$ = gen_macro($2, NULL, $5); + $$ = gen_macro_construct($2, NULL, $5); ast_set_flags($5, AST_FLAG_UNHYGIENIC); } @@ -552,8 +573,6 @@ type $$ = gen_type(AST_TYPE_POINTER, NULL, NULL, NULL); $$->_type.next = $2; } - | anon_struct { $$ = $1; } - | anon_union { $$ = $1; } | "*" type { $$ = gen_type(AST_TYPE_POINTER, NULL, NULL, NULL); $$->_type.next = $2; @@ -574,6 +593,21 @@ type | "mut" type { $$ = $2; ast_set_flags($$, AST_FLAG_MUTABLE); } + | anon_struct + /* syntactic sugar for struct {union {...} } */ + | anon_union + /* syntactic sugar for anon_struct */ + | type_expand + +types + : type "," types + | type + +/* vec![int] is effectively struct {vec![int]} */ +type_expand + : apply "[" types "]" + /* legal, but weird */ + | apply "[" "]" var_decl : type id { $$ = gen_var($2, $1, NULL); } @@ -599,25 +633,25 @@ proc struct_elem : var_decl - | macro_expand + | type_expand ; members : struct_elem ";" members { $$ = $1; $1->next = $3; } - | struct_elem ";" { $$ = $1; } + | struct_elem ";" tagged_union : "union" id "{" members "}" { - $$ = gen_union($2, NULL, $4); + /* essentially struct {union{members}} */ + $$ = gen_struct($2, NULL, $4); } anon_union - : "union" "{" members "}" { $$ = gen_union(NULL, NULL, $3); } - | "union" macro_expand { $$ = gen_union(NULL, NULL, $2); } + : "union" "{" members "}" { $$ = gen_struct(NULL, NULL, $3); } macro_expand - : apply "(" ")" { $$ = gen_macro_expansion($1, NULL); } - | apply "(" args ")" { $$ = gen_macro_expansion($1, $3); } + : apply "(" ")" { $$ = gen_macro_expand($1, NULL); } + | apply "(" args ")" { $$ = gen_macro_expand($1, $3); } tagged_struct : "struct" id "{" members "}" { @@ -626,13 +660,12 @@ tagged_struct anon_struct : "struct" "{" members "}" { $$ = gen_struct(NULL, NULL, $3); } - | "struct" macro_expand { $$ = gen_struct(NULL, NULL, $2); } trait_elem - : id - | id func_sign { $$ = gen_proc($1, $2, NULL); } - | var_decl - | macro_expand + : id /* trait */ + | id func_sign { $$ = gen_proc($1, $2, NULL); } /* proc */ + | var_decl /* member */ + | type_expand /* type construction */ trait_elems : trait_elem ";" trait_elems { $$ = $1; $1->next = $3; } @@ -653,6 +686,21 @@ trait $$ = gen_trait($2, NULL); } +type_param + : id id + +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(@$)); + } + enum_val : id { $$ = gen_val($1, NULL); } | id "=" expr { $$ = gen_val($1, $3); } @@ -686,10 +734,11 @@ top_if /* slightly silly to allow stray semicolons at a top level, but seems to help * with recovering from certain syntax errors */ top - : enum { $$ = $1; } - | proc { $$ = $1; } - | tagged_struct { $$ = $1; } - | tagged_union { $$ = $1; } + : enum + | proc + | tagged_struct + | tagged_union + | type_construct | macro { $$ = $1; } | top_if { $$ = $1; ast_set_flags($$, AST_FLAG_CONST); } | import { $$ = $1; } @@ -698,6 +747,7 @@ 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); } @@ -759,13 +809,13 @@ static int next_interesting_feature(YYSTYPE *yylval, YYLTYPE *yylloc, } -static struct src_loc to_src_loc(YYLTYPE *yylloc) +static struct src_loc src_loc(YYLTYPE yylloc) { struct src_loc loc; - loc.first_line = yylloc->first_line; - loc.last_line = yylloc->last_line; - loc.first_col = yylloc->first_column; - loc.last_col = yylloc->last_column; + loc.first_line = yylloc.first_line; + loc.last_line = yylloc.last_line; + loc.first_col = yylloc.first_column; + loc.last_col = yylloc.last_column; return loc; } @@ -776,7 +826,7 @@ static void yyerror(YYLTYPE *yylloc, void *lexer, struct src_issue issue; issue.level = SRC_ERROR; - issue.loc = to_src_loc(yylloc); + issue.loc = src_loc(*yylloc); issue.fctx.fbuf = parser->buf; issue.fctx.fname = parser->fname; src_issue(issue, msg); diff --git a/src/scope.c b/src/scope.c index 8d9ada3..d6481c3 100644 --- a/src/scope.c +++ b/src/scope.c @@ -17,6 +17,13 @@ #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 int generics_trait_type(struct ast_node *generics) { if (!generics) @@ -36,10 +43,6 @@ static int generic_type(struct ast_node *type) if (type->_type.kind == AST_TYPE_STRUCT) return generics_trait_type(type->_type.struc.impls); - if (type->_type.kind == AST_TYPE_UNION) { - return generics_trait_type(type->_type.unio.impls); - } - if (type->_type.kind == AST_TYPE_TRAIT) return type->_type.trait.actual == NULL; @@ -90,59 +93,19 @@ int fully_qualified(struct ast_node *type) return 0; } - if (type->_type.kind == AST_TYPE_UNION) { - if (!ast_flags(type, AST_FLAG_GENERIC)) - return 1; - - if (type->_type.unio.impls) - return fully_qualified(type->_type.unio.impls); - - return 0; - } - return fully_qualified(type->_type.next); } -static struct param_node *find_primitive(struct proc_node *node, +static struct param_node *find_matching_param(struct resolve_node *node, struct ast_node *type) { - struct param_node *param = node->primitives; + struct param_node *param = node->params; while (param) { - if (types_match(type, param->type)) + /* untyped matches everything, yay */ + if (!param->type) return param; - param = param->next; - } - - return NULL; -} - -static int compare_primitives(struct ast_node *a, struct ast_node *b); - -/* match also checks qualification status of the types, since we can - * differentiate between fully qualified types and not fully qualified types - * by placing qualified types towards the front of the primitive list. - * This is analoguous to the fallback thing in traits, but we want to be able to - * support multiple not fully qualified primitives, for example - * - * add(some_generic_struct) - * add(some_other_generic_struct) - * - * since they are easily distinguishable from eachother, in contract to traits. - * - * Therefore, use this when checking if a primitive should be added to the list, - * otherwise use find_primitive() to get which primitive matches. - * (are these names inverted from their intention? I'm not sure) - */ -static struct param_node *match_primitive(struct proc_node *node, - struct ast_node *type) -{ - struct param_node *param = node->primitives; - while (param) { - /* note very subtle change in that we pass param->type first - * here, but second in find_primitive. This could easily be - * confusing... */ - if (types_match(param->type, type)) + if (types_match(type, param->type)) return param; param = param->next; @@ -151,70 +114,7 @@ static struct param_node *match_primitive(struct proc_node *node, return NULL; } -static int match_generic(struct scope *scope, struct ast_node *a, - struct ast_node *b) -{ - return implements(0, scope, a, b); -} - -static int compare_impls(struct ast_node *a, struct ast_node *b) -{ - if (!a) - return 1; - - if (!b) - return 0; - - while (a && b) { - if (compare_primitives(a, b) == 0) - return 0; - - a = a->next; - b = b->next; - } - - return 1; -} - -/* return 1 if a should come after b, 0 if a should come before b */ -static int compare_primitives(struct ast_node *a, struct ast_node *b) -{ - assert(a); - if (!b) - return 0; - - /* fully qualified types go first */ - if (fully_qualified(a)) - return 0; - - if (fully_qualified(b)) - return 1; - - /* TODO: figure out what kind of unqualified type we're dealing with, - * i.e. some_generic(u32, some_other_generic) should come before - * some_generic */ - - /* if we're dealing with different unqualified types, push stuff - * backwards, so we don't end up with something like - * 1. some_generic_type - * 2. some_generic_union - * 3. some_generic_type(u32) - */ - - if (a->_type.kind != b->_type.kind) - return 1; - - if (a->_type.kind == AST_TYPE_STRUCT) - return compare_impls(a->_type.struc.impls, - b->_type.struc.impls); - - if (a->_type.kind == AST_TYPE_UNION) - return compare_impls(a->_type.unio.impls, b->_type.unio.impls); - - return 1; -} - -static struct proc_node *insert_primitive(struct proc_node *node, +static struct resolve_node *insert_resolve(struct resolve_node *node, struct ast_node *type) { struct param_node *new = calloc(1, sizeof(struct param_node)); @@ -223,181 +123,88 @@ static struct proc_node *insert_primitive(struct proc_node *node, } new->type = type; - struct proc_node *next = calloc(1, sizeof(struct proc_node)); + struct resolve_node *next = calloc(1, sizeof(struct resolve_node)); if (!next) { free(new); return NULL; } - new->proc = next; + new->resolved = next; - if (!node->primitives) { - node->primitives = new; + if (!node->params) { + node->params = new; return next; } - struct param_node *iter = node->primitives, *prev = NULL; - while (iter && compare_primitives(type, iter->type)) { - prev = iter; - iter = iter->next; - } - - if (prev) - prev->next = new; - - new->next = iter; - - if (iter == node->primitives) - node->primitives = new; + new->next = node->params; + node->params = new; return next; } -static int add_next_resolve(struct scope *scope, struct ast_node *proc, - struct proc_node *node, struct ast_node *params) +static int add_next_resolve(struct scope *scope, struct ast_node *resolve, + struct resolve_node *node, struct ast_node *params) { assert(node); if (params && actualize_temp_type(scope, params)) return -1; - /* TODO: variadics? */ + /* 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->proc) { - semantic_error(scope->fctx, proc, "ambiguous callable"); - semantic_error(scope->fctx, node->proc, "matches here"); + if (node->resolved) { + semantic_error(scope->fctx, resolve, "ambiguous resolution"); + semantic_error(scope->fctx, node->resolved, "matches here"); return -1; } - node->proc = proc; + node->resolved = resolve; return 0; } assert(params->node_type == AST_VAR); - if (primitive_type(params->type)) { - struct param_node *match = match_primitive(node, params->type); - if (match) - return add_next_resolve(scope, proc, match->proc, - params->next); - - struct proc_node *next = insert_primitive(node, params->type); - if (!next) - return -1; - - return add_next_resolve(scope, proc, next, params->next); - } + struct param_node *match = find_matching_param(node, params->type); + if (match) + return add_next_resolve(scope, resolve, + match->resolved, + params->next); - if (referential_type(params->type)) { - /* TODO: I don't think there's a good way to check if the - * referential types are identical, but could be worth a shot */ - if (!node->referential) { - node->referential = - calloc(1, sizeof(struct param_node)); - node->referential->type = params->type; - - struct proc_node *next = - calloc(1, sizeof(struct proc_node)); - node->referential->proc = next; - - return add_next_resolve(scope, proc, next, - params->next); - } - - if (!types_match(node->referential->type, params->type)) { - semantic_error(scope->fctx, params->type, - "ambiguous referential"); - semantic_error(scope->fctx, node->referential->type, - "matches here"); - return -1; - } - - /* common reference */ - destroy_ast_tree(params->type); - params->_var.type = NULL; - params->type = node->referential->type; - return add_next_resolve(scope, proc, node->referential->proc, - params->next); - } - - /* otherwise try to use type as fallback */ - if (!node->fallback) { - node->fallback = calloc(1, sizeof(struct param_node)); - node->fallback->type = params->type; - - struct proc_node *next = calloc(1, sizeof(struct proc_node)); - node->fallback->proc = next; - return add_next_resolve(scope, proc, next, params->next); - } - - if (!match_generic(scope, node->fallback->type, params->type)) { - semantic_error(scope->fctx, params->type, "ambiguous generic"); - semantic_info(scope->fctx, node->fallback->type, - "matches here"); + /** @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; - } - /* common reference */ - destroy_ast_tree(params->type); - params->_var.type = NULL; - params->type = node->fallback->type; - return add_next_resolve(scope, proc, node->fallback->proc, - params->next); + return add_next_resolve(scope, resolve, next, params->next); } -static int add_resolve(struct scope *scope, struct proc_node *root, +static int add_resolve(struct scope *scope, struct resolve *resolve, struct ast_node *proc) { - assert(root); - struct ast_node *sign = proc->_proc.sign; struct ast_node *params = sign->_type.sign.params; struct scope *resolv_scope = create_scope(); scope_add_scope(scope, resolv_scope); - return add_next_resolve(resolv_scope, proc, root, params); + return add_next_resolve(resolv_scope, proc, resolve->root, params); } -static struct ast_node *proc_resolve(struct scope *scope, - struct proc_node *node, +static struct ast_node *resolve(struct scope *scope, + struct resolve_node *node, struct ast_node *args) { assert(node); if (!args) { - if (node->proc) - return node->proc; + if (node->resolved) + return node->resolved; return NULL; } /* first check if we match a primitive type */ - struct param_node *found = find_primitive(node, args->type); + struct param_node *found = find_matching_param(node, args->type); if (found) - return proc_resolve(scope, found->proc, args->next); - - /* no primitives, check referentials */ - struct param_node *ref = node->referential; - if (ref) { - /* this works on the assumption that references actually are - * references to previous nodes, which we've hopefully - * initialized with real types by now. - * However, that doesn't happen, because the fallback isn't the - * one that the type is assigned to. Therefore, fuck. */ - if (types_match(args->type, ref->type)) - return proc_resolve(scope, ref->proc, args->next); - } - - /* referential didn't match, check fallback */ - struct param_node *fallback = node->fallback; - if (!fallback) - return NULL; - - if (implements(0, scope, args->type, fallback->type)) { - /* my idea is that we could lock each node individually and - * allow multithreading scopes, but I realize that recursively - * checking traits might cause a lock... */ - init_trait_type(fallback->type, fallback->type, args->type); - return proc_resolve(scope, fallback->proc, args->next); - } + return resolve(scope, found->resolved, args->next); return NULL; } @@ -466,33 +273,34 @@ void destroy_actuals(struct actual *actuals) } while ((prev = cur)); } -void destroy_proc_node(struct proc_node *); +void destroy_resolve_node(struct resolve_node *); void destroy_param_nodes(struct param_node *param) { if (!param) return; - destroy_proc_node(param->proc); + destroy_resolve_node(param->resolved); destroy_param_nodes(param->next); free(param); } -void destroy_proc_node(struct proc_node *proc) +void destroy_resolve_node(struct resolve_node *resolve) { - destroy_param_nodes(proc->primitives); - destroy_param_nodes(proc->referential); - destroy_param_nodes(proc->fallback); - free(proc); + if (!resolve) + return; + + destroy_param_nodes(resolve->params); + free(resolve); } -void destroy_callable(struct callable *callable) +void destroy_resolve(struct resolve *resolve) { - struct callable *prev = callable, *cur; + struct resolve *prev = resolve, *cur; if (prev) do { cur = prev->next; - destroy_proc_node(prev->root); + destroy_resolve_node(prev->root); destroy_ast_node(prev->id); free(prev); } while ((prev = cur)); @@ -510,14 +318,15 @@ void destroy_scope(struct scope *scope) } destroy_scratch(scope->scratch); - destroy_callable(scope->callable); + 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->procs); destroy_visible(scope, scope->builtins); destroy_visible(scope, scope->enums); - destroy_visible(scope, scope->unions); destroy_visible(scope, scope->structs); destroy_visible(scope, scope->aliases); destroy_visible(scope, scope->traits); @@ -572,13 +381,13 @@ static struct scratch *create_scratch(struct ast_node *scratch) } CREATE_VISIBLE(create_var, vars, AST_VAR); -CREATE_VISIBLE(create_macro, macros, AST_MACRO); CREATE_VISIBLE(create_proc, procs, AST_PROC); +CREATE_VISIBLE(create_macro, macros, AST_MACRO_CONSTRUCT); +CREATE_VISIBLE(create_type_construct, type_constructs, AST_TYPE_CONSTRUCT); CREATE_VISIBLE(create_enum, enums, AST_ENUM); CREATE_VISIBLE(create_alias, aliases, AST_ALIAS); CREATE_VISIBLE(create_struct, structs, AST_STRUCT); -CREATE_VISIBLE(create_union, unions, AST_UNION); CREATE_VISIBLE(create_builtin, builtins, AST_TYPE); CREATE_VISIBLE(create_trait, traits, AST_TRAIT); @@ -598,15 +407,15 @@ CREATE_VISIBLE(create_trait, traits, AST_TRAIT); } REFERENCE_VISIBLE(reference_var, vars, AST_VAR); -REFERENCE_VISIBLE(reference_macro, macros, AST_MACRO); REFERENCE_VISIBLE(reference_proc, procs, AST_PROC); +REFERENCE_VISIBLE(reference_macro, macros, AST_MACRO_CONSTRUCT); REFERENCE_VISIBLE(reference_enum, enums, AST_ENUM); +REFERENCE_VISIBLE(reference_trait, traits, AST_TRAIT); REFERENCE_VISIBLE(reference_alias, aliases, AST_ALIAS); -REFERENCE_VISIBLE(reference_union, unions, AST_UNION); REFERENCE_VISIBLE(reference_struct, structs, AST_STRUCT); REFERENCE_VISIBLE(reference_builtin, builtins, AST_TYPE); -REFERENCE_VISIBLE(reference_trait, traits, AST_TRAIT); +REFERENCE_VISIBLE(reference_type_construct, type_constructs, AST_TYPE_CONSTRUCT); /* does NOT walk the scope tree upward if it doesn't find the var in the scope * */ @@ -632,13 +441,13 @@ FIND_VISIBLE(scope_find_enum, enums, AST_ENUM, _enum); FIND_VISIBLE(scope_find_alias, aliases, AST_ALIAS, _alias); FIND_VISIBLE(scope_find_builtin, builtins, AST_TYPE, _type); FIND_VISIBLE(scope_find_struct, structs, AST_STRUCT, _struct); -FIND_VISIBLE(scope_find_union, unions, AST_UNION, _union); FIND_VISIBLE(scope_find_trait, traits, AST_TRAIT, _trait); /* note that these return the first match for the ID, and as such might not be * what should be called. */ FIND_VISIBLE(scope_find_var, vars, AST_VAR, _var); -FIND_VISIBLE(scope_find_macro, macros, AST_MACRO, _macro); FIND_VISIBLE(scope_find_proc, procs, AST_PROC, _proc); +FIND_VISIBLE(scope_find_macro, macros, AST_MACRO_CONSTRUCT, _macro); +FIND_VISIBLE(scope_find_type_construct, type_constructs, AST_TYPE_CONSTRUCT, type_construct); struct ast_node *scope_find(struct scope *scope, struct ast_node *id) { @@ -673,7 +482,7 @@ struct ast_node *scope_find(struct scope *scope, struct ast_node *id) int name(struct scope *scope, struct ast_node *node) \ { \ assert(node->node_type == ast_type); \ - struct ast_node *shadow = file_scope_find(scope, \ + struct ast_node *shadow = file_scope_find_##obj_type(scope, \ node->ast_name.id); \ if (shadow) { \ semantic_error(scope->fctx, node, \ @@ -698,7 +507,6 @@ struct visible *create_type(struct scope *scope, struct ast_node *type) case AST_TRAIT: return create_trait(scope, type); case AST_ENUM: return create_enum(scope, type); case AST_STRUCT: return create_struct(scope, type); - case AST_UNION: return create_union(scope, type); default: semantic_error(scope->fctx, type, "unknown type"); return NULL; @@ -713,7 +521,6 @@ int reference_type(int public, struct scope *scope, struct visible *visible) case AST_TRAIT: return reference_trait(public, scope, visible); case AST_ENUM: return reference_enum(public, scope, visible); case AST_STRUCT: return reference_struct(public, scope, visible); - case AST_UNION: return reference_union(public, scope, visible); default: semantic_error(scope->fctx, visible->node, "unknown type"); return 1; @@ -758,10 +565,6 @@ struct ast_node *scope_find_type(struct scope *scope, struct ast_node *id) if (found) return found; - found = scope_find_union(scope, id); - if (found) - return found; - found = scope_find_alias(scope, id); if (found) return found; @@ -848,44 +651,6 @@ static int find_implementation(struct ast_node *trait, struct ast_node *type) return 0; } -static struct ast_node *match_macro(int global, struct scope *scope, - struct ast_node *id, struct ast_node *args) -{ - const size_t arg_count = ast_list_len(args); - struct visible *prev = scope->macros, *cur; - if (prev) - do { - cur = prev->next; - struct ast_node *macro = prev->node; - /* must have identical IDs */ - if (!identical_ast_nodes(0, macro->_macro.id, id)) - continue; - - const size_t param_count = ast_list_len( - macro->_macro.params); - - /* if macros have the same number of arguments, they - * match */ - if (param_count == arg_count) - return macro; - - /* if we have a variadic macro, a longer list of args is - * a match */ - if (ast_flags(macro, AST_FLAG_VARIADIC) - && param_count < arg_count) - return macro; - - } while ((prev = cur)); - - if (global && !scope_flags(scope, SCOPE_FILE)) - return match_macro(global, scope->parent, id, args); - - return NULL; -} - -static struct ast_node *match_proc(enum match_flags flags, struct scope *scope, - struct ast_node *id, struct ast_node *args); - 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) @@ -901,7 +666,7 @@ static int implements_proc(enum match_flags flags, struct scope *scope, init_trait_types(params, param_type, arg_type); init_trait_type(ret, param_type, arg_type); - struct ast_node *impl = match_proc(1, scope, id, params); + struct ast_node *impl = match_proc(scope, id, params); if (!impl) goto out; @@ -1182,34 +947,53 @@ static int match_params(enum match_flags flags, struct scope *scope, return ret; } -static struct ast_node *match_proc(enum match_flags flags, struct scope *scope, - struct ast_node *id, struct ast_node *args) +static struct ast_node *match_resolve(struct scope *scope, + struct resolve *s, + struct ast_node *id, + struct ast_node *args) { - (void)(flags); - struct callable *cb = scope->callable; - while (cb) { - if (identical_ast_nodes(0, cb->id, id)) - return proc_resolve(scope, cb->root, 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); - cb = cb->next; + 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); +} + int scope_add_macro(struct scope *scope, struct ast_node *macro) { - assert(macro->node_type == AST_MACRO); + assert(macro->node_type == AST_MACRO_CONSTRUCT); /* TODO: separate between arrays and macros? */ struct ast_node *id = macro->_macro.id; struct ast_node *params = macro->_macro.params; - int macro_exists = match_macro(0, scope, id, params) != NULL; - // TODO: search for any proc with same number of parameters as macro */ - // int proc_exists = match_proc(0, scope, id, params) != NULL; - int proc_exists = 0; - - if (macro_exists || proc_exists) { + int macro_exists = (match_macro(scope, id, params) != NULL); + if (macro_exists) { semantic_error(scope->fctx, macro, "macro redefined"); return -1; } @@ -1225,6 +1009,75 @@ int scope_add_macro(struct scope *scope, struct ast_node *macro) return 0; } +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); +} + +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, macro->_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(macro->_macro.id); + resolve->next = scope->macro_resolve; + scope->macro_resolve = resolve; + + return add_resolve(scope, resolve, macro); +} + +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_GET(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_GET(type_construct, id)); + resolve->next = scope->type_construct_resolve; + scope->type_construct_resolve = resolve; + + return add_resolve(scope, resolve, type_construct); +} + /* would be useful with scope_remove_proc which also removed all references? */ int scope_add_proc(struct scope *scope, struct ast_node *proc) { @@ -1234,7 +1087,7 @@ int scope_add_proc(struct scope *scope, struct ast_node *proc) struct ast_node *sign = proc->_proc.sign; struct ast_node *params = sign->_type.sign.params; - struct ast_node *macro_exists = match_macro(0, scope, id, params); + struct ast_node *macro_exists = match_proc(scope, id, params); if (macro_exists) { semantic_error(scope->fctx, proc, "proc redefined"); @@ -1246,6 +1099,8 @@ int scope_add_proc(struct scope *scope, struct ast_node *proc) if (!new) return -1; + add_proc_resolve(scope, proc); + int public = scope_flags(scope, SCOPE_PUBLIC); if (scope_flags(scope, SCOPE_FILE) && ast_flags(proc, AST_FLAG_PUBLIC)) return reference_proc(public, scope->parent, new); @@ -1253,65 +1108,28 @@ int scope_add_proc(struct scope *scope, struct ast_node *proc) return 0; } -int scope_add_existing_var(struct scope *scope, struct visible *visible) -{ - struct ast_node *node = visible->node; - assert(node->node_type == AST_VAR); - struct ast_node *shadow = file_scope_find(scope, node->_var.id); - if (shadow) { - semantic_error(scope->fctx, node, "shadowing is not allowed\n"); - semantic_info(scope->fctx, shadow, - "previous declaration was here\n"); - return -1; - } - - visible->next = scope->vars; - scope->vars = visible; - - int public = scope_flags(scope, SCOPE_PUBLIC); - if (scope_flags(scope, SCOPE_FILE) && ast_flags(node, AST_FLAG_PUBLIC)) - return reference_proc(public, scope->parent, visible); - - return 0; -} - -int scope_add_existing_proc(struct scope *scope, struct visible *visible) +int scope_add_type_construct(struct scope *scope, struct ast_node *type_construct) { - struct ast_node *proc = visible->node; - assert(proc->node_type == AST_PROC); + assert(type_construct->node_type == AST_TYPE_CONSTRUCT); - struct ast_node *id = proc->_proc.id; - struct ast_node *sign = proc->_proc.sign; - struct ast_node *params = sign->_type.sign.params; + struct ast_node *id = AST_GET(type_construct, id); + struct ast_node *params = AST_GET(type_construct, params); - struct ast_node *macro_exists = match_macro(0, scope, id, params); - if (macro_exists) { - semantic_error(scope->fctx, proc, "proc redefined"); - semantic_info(scope->fctx, macro_exists, "previously as macro"); + int type_construct_exists = (match_type_construct(scope, id, params) != NULL); + if (type_construct_exists) { + semantic_error(scope->fctx, type_construct, "type construct redefined"); return -1; } - if (!scope->callable) { - scope->callable = calloc(1, sizeof(struct callable)); - scope->callable->root = calloc(1, sizeof(struct proc_node)); - scope->callable->id = clone_ast_node(id); - return add_resolve(scope, scope->callable->root, proc); - } - - struct callable *cb = scope->callable; - while (cb) { - if (identical_ast_nodes(0, cb->id, id)) - return add_resolve(scope, cb->root, proc); + struct visible *new = create_type_construct(scope, type_construct); + if (!new) + return -1; - cb = cb->next; - } + int public = scope_flags(scope, SCOPE_PUBLIC); + if (scope_flags(scope, SCOPE_FILE) && ast_flags(type_construct, AST_FLAG_PUBLIC)) + return reference_type_construct(public, scope->parent, new); - cb = calloc(1, sizeof(struct callable)); - cb->root = calloc(1, sizeof(struct proc_node)); - cb->id = clone_ast_node(id); - cb->next = scope->callable; - scope->callable = cb; - return add_resolve(scope, cb->root, proc); + return 0; } #define FIND_FILE_VISIBLE(name, obj_type) \ @@ -1378,12 +1196,12 @@ struct ast_node *file_scope_find(struct scope *scope, struct ast_node *id) return NULL; } -struct ast_node *scope_resolve_macro(struct scope *scope, struct ast_node *call) +struct ast_node *scope_resolve_macro(struct scope *scope, struct ast_node *macro) { - assert(call->node_type == AST_CALL); - struct ast_node *id = call->_call.id; - struct ast_node *args = call->_call.args; - return match_macro(0, scope, id, args); + 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); } static int trait_contains_proc(enum match_flags flags, struct scope *scope, @@ -1423,39 +1241,7 @@ struct ast_node *scope_resolve_proc(struct scope *scope, struct ast_node *call) struct ast_node *id = call->_call.id; struct ast_node *args = call->_call.args; - /* TODO: this prints out an error for each scope we run through, figure - * out where we should check for this stuff so only a single error is - * printed */ - /* loop over arguments, if any of them are traitd check that the - * found proc can be found in the trait */ - struct ast_node *arg = args; - while (arg) { - struct ast_node *trait = extract_trait(arg->type); - if (!trait) - goto next; - - if (!trait_contains_proc(MATCH_CALL, scope, trait, id, - args)) { - char *cstr = call_str(call); - char *tstr = type_str(arg); - semantic_error(scope->fctx, arg, - "%s not associated with %s", - cstr, - tstr); - free(cstr); - free(tstr); - return NULL; - } - -next: - arg = arg->next; - } - - struct ast_node *proc = match_proc(MATCH_CALL, scope, id, args); - if (!proc) - return NULL; - - return proc; + return match_proc(scope, id, args); } struct ast_node *scope_resolve_actual(struct scope *scope, @@ -1488,40 +1274,11 @@ struct ast_node *scope_resolve_actual(struct scope *scope, return NULL; } -struct ast_node *scope_resolve_arr(struct scope *scope, struct ast_node *call) -{ - assert(call->node_type == AST_CALL); - /* could implement arrays in multiple dimensions, though that might make - * other things complicated so disallow it for now */ - if (ast_list_len(call->_call.args) != 1) - return NULL; - - struct ast_node *arg = call->_call.args; - struct ast_node *var = scope_find_var(scope, call->_call.id); - if (!var) - return NULL; - - /* TODO: actualize has types_match, should it be generalized into ast.c - * or something? */ - if (!identical_ast_nodes(0, var->type, arg->type)) - return NULL; - - return var; -} - struct ast_node *scope_resolve_call(struct scope *scope, struct ast_node *call) { assert(call->node_type == AST_CALL); - /* TODO: should make sure we're getting an array at some point */ - struct ast_node *found = scope_resolve_arr(scope, call); - if (found) - return found; - - found = scope_resolve_macro(scope, call); - if (found) - return found; - - found = scope_resolve_actual(scope, call); + /* unsure if actual should be here or somewhere else but eh */ + struct ast_node *found = scope_resolve_actual(scope, call); if (found) return found; @@ -1567,10 +1324,6 @@ struct ast_node *scope_resolve_type(struct scope *scope, struct ast_node *type) id = type->_struct.id; break; - case AST_UNION: - id = type->_union.id; - break; - case AST_ENUM: id = type->_enum.id; break; @@ -1596,6 +1349,18 @@ struct ast_node *file_scope_resolve_type(struct scope *scope, return NULL; } +struct ast_node *file_scope_resolve_macro(struct scope *scope, struct ast_node *macro) +{ + struct ast_node *found = scope_resolve_macro(scope, macro); + if (found) + return found; + + if (!scope_flags(scope, SCOPE_FILE)) + return file_scope_resolve_type(scope->parent, macro); + + return NULL; +} + /* this might be useful somewhere else as well */ static const char *default_types[] = {"u8", "u16", "u32", "u64", "i8" "i16", "i32", "i64", @@ -1610,7 +1375,7 @@ int scope_add_defaults(struct scope *root) i < sizeof(default_types) / sizeof(default_types[0]); ++i) { const char *type = default_types[i]; - struct ast_node *n = gen_id(strdup(type)); + struct ast_node *n = gen_id(strdup(type), NULL_LOC()); if (!n) return -1; |
