multiple declarations work in procedure bodies
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 12 Jan 2021 20:32:07 +0000 (14:32 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 12 Jan 2021 20:32:07 +0000 (14:32 -0600)
bin/onyx
include/onyxastnodes.h
onyx.exe
src/onyxastnodes.c
src/onyxchecker.c
src/onyxparser.c
src/onyxtypes.c
src/onyxutils.c
src/onyxwasm.c

index 4d6e3d911cb5a7741d99a9d5383aa64f68144f2f..dddbe4b52469d33867956c997987a174d9096cc2 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 879d89a91c69c098b222f42a60b12db2aa282a27..720833205ad6b638c2482e3faa9e7916b5bcd430 100644 (file)
@@ -987,6 +987,8 @@ AstNumLit* make_float_literal(bh_allocator a, f64 value);
 AstBinaryOp* make_binary_op(bh_allocator a, BinaryOp operation, AstTyped* left, AstTyped* right);
 AstArgument* make_argument(bh_allocator a, AstTyped* value);
 AstFieldAccess* make_field_access(bh_allocator a, AstTyped* node, char* field);
+AstLocal* make_local(bh_allocator a, OnyxToken* token, AstType* type_node);
+AstNode* make_symbol(bh_allocator a, OnyxToken* sym);
 
 typedef enum PolyProcLookupMethod {
     PPLM_By_Call,
index 56839afc24d0e047aaac0a9b754a5cc20bd5439c..2e658aab068e6c9f72a5f94943a006748fc9c403 100644 (file)
Binary files a/onyx.exe and b/onyx.exe differ
index 8c7b15a36a27e235280ea1820072a3a0045e7caf..b94cc535df4488ea4be849303cbb98902d180b66 100644 (file)
@@ -617,3 +617,16 @@ AstFieldAccess* make_field_access(bh_allocator a, AstTyped* node, char* field) {
     return fa;
 }
 
+AstLocal* make_local(bh_allocator a, OnyxToken* token, AstType* type_node) {
+    AstLocal* local = onyx_ast_node_new(a, sizeof(AstLocal), Ast_Kind_Local);
+    local->token = token;
+    local->type_node = type_node;
+
+    return local;
+}
+
+AstNode* make_symbol(bh_allocator a, OnyxToken* sym) {
+    AstNode* symbol = onyx_ast_node_new(a, sizeof(AstNode), Ast_Kind_Symbol);
+    symbol->token = sym;
+    return symbol;
+}
index 03ffaf50fe91eb1882df8b11b5f980fb47e901c5..d5b7cf12f4e2c64389d90ddb8d83db12b8bdeaed 100644 (file)
@@ -591,7 +591,24 @@ CheckStatus check_binop_assignment(AstBinaryOp* binop, b32 assignment_is_ok) {
         // NOTE: This is the 'type inference' system. Very stupid, but very easy.
         // If a left operand has an unknown type, fill it in with the type of
         // the right hand side.
-        if (binop->left->type == NULL) binop->left->type = resolve_expression_type(binop->right);
+        if (binop->left->type == NULL) {
+            resolve_expression_type(binop->right);
+
+            if (binop->right->type->kind == Type_Kind_Compound) {
+                i32 expr_count = binop->right->type->Compound.count;
+                AstCompound* lhs = (AstCompound *) binop->left;
+                assert(lhs->kind == Ast_Kind_Compound);
+
+                fori (i, 0, expr_count) {
+                    lhs->exprs[i]->type = binop->right->type->Compound.types[i];
+                }
+
+                lhs->type = type_build_compound_type(semstate.node_allocator, lhs);
+
+            } else {
+                binop->left->type = binop->right->type;
+            }
+        }
 
     } else {
         // NOTE: +=, -=, ...
@@ -1115,7 +1132,7 @@ CheckStatus check_range_literal(AstRangeLiteral** prange) {
 CheckStatus check_compound(AstCompound* compound) {
     bh_arr_each(AstTyped *, expr, compound->exprs) {
         CHECK(expression, expr);
-        resolve_expression_type(*expr);        
+        resolve_expression_type(*expr);
     }
 
     compound->type = type_build_compound_type(semstate.node_allocator, compound);
@@ -1194,7 +1211,9 @@ CheckStatus check_array_access(AstArrayAccess* aa) {
     resolve_expression_type(aa->expr);
     if (aa->expr->type->kind != Type_Kind_Basic
             || (aa->expr->type->Basic.kind != Basic_Kind_I32 && aa->expr->type->Basic.kind != Basic_Kind_U32)) {
-        onyx_report_error(aa->token->pos, "Expected type u32 or i32 for index.");
+        onyx_report_error(aa->token->pos,
+            "Expected type u32 or i32 for index, got '%s'.",
+            type_get_name(aa->expr->type));
         return Check_Error;
     }
 
index 51277e20aaea62a5b87910066bb0cc1cb35b9b0d..5d309d9861fb5bbc038c48157de98eeef76abbee 100644 (file)
@@ -5,6 +5,7 @@
 
 // NOTE: The one weird define you need to know before read the code below
 #define make_node(nclass, kind) onyx_ast_node_new(parser->allocator, sizeof(nclass), kind)
+#define peek_token(ahead) (parser->curr + ahead)
 
 #define STORE_PARSER_STATE \
     OnyxToken* __parser_curr = parser->curr; \
@@ -167,7 +168,7 @@ static AstNumLit* parse_float_literal(OnyxParser* parser) {
 
 static b32 parse_possible_struct_literal(OnyxParser* parser, AstTyped* left, AstTyped** ret) {
     if (parser->curr->type != '.'
-        || (parser->curr + 1)->type != '{') return 0;
+        || peek_token(1)->type != '{') return 0;
 
     AstStructLiteral* sl = make_node(AstStructLiteral, Ast_Kind_Struct_Literal);
     sl->token = parser->curr;
@@ -182,7 +183,7 @@ static b32 parse_possible_struct_literal(OnyxParser* parser, AstTyped* left, Ast
 
     expect_token(parser, '.');
     expect_token(parser, '{');
-    b32 is_named = ((parser->curr + 1)->type == '=');
+    b32 is_named = (peek_token(1)->type == '=');
 
     OnyxToken* name = NULL;
     while (parser->curr->type != '}') {
@@ -220,7 +221,7 @@ static b32 parse_possible_struct_literal(OnyxParser* parser, AstTyped* left, Ast
 
 static b32 parse_possible_array_literal(OnyxParser* parser, AstTyped* left, AstTyped** ret) {
     if (parser->curr->type != '.'
-        || (parser->curr + 1)->type != '[') return 0;
+        || peek_token(1)->type != '[') return 0;
     
     AstArrayLiteral* al = make_node(AstArrayLiteral, Ast_Kind_Array_Literal);
     al->token = parser->curr;
@@ -858,9 +859,9 @@ static AstIfWhile* parse_if_stmt(OnyxParser* parser) {
 
     AstIfWhile* root_if = if_node;
 
-    if ((parser->curr + 1)->type == ':') {
-        if_node->local = make_node(AstLocal, Ast_Kind_Local);
-        if_node->local->token = expect_token(parser, Token_Type_Symbol);
+    if (peek_token(1)->type == ':') {
+        OnyxToken* local_sym = expect_token(parser, Token_Type_Symbol);
+        if_node->local = make_local(parser->allocator, local_sym, NULL);
 
         expect_token(parser, ':');
 
@@ -915,9 +916,9 @@ static AstIfWhile* parse_while_stmt(OnyxParser* parser) {
     AstIfWhile* while_node = make_node(AstIfWhile, Ast_Kind_While);
     while_node->token = while_token;
 
-    if ((parser->curr + 1)->type == ':') {
-        while_node->local = make_node(AstLocal, Ast_Kind_Local);
-        while_node->local->token = expect_token(parser, Token_Type_Symbol);
+    if (peek_token(1)->type == ':') {
+        OnyxToken* local_sym = expect_token(parser, Token_Type_Symbol);
+        while_node->local = make_local(parser->allocator, local_sym, NULL);
 
         expect_token(parser, ':');
 
@@ -951,8 +952,8 @@ static AstFor* parse_for_stmt(OnyxParser* parser) {
         for_node->by_pointer = 1;
     }
 
-    AstLocal* var_node = make_node(AstLocal, Ast_Kind_Local);
-    var_node->token = expect_token(parser, Token_Type_Symbol);
+    OnyxToken* local_sym = expect_token(parser, Token_Type_Symbol);
+    AstLocal* var_node = make_local(parser->allocator, local_sym, NULL);
 
     for_node->var = var_node;
 
@@ -969,9 +970,9 @@ static AstSwitch* parse_switch_stmt(OnyxParser* parser) {
 
     bh_arr_new(global_heap_allocator, switch_node->cases, 4);
 
-    if ((parser->curr + 1)->type == ':') {
-        switch_node->local = make_node(AstLocal, Ast_Kind_Local);
-        switch_node->local->token = expect_token(parser, Token_Type_Symbol);
+    if (peek_token(1)->type == ':') {
+        OnyxToken* local_sym = expect_token(parser, Token_Type_Symbol);
+        switch_node->local = make_local(parser->allocator, local_sym, NULL);
 
         expect_token(parser, ':');
 
@@ -1027,6 +1028,63 @@ static AstSwitch* parse_switch_stmt(OnyxParser* parser) {
     return switch_node;
 }
 
+static i32 parse_possible_compound_symbol_declaration(OnyxParser* parser, AstNode** ret) {
+    u32 token_offset = 0;
+    while (peek_token(token_offset)->type == Token_Type_Symbol) {
+        token_offset += 1;
+
+        if (peek_token(token_offset)->type != ',') break;
+        token_offset += 1;
+    }
+
+    if (peek_token(token_offset)->type != ':') return 0;
+
+    // At this point, we are sure it is a compound declaration.
+    AstCompound* local_compound = make_node(AstCompound, Ast_Kind_Compound);
+    bh_arr_new(global_heap_allocator, local_compound->exprs, token_offset / 2);
+
+    AstLocal* first_local = NULL;
+    AstLocal* prev_local  = NULL;
+
+    while (parser->curr->type == Token_Type_Symbol) {
+        if (parser->hit_unexpected_token) return 1;
+
+        OnyxToken* local_sym = expect_token(parser, Token_Type_Symbol);
+        AstLocal* new_local = make_local(parser->allocator, local_sym, NULL);
+
+        if (prev_local == NULL) {
+            first_local = new_local;
+        } else {
+            prev_local->next = (AstNode *) new_local;
+        }
+        prev_local = new_local;
+
+        AstNode* sym_node = make_symbol(parser->allocator, local_sym);
+        bh_arr_push(local_compound->exprs, (AstTyped *) sym_node);
+
+        if (parser->curr->type == ',')
+            expect_token(parser, ',');
+    }
+
+    expect_token(parser, ':');
+
+    if (parser->curr->type == '=') {
+        AstBinaryOp* assignment = make_binary_op(parser->allocator, Binary_Op_Assign, (AstTyped *) local_compound, NULL);
+        assignment->token = expect_token(parser, '=');
+        assignment->right = parse_compound_expression(parser, 0);
+
+        prev_local->next = (AstNode *) assignment;
+
+    } else {
+        AstType* type_for_all = parse_type(parser);
+        bh_arr_each(AstTyped *, local, local_compound->exprs)
+            (*local)->type_node = type_for_all;
+    }
+
+    *ret = (AstNode *) first_local;
+    return 1;
+}
+
 // Returns:
 //     0 - if this was not a symbol declaration.
 //     1 - if this was a local declaration.
@@ -1036,9 +1094,18 @@ static AstSwitch* parse_switch_stmt(OnyxParser* parser) {
 // <symbol> : <type> : <expr>
 // <symbol> := <expr>
 // <symbol> :: <expr>
+// <symbol> (, <symbol>)* : <type>
+// <symbol> (, <symbol>)* := <expr>
 static i32 parse_possible_symbol_declaration(OnyxParser* parser, AstNode** ret) {
+    // Has to start with a symbol to be a declaration
     if (parser->curr->type != Token_Type_Symbol) return 0;
-    if ((parser->curr + 1)->type != ':')         return 0;
+
+    // If the token after the symbol is a comma, assume this is a compound declaration.
+    if (peek_token(1)->type == ',') {
+        return parse_possible_compound_symbol_declaration(parser, ret);
+    }
+
+    if (peek_token(1)->type != ':')         return 0;
 
     OnyxToken* symbol = expect_token(parser, Token_Type_Symbol);
     expect_token(parser, ':');
@@ -1060,9 +1127,7 @@ static i32 parse_possible_symbol_declaration(OnyxParser* parser, AstNode** ret)
         type_node = parse_type(parser);
     }
 
-    AstLocal* local = make_node(AstLocal, Ast_Kind_Local);
-    local->token = symbol;
-    local->type_node = type_node;
+    AstLocal* local = make_local(parser->allocator, symbol, type_node);
     *ret = (AstNode *) local;
 
     if (parser->curr->type == '=') {
@@ -1304,19 +1369,15 @@ static AstNode* parse_statement(OnyxParser* parser) {
         }
 
         case Token_Type_Keyword_Use: {
-            // AstUse* use_node = make_node(AstUse, Ast_Kind_Use);
-            // use_node->token = expect_token(parser, Token_Type_Keyword_Use);
-            // use_node->expr = parse_expression(parser);
-
             needs_semicolon = 0;
+
             retval = (AstNode *) parse_use_stmt(parser);
             break;
         }
 
         case '#': {
             if (parse_possible_directive(parser, "context_scope")) {
-                AstLocal* context_tmp = make_node(AstLocal, Ast_Kind_Local);
-                context_tmp->type_node = builtin_context_variable->type_node;
+                AstLocal* context_tmp = make_local(parser->allocator, NULL, builtin_context_variable->type_node);
 
                 AstBinaryOp* assignment = make_node(AstBinaryOp, Ast_Kind_Binary_Op);
                 assignment->operation = Binary_Op_Assign;
@@ -1527,7 +1588,7 @@ static AstType* parse_type(OnyxParser* parser) {
                 while (parser->curr->type != ')') {
                     if (parser->hit_unexpected_token) return root;
 
-                    if ((parser->curr + 1)->type == ':') {
+                    if (peek_token(1)->type == ':') {
                         expect_token(parser, Token_Type_Symbol);
                         expect_token(parser, ':');
                     }
@@ -1792,8 +1853,8 @@ static void parse_function_params(OnyxParser* parser, AstFunction* func) {
         expect_token(parser, ':');
 
         curr_param.vararg_kind = VA_Kind_Not_VA;
-        curr_param.local = make_node(AstLocal, Ast_Kind_Param);
-        curr_param.local->token = symbol;
+        curr_param.local = make_local(parser->allocator, symbol, NULL);
+        curr_param.local->kind = Ast_Kind_Param;
 
         if (param_use) {
             curr_param.local->flags |= Ast_Flag_Param_Use;
index ed76107daafb4e6455767dbbb6c4345023f5336b..718d8942d2349b57af2fccb0ee9817e7120557b4 100644 (file)
@@ -576,6 +576,9 @@ Type* type_build_function_type(bh_allocator alloc, AstFunction* func) {
 
 Type* type_build_compound_type(bh_allocator alloc, AstCompound* compound) {
     i64 expr_count = bh_arr_length(compound->exprs);
+    fori (i, 0, expr_count) {
+        if (compound->exprs[i]->type == NULL) return NULL;
+    }
 
     Type* comp_type = bh_alloc(alloc, sizeof(Type) + sizeof(Type *) * expr_count);
     comp_type->kind = Type_Kind_Compound;
index 2fca21ddcb2e53665a30465e1fc52401d93b5208..639e8dbdb9be27108b013b428763e4966d0f8dbb 100644 (file)
@@ -78,13 +78,14 @@ b32 symbol_introduce(Scope* scope, OnyxToken* tkn, AstNode* symbol) {
 }
 
 b32 symbol_raw_introduce(Scope* scope, char* name, OnyxFilePos pos, AstNode* symbol) {
-    if (bh_table_has(AstNode *, scope->symbols, name)) {
-        if (bh_table_get(AstNode *, scope->symbols, name) != symbol) {
-            onyx_report_error(pos, "Redeclaration of symbol '%s'.", name);
-            return 0;
+    if (strcmp(name, "_")) {
+        if (bh_table_has(AstNode *, scope->symbols, name)) {
+            if (bh_table_get(AstNode *, scope->symbols, name) != symbol) {
+                onyx_report_error(pos, "Redeclaration of symbol '%s'.", name);
+                return 0;
+            }
+            return 1;
         }
-
-        return 1;
     }
 
     bh_table_put(AstNode *, scope->symbols, name, symbol);
index 24ff36abe12b4811efbfc4ff96ca45ea5837cfdf..8b7c6c4721f60dab4601c4a2bf2bf7a997780d85 100644 (file)
@@ -2445,10 +2445,15 @@ EMIT_FUNC(expression, AstTyped* expr) {
             assert(0);
     }
 
-    // FIX: This is going to be wrong for structs and compound types.
+    // FIX: This is going to be wrong for struct types.
     if (expr->flags & Ast_Flag_Expr_Ignored &&
         !type_results_in_void(expr->type)) {
-        WI(WI_DROP);
+         if (expr->type->kind == Type_Kind_Compound) {
+             fori (i, 0, expr->type->Compound.count)
+                 WI(WI_DROP);
+         } else {
+            WI(WI_DROP);
+        }
     }
 
     *pcode = code;
@@ -3234,6 +3239,12 @@ void emit_entity(Entity* ent) {
         case Entity_Type_Function_Header:
             if (!should_emit_function(ent->function)) break;
 
+            // bh_printf("%d -> %s:%d:%d\n",
+            //     module->next_func_idx,
+            //     ent->expr->token->pos.filename,
+            //     ent->expr->token->pos.line,
+            //     ent->expr->token->pos.column);
+            
             bh_imap_put(&module->index_map, (u64) ent->function, module->next_func_idx++);
             break;