array types are polymorphic on size
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 7 Jan 2021 22:32:41 +0000 (16:32 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Thu, 7 Jan 2021 22:32:41 +0000 (16:32 -0600)
bin/onyx
include/onyxastnodes.h
onyx.exe
src/onyxparser.c
src/onyxtypes.c
src/onyxutils.c

index b2d10f0dfedb6584c5886b9d6f72090f8e300798..a62f136fbe4fdfd9e010430cbb4114a9d35adabb 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 4ade1191565fd0908b8aef0f9da8447bed2b5c0b..42485c5a4f5b2be8c52361280708463e391fc3cd 100644 (file)
@@ -743,12 +743,25 @@ struct AstPolyParam {
     // The parameter index where the polymorphic variable occurs.
     u64 idx;
 };
+
+typedef enum PolySolutionKind {
+    PSK_Type,
+    PSK_Value,
+} PolySolutionKind;
+
 struct AstPolySolution {
+    PolySolutionKind kind;
     AstNode* poly_sym;
-    Type*    type;
 
-    // If `type` is null, it is filled in with this type.
-    AstType* ast_type;
+    union {
+        struct {
+            // If `type` is null, it is filled in with this type.
+            AstType* ast_type;
+            Type*    type;
+        };
+
+        AstTyped* value;
+    };
 };
 struct AstPolyProc {
     AstNode_base;
@@ -924,6 +937,7 @@ void initialize_builtins(bh_allocator a, ProgramInfo* prog);
 AstTyped* ast_reduce(bh_allocator a, AstTyped* node);
 AstNode* ast_clone(bh_allocator a, void* n);
 void promote_numlit_to_larger(AstNumLit* num);
+AstNumLit* make_int_literal(bh_allocator, i64 value);
 b32 convert_numlit_to_type(AstNumLit* num, Type* type);
 b32 type_check_or_auto_cast(AstTyped** pnode, Type* type);
 Type* resolve_expression_type(AstTyped* node);
index 7258d4213114a631c7461b356aef196b1028d84d..fd15f1d2b55c8bbf19c6af23bce4e3f59509ccc1 100644 (file)
Binary files a/onyx.exe and b/onyx.exe differ
index 08e9ec83c39bbe70d92fc18e1115bac52830f613..c7b4cd68811c31687d38e674443eb517105abf15 100644 (file)
@@ -114,7 +114,7 @@ static void add_node_to_process(OnyxParser* parser, AstNode* node) {
 }
 
 
-static AstNumLit* make_int_literal(bh_allocator a, i64 i) {
+AstNumLit* make_int_literal(bh_allocator a, i64 i) {
     AstNumLit* num = onyx_ast_node_new(a, sizeof(AstNumLit), Ast_Kind_NumLit);
     if (bh_abs(i) >= ((u64) 1 << 32))
         num->type_node = (AstType *) &basic_type_i64;
@@ -536,7 +536,11 @@ static AstTyped* parse_factor(OnyxParser* parser) {
                     expect_token(parser, '=');
                     AstType* poly_type = parse_type(parser);
 
+                    PolySolutionKind sln_kind = PSK_Type;
+                    if (!node_is_type((AstNode *) poly_type)) sln_kind = PSK_Value;
+
                     bh_arr_push(solid->known_polyvars, ((AstPolySolution) {
+                        .kind     = sln_kind,
                         .poly_sym = poly_var,
                         .ast_type = poly_type,
                         .type     = NULL
@@ -1362,6 +1366,35 @@ static AstBlock* parse_block(OnyxParser* parser) {
     return block;
 }
 
+static void parse_polymorphic_variable(OnyxParser* parser, AstType*** next_insertion) {
+    bh_arr(AstPolyParam) pv = NULL;
+
+    if (parser->polymorph_context.poly_params == NULL)
+        onyx_report_error(parser->curr->pos, "polymorphic variable not valid here.");
+    else
+        pv = *parser->polymorph_context.poly_params;
+
+    consume_token(parser);
+
+    AstNode* symbol_node = make_node(AstNode, Ast_Kind_Symbol);
+    symbol_node->token = expect_token(parser, Token_Type_Symbol);
+
+    **next_insertion = (AstType *) symbol_node;
+    *next_insertion = NULL;
+
+    if (pv != NULL) {
+        bh_arr_push(pv, ((AstPolyParam) {
+            .poly_sym = symbol_node,
+
+            // These will be filled out by function_params()
+            .type_expr = NULL,
+            .idx = -1,
+        }));
+
+        *parser->polymorph_context.poly_params = pv;
+    }
+}
+
 // <symbol>
 // '^' <type>
 static AstType* parse_type(OnyxParser* parser) {
@@ -1380,7 +1413,7 @@ static AstType* parse_type(OnyxParser* parser) {
         }
 
         else if (parser->curr->type == '[') {
-            AstSliceType *new;
+            AstType *new;
             OnyxToken *open_bracket = expect_token(parser, '[');
 
             if (parser->curr->type == ']') {
@@ -1395,12 +1428,18 @@ static AstType* parse_type(OnyxParser* parser) {
             } else {
                 new = make_node(AstArrayType, Ast_Kind_Array_Type);
                 new->token = open_bracket;
-                ((AstArrayType *) new)->count_expr = parse_expression(parser);
+
+                if (parser->curr->type == '$') {
+                    AstType** insertion = (AstType **) &((AstArrayType *) new)->count_expr;
+                    parse_polymorphic_variable(parser, &insertion);
+                } else {
+                    ((AstArrayType *) new)->count_expr = parse_expression(parser);
+                }
             }
 
             expect_token(parser, ']');
             *next_insertion = (AstType *) new;
-            next_insertion = &new->elem;
+            next_insertion = &((AstSliceType *) new)->elem;
         }
 
         else if (parser->curr->type == Token_Type_Keyword_Proc) {
@@ -1444,32 +1483,7 @@ static AstType* parse_type(OnyxParser* parser) {
         }
 
         else if (parser->curr->type == '$') {
-            bh_arr(AstPolyParam) pv = NULL;
-
-            if (parser->polymorph_context.poly_params == NULL)
-                onyx_report_error(parser->curr->pos, "polymorphic variable not valid here.");
-            else
-                pv = *parser->polymorph_context.poly_params;
-
-            consume_token(parser);
-
-            AstNode* symbol_node = make_node(AstNode, Ast_Kind_Symbol);
-            symbol_node->token = expect_token(parser, Token_Type_Symbol);
-
-            *next_insertion = (AstType *) symbol_node;
-            next_insertion = NULL;
-
-            if (pv != NULL) {
-                bh_arr_push(pv, ((AstPolyParam) {
-                    .poly_sym = symbol_node,
-
-                    // These will be filled out by function_params()
-                    .type_expr = NULL,
-                    .idx = -1,
-                }));
-
-                *parser->polymorph_context.poly_params = pv;
-            }
+            parse_polymorphic_variable(parser, &next_insertion);
         }
 
         else if (parser->curr->type == Token_Type_Symbol) {
@@ -1521,6 +1535,13 @@ static AstType* parse_type(OnyxParser* parser) {
             next_insertion = NULL;
         }
 
+        else if (parse_possible_directive(parser, "value")) {
+            // :ValueDirectiveHack
+            *next_insertion = (AstType *) parse_expression(parser);
+            next_insertion = NULL;
+            break;
+        }
+
         else {
             onyx_report_error(parser->curr->pos, "unexpected token '%b'.", parser->curr->text, parser->curr->length);
             consume_token(parser);
index 3d8bb299f180536a300039c8d463d181d3067d7c..e23f163e0e97821bc045143aaf14bb2eb7f549a2 100644 (file)
@@ -460,7 +460,9 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
 
         case Ast_Kind_Poly_Struct_Type:
             // @Cleanup: Replace this with a proper onyx_report_error. - brendanfh 2020/09/14
-            assert(("Polymorphic struct used without instantiation.", 0));
+            onyx_report_error(type_node->token->pos,
+                "This structure is polymorphic, which means you need to provide arguments to it to make it a concrete structure. "
+                "This error message is probably in the wrong place, so look through your code for uses of this struct.");
             break;
 
         case Ast_Kind_Poly_Call_Type: {
index befb3f6e89cde8a6205bf9eea9e98a41b79bcff8..54e09c238fbdff2e1961bb9d20ed6c6759d12a4a 100644 (file)
@@ -428,16 +428,29 @@ void promote_numlit_to_larger(AstNumLit* num) {
     }
 }
 
+typedef struct PolySolveResult {
+    PolySolutionKind kind;
+    union {
+        AstTyped* value;
+        Type*     actual;
+    };
+} PolySolveResult;
+
 typedef struct PolySolveElem {
     AstType* type_expr;
-    Type*    actual;
+
+    PolySolutionKind kind;
+    union {
+        AstTyped* value;
+        Type*     actual;
+    };
 } PolySolveElem;
 
-static Type* solve_poly_type(AstNode* target, AstType* type_expr, Type* actual) {
+static PolySolveResult solve_poly_type(AstNode* target, AstType* type_expr, Type* actual) {
     bh_arr(PolySolveElem) elem_queue = NULL;
     bh_arr_new(global_heap_allocator, elem_queue, 4);
 
-    Type* result = NULL;
+    PolySolveResult result = { -1, { NULL } };
 
     bh_arr_push(elem_queue, ((PolySolveElem) {
         .type_expr = type_expr,
@@ -449,7 +462,12 @@ static Type* solve_poly_type(AstNode* target, AstType* type_expr, Type* actual)
         bh_arr_deleten(elem_queue, 0, 1);
 
         if (elem.type_expr == (AstType *) target) {
-            result = elem.actual;
+            result.kind = elem.kind;
+            if (result.kind == PSK_Type) {
+                result.actual = elem.actual;
+            } else {
+                result.value = elem.value;
+            }
             break;
         }
 
@@ -459,17 +477,24 @@ static Type* solve_poly_type(AstNode* target, AstType* type_expr, Type* actual)
 
                 bh_arr_push(elem_queue, ((PolySolveElem) {
                     .type_expr = ((AstPointerType *) elem.type_expr)->elem,
+                    .kind = PSK_Type,
                     .actual = elem.actual->Pointer.elem,
                 }));
                 break;
             }
 
             case Ast_Kind_Array_Type: {
-                // TODO: Add check for same size array
                 if (elem.actual->kind != Type_Kind_Array) break;
 
+                bh_arr_push(elem_queue, ((PolySolveElem) {
+                    .type_expr = (AstType*) ((AstArrayType *) elem.type_expr)->count_expr,
+                    .kind = PSK_Value,
+                    .value = (AstTyped *) make_int_literal(semstate.node_allocator, elem.actual->Array.count)
+                }));
+
                 bh_arr_push(elem_queue, ((PolySolveElem) {
                     .type_expr = ((AstArrayType *) elem.type_expr)->elem,
+                    .kind = PSK_Type,
                     .actual = elem.actual->Array.elem,
                 }));
                 break;
@@ -480,6 +505,7 @@ static Type* solve_poly_type(AstNode* target, AstType* type_expr, Type* actual)
 
                 bh_arr_push(elem_queue, ((PolySolveElem) {
                     .type_expr = ((AstSliceType *) elem.type_expr)->elem,
+                    .kind = PSK_Type,
                     .actual = elem.actual->Slice.ptr_to_data->Pointer.elem,
                 }));
                 break;
@@ -490,6 +516,7 @@ static Type* solve_poly_type(AstNode* target, AstType* type_expr, Type* actual)
 
                 bh_arr_push(elem_queue, ((PolySolveElem) {
                     .type_expr = ((AstDynArrType *) elem.type_expr)->elem,
+                    .kind = PSK_Type,
                     .actual = elem.actual->DynArray.ptr_to_data->Pointer.elem,
                 }));
                 break;
@@ -498,6 +525,7 @@ static Type* solve_poly_type(AstNode* target, AstType* type_expr, Type* actual)
             case Ast_Kind_VarArg_Type:
                 bh_arr_push(elem_queue, ((PolySolveElem) {
                     .type_expr = ((AstVarArgType *) elem.type_expr)->elem,
+                    .kind = PSK_Type,
                     .actual = actual,
                 }));
                 break;
@@ -510,12 +538,14 @@ static Type* solve_poly_type(AstNode* target, AstType* type_expr, Type* actual)
                 fori (i, 0, (i64) ft->param_count) {
                     bh_arr_push(elem_queue, ((PolySolveElem) {
                         .type_expr = ft->params[i],
+                        .kind = PSK_Type,
                         .actual = elem.actual->Function.params[i],
                     }));
                 }
 
                 bh_arr_push(elem_queue, ((PolySolveElem) {
                     .type_expr = ft->return_type,
+                    .kind = PSK_Type,
                     .actual = elem.actual->Function.return_type,
                 }));
 
@@ -531,6 +561,7 @@ static Type* solve_poly_type(AstNode* target, AstType* type_expr, Type* actual)
                 fori (i, 0, bh_arr_length(pt->params)) {
                     bh_arr_push(elem_queue, ((PolySolveElem) {
                         .type_expr = pt->params[i],
+                        .kind = PSK_Type,
                         .actual = elem.actual->Struct.poly_args[i],
                     }));
                 }
@@ -594,17 +625,33 @@ AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lo
             return NULL;
         }
 
-        Type* resolved_type = solve_poly_type(param->poly_sym, param->type_expr, actual_type);
+        PolySolveResult resolved = solve_poly_type(param->poly_sym, param->type_expr, actual_type);
 
-        if (resolved_type == NULL) {
-            onyx_report_error(pos, "Unable to match polymorphic procedure type with actual type, '%s'.", type_get_name(actual_type));
-            return NULL;
-        }
+        switch (resolved.kind) {
+            case -1:
+                onyx_report_error(pos,
+                    "Unable to solve for polymoprhic variable '%b', using the type '%s'.",
+                    param->poly_sym->token->text,
+                    param->poly_sym->token->length,
+                    type_get_name(actual_type));
+                return NULL;
+
+            case PSK_Type:
+                bh_arr_push(slns, ((AstPolySolution) {
+                    .kind     = PSK_Type,
+                    .poly_sym = param->poly_sym,
+                    .type     = resolved.actual,
+                }));
+                break;
 
-        bh_arr_push(slns, ((AstPolySolution) {
-            .poly_sym = param->poly_sym,
-            .type     = resolved_type
-        }));
+            case PSK_Value:
+                bh_arr_push(slns, ((AstPolySolution) {
+                    .kind     = PSK_Value,
+                    .poly_sym = param->poly_sym,
+                    .value    = resolved.value,
+                }));
+                break;
+        }
     }
 
     AstFunction* result = polymorphic_proc_solidify(pp, slns, pos);
@@ -613,6 +660,34 @@ AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lo
     return result;
 }
 
+// NOTE: This might return a volatile string. Do not store it without copying it.
+static char* build_poly_solution_key(AstPolySolution* sln) {
+    static char buffer[128];
+
+    if (sln->kind == PSK_Type) {
+        return (char *) type_get_unique_name(sln->type);
+    }
+
+    else if (sln->kind == PSK_Value) {
+        fori (i, 0, 128) buffer[i] = 0;
+
+        if (sln->value->kind == Ast_Kind_NumLit) {
+            strncat(buffer, "NUMLIT:", 127);
+            strncat(buffer, bh_bprintf("%l", ((AstNumLit *) sln->value)->value.l), 127);
+
+        } else {
+            // HACK: For now, the value pointer is just used. This means that
+            // sometimes, even through the solution is the same, it won't be
+            // stored the same.
+            bh_snprintf(buffer, 128, "%p", sln->value);
+        }
+
+        return buffer;
+    }
+
+    return NULL;
+}
+
 // NOTE: This returns a volatile string. Do not store it without copying it.
 static char* build_polyproc_unique_key(bh_arr(AstPolySolution) slns) {
     static char key_buf[1024];
@@ -623,7 +698,7 @@ static char* build_polyproc_unique_key(bh_arr(AstPolySolution) slns) {
 
         strncat(key_buf, sln->poly_sym->token->text, 1023);
         strncat(key_buf, "=", 1023);
-        strncat(key_buf, type_get_unique_name(sln->type), 1023);
+        strncat(key_buf, build_poly_solution_key(sln), 1023);
         strncat(key_buf, ";", 1023);
 
         token_toggle_end(sln->poly_sym->token);
@@ -645,10 +720,21 @@ AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution)
 
     Scope* poly_scope = scope_create(semstate.node_allocator, pp->poly_scope, pos);
     bh_arr_each(AstPolySolution, sln, slns) {
-        AstTypeRawAlias* raw = onyx_ast_node_new(semstate.node_allocator, sizeof(AstTypeRawAlias), Ast_Kind_Type_Raw_Alias);
-        raw->to = sln->type;
+        AstNode *node = NULL;
+
+        switch (sln->kind) {
+            case PSK_Type:
+                node = onyx_ast_node_new(semstate.node_allocator, sizeof(AstTypeRawAlias), Ast_Kind_Type_Raw_Alias);
+                ((AstTypeRawAlias *) node)->to = sln->type;
+                break;
+
+            case PSK_Value:
+                // CLEANUP: Maybe clone this?
+                node = (AstNode *) sln->value;
+                break;
+        }
 
-        symbol_introduce(poly_scope, sln->poly_sym->token, (AstNode *) raw);
+        symbol_introduce(poly_scope, sln->poly_sym->token, node);
     }
 
     AstFunction* func = (AstFunction *) ast_clone(semstate.node_allocator, pp->base_func);