bug fixes for params shadowing
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 24 May 2020 16:47:59 +0000 (11:47 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 24 May 2020 16:47:59 +0000 (11:47 -0500)
onyx
onyx.c
onyxmsgs.c
onyxmsgs.h
onyxparser.c
onyxparser.h
progs/minimal.onyx

diff --git a/onyx b/onyx
index 2c67a97770447bdd8cd6786329c985c095e460e5..6ec79ea91f5dad35682e1545c61ee8a15a197f14 100755 (executable)
Binary files a/onyx and b/onyx differ
diff --git a/onyx.c b/onyx.c
index cd94fdc3de7673eec6e84fe25c7c4336db256422..d91dd70e492ac8af88798c48d7d274f49b2ab55b 100644 (file)
--- 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);
index fae03d8576c7c014eebbbc1dc223310e254abe7c..6b92357d4643ce0f25a5c5794641bf49bf23dfc8 100644 (file)
@@ -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, ...) {
index 81c667b26cef29c44b45b24337bc5a581d02171c..fc102233a3adb9f160764b43e255274865d66f41 100644 (file)
@@ -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;
index 020c88d34269d9f7722d82a1eb5a054a370074b2..82949e7966126cd802b8d017904ec2ab42b530b3 100644 (file)
@@ -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) {
index 3dfd782ca3ed87769c71826992b1dc697ea12801..9b16c10b35c0d83d0188d6deda20fc4a05a9c6ef 100644 (file)
@@ -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;
index 8e3b4d853e127be8ea706c280dd25ccf32822a0a..5b82b6991324ecb41b61789d3049a58415995b5b 100644 (file)
@@ -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;
-};
+}