From: Brendan Hansen Date: Thu, 7 Jan 2021 22:32:41 +0000 (-0600) Subject: array types are polymorphic on size X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=0ada40003878efafe6d97b08d4d6b1df9852b7cf;p=onyx.git array types are polymorphic on size --- diff --git a/bin/onyx b/bin/onyx index b2d10f0d..a62f136f 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index 4ade1191..42485c5a 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -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); diff --git a/onyx.exe b/onyx.exe index 7258d421..fd15f1d2 100644 Binary files a/onyx.exe and b/onyx.exe differ diff --git a/src/onyxparser.c b/src/onyxparser.c index 08e9ec83..c7b4cd68 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -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; + } +} + // // '^' 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); diff --git a/src/onyxtypes.c b/src/onyxtypes.c index 3d8bb299..e23f163e 100644 --- a/src/onyxtypes.c +++ b/src/onyxtypes.c @@ -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: { diff --git a/src/onyxutils.c b/src/onyxutils.c index befb3f6e..54e09c23 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -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);