From: Brendan Hansen Date: Sun, 24 May 2020 16:47:59 +0000 (-0500) Subject: bug fixes for params shadowing X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=db07e7bd3dd9eb9058afa5bd7573ddbafd00b14c;p=onyx.git bug fixes for params shadowing --- diff --git a/onyx b/onyx index 2c67a977..6ec79ea9 100755 Binary files a/onyx and b/onyx differ diff --git a/onyx.c b/onyx.c index cd94fdc3..d91dd70e 100644 --- a/onyx.c +++ b/onyx.c @@ -54,7 +54,9 @@ int main(int argc, char *argv[]) { if (onyx_message_has_errors(&msgs)) { onyx_message_print(&msgs); } else { - onyx_ast_print(program); + // TODO: Make a better AST printer so there aren't infinite loops + // onyx_ast_print(program); + bh_printf("No errors.\n"); } bh_file_contents_delete(&fc); diff --git a/onyxmsgs.c b/onyxmsgs.c index fae03d85..6b92357d 100644 --- a/onyxmsgs.c +++ b/onyxmsgs.c @@ -8,6 +8,7 @@ static const char* msg_formats[] = { "expected lval '%s'", "attempt to assign to constant '%s'", "unknown symbol '%s'", + "redefinition of function '%s'", }; void onyx_message_add(OnyxMessages* msgs, OnyxMessageType type, OnyxFilePos pos, ...) { diff --git a/onyxmsgs.h b/onyxmsgs.h index 81c667b2..fc102233 100644 --- a/onyxmsgs.h +++ b/onyxmsgs.h @@ -15,6 +15,7 @@ typedef enum OnyxMessageType { ONYX_MESSAGE_TYPE_NOT_LVAL, ONYX_MESSAGE_TYPE_ASSIGN_CONST, ONYX_MESSAGE_TYPE_UNKNOWN_SYMBOL, + ONYX_MESSAGE_TYPE_FUNCTION_REDEFINITION, ONYX_MESSAGE_TYPE_COUNT, } OnyxMessageType; diff --git a/onyxparser.c b/onyxparser.c index 020c88d3..82949e79 100644 --- a/onyxparser.c +++ b/onyxparser.c @@ -72,7 +72,8 @@ static b32 is_terminating_token(OnyxTokenType token_type); static OnyxToken* expect(OnyxParser* parser, OnyxTokenType token_type); static OnyxAstNodeScope* enter_scope(OnyxParser* parser); static OnyxAstNodeScope* leave_scope(OnyxParser* parser); -static void insert_local(OnyxParser* parser, OnyxAstNodeLocal* local); +static void insert_identifier(OnyxParser* parser, OnyxAstNode* ident, b32 is_local); +static void remove_identifier(OnyxParser* parser, OnyxAstNode* ident); static OnyxAstNode* parse_factor(OnyxParser* parser); static OnyxAstNode* parse_bin_op(OnyxParser* parser, OnyxAstNode* left); static OnyxAstNode* parse_expression(OnyxParser* parser); @@ -146,16 +147,7 @@ static OnyxAstNodeScope* leave_scope(OnyxParser* parser) { assert(parser->curr_scope != NULL); for (OnyxAstNodeLocal *walker = parser->curr_scope->last_local; walker != NULL; walker = walker->prev_local) { - onyx_token_null_toggle(*walker->token); - - if (walker->shadowed) { - // NOTE: Restore shadowed variable - bh_hash_put(OnyxAstNode*, parser->identifiers, walker->token->token, walker->shadowed); - } else { - bh_hash_delete(OnyxAstNode*, parser->identifiers, walker->token->token); - } - - onyx_token_null_toggle(*walker->token); + remove_identifier(parser, (OnyxAstNode *) walker); } parser->curr_scope = parser->curr_scope->prev_scope; @@ -174,13 +166,16 @@ static OnyxAstNode* lookup_identifier(OnyxParser* parser, OnyxToken* token) { return ident; } -static void insert_local(OnyxParser* parser, OnyxAstNodeLocal* local) { - OnyxAstNodeScope* scope = parser->curr_scope; - local->prev_local = scope->last_local; - scope->last_local = local; +static void insert_identifier(OnyxParser* parser, OnyxAstNode* ident, b32 is_local) { + OnyxAstNodeLocal* local = (OnyxAstNodeLocal *) ident; + if (is_local) { + OnyxAstNodeScope* scope = parser->curr_scope; + local->prev_local = scope->last_local; + scope->last_local = local; + } onyx_token_null_toggle(*local->token); - if (bh_hash_has(OnyxAstNodeLocal*, parser->identifiers, local->token->token)) { + if (bh_hash_has(OnyxAstNode*, parser->identifiers, local->token->token)) { local->shadowed = bh_hash_get(OnyxAstNode*, parser->identifiers, local->token->token); } @@ -188,6 +183,18 @@ static void insert_local(OnyxParser* parser, OnyxAstNodeLocal* local) { onyx_token_null_toggle(*local->token); } +static void remove_identifier(OnyxParser* parser, OnyxAstNode* ident) { + OnyxAstNodeLocal* local = (OnyxAstNodeLocal *) ident; + + onyx_token_null_toggle(*local->token); + if (local->shadowed) { + bh_hash_put(OnyxAstNode*, parser->identifiers, local->token->token, local->shadowed); + } else { + bh_hash_delete(OnyxAstNode*, parser->identifiers, local->token->token); + } + onyx_token_null_toggle(*local->token); +} + static OnyxAstNode* parse_factor(OnyxParser* parser) { switch (parser->curr_token->type) { case TOKEN_TYPE_OPEN_PAREN: { @@ -296,7 +303,7 @@ static b32 parse_symbol_statement(OnyxParser* parser, OnyxAstNode** ret) { local->type = type; local->flags |= flags; - insert_local(parser, local); + insert_identifier(parser, (OnyxAstNode *) local, 1); if (parser->curr_token->type == TOKEN_TYPE_SYM_EQUALS) { parser_next_token(parser); @@ -528,21 +535,16 @@ static OnyxAstNodeFuncDef* parse_function_definition(OnyxParser* parser) { OnyxTypeInfo* return_type = parse_type(parser); func_def->return_type = return_type; - // BUG: if a param has the same name as a global or function, that global/function - // will no longer be in scope after the function body ends for (OnyxAstNodeParam* p = func_def->params; p != NULL; p = p->next) { - onyx_token_null_toggle(*p->token); - bh_hash_put(OnyxAstNode*, parser->identifiers, p->token->token, (OnyxAstNode*) p); - onyx_token_null_toggle(*p->token); + insert_identifier(parser, (OnyxAstNode *) p, 0); } func_def->body = parse_block(parser, 1); for (OnyxAstNodeParam* p = func_def->params; p != NULL; p = p->next) { - onyx_token_null_toggle(*p->token); - bh_hash_delete(OnyxAstNode*, parser->identifiers, p->token->token); - onyx_token_null_toggle(*p->token); + remove_identifier(parser, (OnyxAstNode *) p); } + return func_def; } @@ -578,6 +580,23 @@ static OnyxAstNode* parse_top_level_statement(OnyxParser* parser) { if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_PROC) { OnyxAstNodeFuncDef* func_def = parse_function_definition(parser); func_def->token = symbol; + + onyx_token_null_toggle(*symbol); + + if (!bh_hash_has(OnyxAstNode *, parser->identifiers, symbol->token)) { + bh_hash_put(OnyxAstNode *, parser->identifiers, symbol->token, (OnyxAstNode *) func_def); + } else { + onyx_message_add(parser->msgs, + ONYX_MESSAGE_TYPE_FUNCTION_REDEFINITION, + symbol->pos, + symbol->token); + + // NOTE: I really wish C had defer... + onyx_token_null_toggle(*symbol); + return NULL; + } + + onyx_token_null_toggle(*symbol); return (OnyxAstNode *) func_def; } else if (parser->curr_token->type == TOKEN_TYPE_KEYWORD_STRUCT) { diff --git a/onyxparser.h b/onyxparser.h index 3dfd782c..9b16c10b 100644 --- a/onyxparser.h +++ b/onyxparser.h @@ -120,7 +120,18 @@ struct OnyxAstNodeLocal { OnyxTypeInfo *type; OnyxAstNodeLocal *prev_local; OnyxAstNode *shadowed; - OnyxAstNode *unused2; + OnyxAstNode *unused; +}; + +// NOTE: Needs to have shadowed in the same position as OnyxAstNodeLocal +struct OnyxAstNodeParam { + OnyxAstNodeKind kind; + u32 flags; + OnyxToken *token; // Symbol name i.e. 'a', 'b' + OnyxTypeInfo *type; + OnyxAstNodeParam *next; + OnyxAstNode *shadowed; + u64 param_count; }; struct OnyxAstNodeScope { @@ -143,16 +154,6 @@ struct OnyxAstNodeBlock { OnyxAstNodeScope *scope; // NOTE: Only set on blocks belonging to functions }; -struct OnyxAstNodeParam { - OnyxAstNodeKind kind; - u32 flags; - OnyxToken *token; // Symbol name i.e. 'a', 'b' - OnyxTypeInfo *type; - OnyxAstNodeParam *next; - u64 param_count; - OnyxAstNode *right; -}; - struct OnyxAstNodeFuncDef { OnyxAstNodeKind kind; u32 flags; diff --git a/progs/minimal.onyx b/progs/minimal.onyx index 8e3b4d85..5b82b699 100644 --- a/progs/minimal.onyx +++ b/progs/minimal.onyx @@ -1,19 +1,21 @@ /* This is a comment */ /* Currently the "foreign" keyword doesn't do anything */ -foreign "console" log :: proc (a i32, b i32) -> i32 ---; +foreign "console" log :: proc (a i32, b i32) -> i32 --- export add :: proc (a i32, b i32) -> i32 { /* More comments */ return a + b; -}; +} + +c :: proc () -> void --- export mul :: proc (a i32, b i32) -> i32 { c: const i32 = a - b; /* Don't love this syntax, but it's easy to parse so whatever Inferred type, but constant */ - d: const = a + 2; + d: const = a + b; return c * d; -}; +}