diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/actualize.c | 87 | ||||
| -rw-r--r-- | src/ast.c | 1 | ||||
| -rw-r--r-- | src/debug.c | 10 | ||||
| -rw-r--r-- | src/lexer.l | 2 | ||||
| -rw-r--r-- | src/lower.c | 41 | ||||
| -rw-r--r-- | src/parser.y | 4 |
6 files changed, 105 insertions, 40 deletions
diff --git a/src/actualize.c b/src/actualize.c index 2cf4c13..ba5475e 100644 --- a/src/actualize.c +++ b/src/actualize.c @@ -815,6 +815,14 @@ static int actualize_macro_def(struct act_state *state, /* macro bodies, arguments, etc aren't expanded upon until the macro is * called, so just try to add it to the local scope */ assert(n && n->k == AST_MACRO_DEF); + + n->t = void_type(); + + /* analysis should've added us to the file scope already */ + if (scope_flags(scope, SCOPE_FILE)) + return 0; + + /* otherwise, add us to whatever scope we're in */ return scope_add_macro(scope, n); } @@ -1443,7 +1451,8 @@ static int actualize_tconstruct(struct act_state *state, struct type *t) { assert(t->k == TYPE_CONSTRUCT); - struct ast *d = actualized_file_scope_find_type(state, scope, construct_id(t)); + struct ast *d = actualized_file_scope_find_type(state, scope, + construct_id(t)); if (!d) { type_error(scope->fctx, t, "no such type"); return -1; @@ -1602,8 +1611,7 @@ static int actualize_cast(struct act_state *state, char *left_type = type_str(expr->t); char *right_type = type_str(type); - semantic_error(scope->fctx, cast, "illegal cast: %s vs %s", - left_type, right_type); + type_mismatch(scope, "illegal cast", cast, expr->t, type); free(left_type); free(right_type); return -1; @@ -1690,7 +1698,7 @@ static int actualize_return(struct act_state *state, struct scope *scope, struct type *rtype = callable_rtype(cur_proc->t); if (!types_match(node->t, rtype)) { type_mismatch(scope, "return type mismatch", node, - rtype, node->t); + rtype, node->t); return -1; } @@ -2099,7 +2107,8 @@ static int actualize_struct(struct act_state *state, else if (same_id(id, "i9")) node->t = tgen_primitive(TYPE_I9, strdup(id), node, node->loc); else if (same_id(id, "bool")) - node->t = tgen_primitive(TYPE_BOOL, strdup(id), node, node->loc); + node->t = tgen_primitive(TYPE_BOOL, strdup(id), node, + node->loc); else if (same_id(id, "ptr")) { node->t = tgen_ptr(void_type(), node->loc); /* we know we're the definition for pointers */ @@ -2145,7 +2154,7 @@ static int actualize_struct(struct act_state *state, * table */ if (n->k == AST_VAR_DEF && node->t->k != TYPE_STRUCT) { semantic_error(scope->fctx, n, - "variables not allowed in primitive struct"); + "variables not allowed in primitive struct"); return -1; } @@ -2275,8 +2284,17 @@ static int actualize_dot(struct act_state *state, } } + if (def->k == AST_ENUM_DEF) + def = (enum_type(def))->d; + + if (!def) { + semantic_error(scope->fctx, node, + "no such type"); + return -1; + } + struct ast *exists = actualized_scope_find_symbol(state, - def->scope, + def->scope, id); if (exists) { assert(exists->t); @@ -2284,8 +2302,11 @@ static int actualize_dot(struct act_state *state, return 0; } + char *tstr = type_str(type); semantic_error(scope->fctx, node, - "does not have member"); + "%s does not have have member", + tstr); + free(tstr); return -1; } @@ -2430,6 +2451,8 @@ static int actualize_enum_fetch(struct act_state *state, struct scope *scope, return -1; } + /* this should be safe since we currently don't allow enums to be part + * of any generic structures. */ replace_slice_ast(fetch, val_val(member)); set_type(fetch, def->t); return 0; @@ -2443,7 +2466,8 @@ static int actualize_fetch(struct act_state *state, struct scope *scope, if (actualize_type(state, scope, type)) return -1; - if (type->k == TYPE_ENUM) + assert(type->d); + if (type->d->k == AST_ENUM_DEF) return actualize_enum_fetch(state, scope, fetch); if (type->k != TYPE_STRUCT && type->k != TYPE_TRAIT && @@ -2473,41 +2497,45 @@ static int actualize_enum(struct act_state *state, struct scope *scope, struct ast *node) { assert(node->k == AST_ENUM_DEF); - struct type *type = enum_type(node); struct scope *enum_scope = node->scope; /* TODO: here we could save space by choosing the smallest type that * fits */ - if (!type) { - type = i27_type(scope); - node->t = type; - } else if (actualize_type(state, enum_scope, type)) + if (!enum_type(node)) + enum_type(node) = i27_type(scope); + + /* enum are at least currently limited to top scope, so we don't have to + * worry about them being part of some generic structure. Might be a + * future improvement, though. */ + struct type *type = enum_type(node); + if (actualize_type(state, enum_scope, type)) return -1; + /* overwrite type definition to point to us. + * This is maybe something of a hack, but effectively 'pretend' to be a + * regular i27 or whatever to make casts etc. work like in C. */ + node->t = clone_type(type); + node->t->d = node; + long long counter = 0; - node->t = type; struct ast *members = enum_body(node); while (members) { set_type(members, type); - if (val_val(members)) { - struct ast *val = val_val(members); - if (actualize(state, enum_scope, val)) - return -1; + if (!val_val(members)) + val_val(members) = gen_const_int(counter, NULL_LOC()); - if (val->k != AST_CONST_INT) { - semantic_error(scope->fctx, members, - "unable to process nonconstant expression"); - return -1; - } + struct ast *val = val_val(members); + if (actualize(state, enum_scope, val)) + return -1; - counter = int_val(val); - } - else { - val_val(members) = gen_const_int(counter, NULL_LOC()); + if (val->k != AST_CONST_INT) { + semantic_error(scope->fctx, members, + "unable to process nonconstant expression"); + return -1; } + counter = int_val(val) + 1; members = members->n; - counter++; } /* TODO: check that we don't go outside the limits of the type */ @@ -2681,6 +2709,7 @@ static int actualize(struct act_state *state, struct scope *scope, } switch (node->k) { + case AST_IMPORT: ret = 0; node->t = void_type(); break; case AST_PROC_DEF: ret = actualize_proc(state, scope, node); break; case AST_TRAIT_DEF: ret = actualize_trait(state, scope, node); break; case AST_ALIAS_DEF: ret = actualize_alias(state, scope, node); break; @@ -296,6 +296,7 @@ void ast_dump(int depth, struct ast *n) DUMP(AST_CONST_CHAR); DUMP(AST_CONST_BOOL); DUMP(AST_CONST_STR); + DUMP(AST_UNPACK); } #undef DUMP diff --git a/src/debug.c b/src/debug.c index e90f1ee..32c74a2 100644 --- a/src/debug.c +++ b/src/debug.c @@ -280,10 +280,18 @@ static void _type_str(FILE *fp, struct type *type) break; } + case TYPE_ENUM: { + struct ast *def = type->d; + if (enum_id(def)) { + fprintf(fp, "%s", enum_id(def)); + } + break; + } + case TYPE_TRAIT: { struct ast *def = type->d; if (trait_id(def)) { - fprintf(fp, "%s ", trait_id(def)); + fprintf(fp, "%s", trait_id(def)); } if (struct_params(def)) { diff --git a/src/lexer.l b/src/lexer.l index b38833d..3d5a413 100644 --- a/src/lexer.l +++ b/src/lexer.l @@ -165,7 +165,7 @@ STRING \"(\\.|[^"\\])*\" {STRING} { /* seems risky, I know, but letting the parser choose when to allocate a * new string seems to help with syntax error cleanup */ - yylval->str = yytext; + yylval->str = strdup(yytext); return STRING; } diff --git a/src/lower.c b/src/lower.c index 02d28e4..a01dd40 100644 --- a/src/lower.c +++ b/src/lower.c @@ -279,11 +279,15 @@ static int lower_param(struct lower_state *s, struct ast *p, struct vec *fixups) assert(p->k == AST_VAR_DEF); assert(var_init(p) == NULL); - if (is_primitive(p->t) || p->t->k == TYPE_PTR) { + if (is_primitive(p->t) || p->t->k == TYPE_PTR || p->t->k == TYPE_CALLABLE) { return lower_simple_param(s, p); } - assert(p->t->k == TYPE_STRUCT); + if (p->t->k != TYPE_STRUCT) { + semantic_error(p->scope->fctx, p, + "illegal type"); + return -1; + } char *name = NULL; if (var_id(p)) name = mangle(p); @@ -496,13 +500,19 @@ static int lower_id(struct lower_state *s, struct ast *id, * them but if we did have them we might have to run * file_scope_find_symbol and add it to the state as we run into * them */ - struct ast *def = file_scope_find_proc(id->scope, id->s); + struct ast *def = file_scope_find_symbol(id->scope, id->s); assert(def); - add_proc(s, def); - char *o = m; - m = build_str("&%s", m); - free(o); + if (def->k == AST_PROC_DEF) { + add_proc(s, def); + + char *o = m; + /* we don't want to take the address of a variable + * (pointer to function, whatever), + * just the regular functions */ + m = build_str("&%s", m); + free(o); + } } *retval = build_retval(kind, m); @@ -960,6 +970,18 @@ static int lower_init(struct lower_state *s, struct ast *init, return 0; } +static struct ast *maybe_fetch_enum_type(struct ast *node) +{ + if (node->k == AST_ENUM_DEF) { + struct type *t = enum_type(node); + assert(t && (t->k == TYPE_I9 || t->k == TYPE_I27)); + + return file_scope_find_type(node->scope, t->id); + } + + return node; +} + static int lower_fetch(struct lower_state *s, struct ast *f, struct retval *retval) { @@ -972,6 +994,11 @@ static int lower_fetch(struct lower_state *s, struct ast *f, struct ast *def = (fetch_type(f))->d; assert(def); + /* enums are kind of sneaky as they masquerade as their underlying type + * but their definition differs */ + def = maybe_fetch_enum_type(def); + assert(def); + struct ast *proc = scope_find_proc(def->scope, fetch_id(f)); assert(proc); diff --git a/src/parser.y b/src/parser.y index 62afcac..c7a3a63 100644 --- a/src/parser.y +++ b/src/parser.y @@ -253,7 +253,7 @@ var : var_init embed - : "embed" "(" STRING ")" { $$ = gen_embed(strip($3), src_loc(@$)); } + : "embed" STRING { $$ = gen_embed(strip($2), src_loc(@$)); } import : "import" STRING { $$ = gen_import(strip($2), src_loc(@$)); } @@ -423,6 +423,7 @@ expr | "sizeof" expr { $$ = gen_sizeof($2, src_loc(@$)); } | expr "as" type { $$ = gen_cast($1, $3, src_loc(@$)); } | ID "::" type { $$ = gen_fetch($1, $3, src_loc(@$)); } + | "..." ID { $$ = gen_unpack($2, src_loc(@$)); } | macro_expand | construct | assign @@ -477,7 +478,6 @@ statement | for | if | const - | enum | macro | ID ":" { $$ = gen_label($[ID], NULL, src_loc(@$)); } |
