started work on `#solidify`
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 25 Dec 2020 19:39:21 +0000 (13:39 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 25 Dec 2020 19:39:21 +0000 (13:39 -0600)
.vimspector.json
docs/todo
include/onyxastnodes.h
include/onyxlex.h
onyx
progs/poly_solidify.onyx [new file with mode: 0644]
src/onyxchecker.c
src/onyxlex.c
src/onyxparser.c
src/onyxsymres.c
src/onyxutils.c

index b1d77d0af774d9f3593db933ef098adfe65b339d..d9aef1fdcfbeffbd6fa4dbbd07a0355c8a5d2765 100644 (file)
@@ -6,7 +6,7 @@
                 "type": "cppdbg",
                 "request": "launch",
                 "program": "${workspaceFolder}/onyx",
-                "args": ["--verbose", "progs/odin_example.onyx"],
+                "args": ["--verbose", "progs/poly_solidify.onyx"],
                 "stopAtEntry": true,
                 "cwd": "~/dev/c/onyx",
                 "environment": [],
index d9924b44952428b6f9c4418e1bf4501dce27beb2..7a6faf3be931e42e037857a8f2d98c96e8de44fa 100644 (file)
--- a/docs/todo
+++ b/docs/todo
@@ -112,6 +112,8 @@ Language Cohesion:
 
     [ ] Add macros.
 
+    [ ] #solidify polymoprhic procedures.
+
 API Expansion:
     There are many different places where the standard API for WASI and JS
     backends could be improved. Here are some of the target areas.
index 1ecbee00ad17dd51c47c8325c376792fb9b21afd..82a7e3f2c8db6db01e2f9c4e97c937775e9f4ff0 100644 (file)
@@ -26,6 +26,8 @@ typedef struct AstStructLiteral AstStructLiteral;
 typedef struct AstArrayLiteral AstArrayLiteral;
 typedef struct AstRangeLiteral AstRangeLiteral;
 
+typedef struct AstDirectiveSolidify AstDirectiveSolidify;
+
 typedef struct AstReturn AstReturn;
 typedef struct AstJump AstJump;
 typedef struct AstUse AstUse;
@@ -152,6 +154,8 @@ typedef enum AstKind {
     Ast_Kind_Switch,
     Ast_Kind_Switch_Case,
 
+    Ast_Kind_Directive_Solidify,
+
     Ast_Kind_Count
 } AstKind;
 
@@ -508,6 +512,15 @@ struct AstIntrinsicCall {
     VarArgKind va_kind;
 };
 
+struct AstDirectiveSolidify {
+    AstTyped_base;
+
+    AstPolyProc* poly_proc;
+    bh_arr(AstPolySolution) known_polyvars;
+
+    AstNode* resolved_proc;
+};
+
 // Intruction Node
 struct AstReturn        { AstNode_base; AstTyped* expr; };
 struct AstJump          { AstNode_base; JumpType jump; u32 count; };
@@ -729,6 +742,9 @@ struct AstPolyParam {
 struct AstPolySolution {
     AstNode* poly_sym;
     Type*    type;
+
+    // If `type` is null, it is filled in with this type.
+    AstType* ast_type;
 };
 struct AstPolyProc {
     AstNode_base;
@@ -736,6 +752,8 @@ struct AstPolyProc {
     Scope *poly_scope;
     bh_arr(AstPolyParam) poly_params;
 
+    bh_arr(AstPolySolution) known_slns;
+
     AstFunction* base_func;
     bh_table(AstFunction *) concrete_funcs;
 };
@@ -911,6 +929,8 @@ typedef enum PolyProcLookupMethod {
 } PolyProcLookupMethod;
 AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lookup, ptr actual, OnyxFilePos pos);
 AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxFilePos pos);
+AstNode* polymorphic_proc_try_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxFilePos pos);
+
 
 AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(Type *) params, OnyxFilePos pos);
 
index 3e4cf559fb1183ae911ae3653614024af6580f81..645a5c93df2c5d787a0c03e95796ee6f357b831e 100644 (file)
@@ -111,4 +111,6 @@ OnyxTokenizer onyx_tokenizer_create(bh_allocator allocator, bh_file_contents *fc
 void onyx_tokenizer_free(OnyxTokenizer* tokenizer);
 void onyx_lex_tokens(OnyxTokenizer* tokenizer);
 
+b32 token_equals(OnyxToken* tkn1, OnyxToken* tkn2);
+
 #endif
diff --git a/onyx b/onyx
index 722bd518f0a25854d28a426c17642eea3dac1bbd..4777151a3e66e23a4bff5fdb082f623d16365f80 100755 (executable)
Binary files a/onyx and b/onyx differ
diff --git a/progs/poly_solidify.onyx b/progs/poly_solidify.onyx
new file mode 100644 (file)
index 0000000..f71cb85
--- /dev/null
@@ -0,0 +1,18 @@
+#include_file "core/std/wasi"
+
+use package core
+
+max_f32 :: #solidify math.max { T = f32 };
+
+compose :: proc (a: $A, f: proc (A) -> $B, g: proc (B) -> $C) -> C do return g(f(a));
+
+specific_compose :: #solidify compose { A = f32, B = f32, C = u32 };
+
+main :: proc (args: [] cstr) {
+       printf("max(1, 2) = %i\n", math.max(1, 2));
+       printf("max_f32(1.0, 2.0) = %f\n", max_f32(1, 2));
+
+       // printf("max_f32(1, 2) = %i\n", max_f32(cast(u32) 1, cast(u32) 2));
+
+
+}
\ No newline at end of file
index cfdef2e8f008e61cbccdae8d20a78927a19875e0..8a2610ed08d81c0964a2a912ed57ab14f8341e2b 100644 (file)
@@ -1283,6 +1283,10 @@ b32 check_expression(AstTyped** pexpr) {
             expr->flags |= Ast_Flag_Function_Used;
             break;
 
+        case Ast_Kind_Directive_Solidify:
+            *pexpr = (AstTyped *) ((AstDirectiveSolidify *) expr)->resolved_proc;
+            break;
+
         case Ast_Kind_StrLit: break;
         case Ast_Kind_File_Contents: break;
         case Ast_Kind_Overloaded_Function: break;
index 9a678ad9210890bf00c873b6d06295d72df3c249..18f020d5d5717b33acb2247674714f8cfa6cd55f 100644 (file)
@@ -437,3 +437,10 @@ void onyx_lex_tokens(OnyxTokenizer* tokenizer) {
     lexer_lines_processed += tokenizer->line_number - 1;
     lexer_tokens_processed += bh_arr_length(tokenizer->tokens);
 }
+
+b32 token_equals(OnyxToken* tkn1, OnyxToken* tkn2) {
+    if (tkn1->length != tkn2->length) return 0;
+    fori (i, 0, tkn1->length)
+        if (tkn1->text[i] != tkn2->text[i]) return 0;
+    return 1;
+}
index 3066b560b2bcb717c35fcf65accc430447aa8d0c..1b034777b89f43ea46f13ceefc69b79657ce1809 100644 (file)
@@ -531,6 +531,39 @@ static AstTyped* parse_factor(OnyxParser* parser) {
                 retval = (AstTyped *) alias;
                 break;
             }
+            else if (parse_possible_directive(parser, "solidify")) {
+                AstDirectiveSolidify* solid = make_node(AstDirectiveSolidify, Ast_Kind_Directive_Solidify);
+                solid->token = parser->curr - 1;
+
+                solid->poly_proc = (AstPolyProc *) parse_factor(parser);
+
+                solid->known_polyvars = NULL;
+                bh_arr_new(global_heap_allocator, solid->known_polyvars, 2);
+
+                expect_token(parser, '{');
+                while (parser->curr->type != '}') {
+                    if (parser->hit_unexpected_token) break;
+
+                    AstNode* poly_var = make_node(AstNode, Ast_Kind_Symbol);
+                    poly_var->token = expect_token(parser, Token_Type_Symbol);
+
+                    expect_token(parser, '=');
+                    AstType* poly_type = parse_type(parser);
+
+                    bh_arr_push(solid->known_polyvars, ((AstPolySolution) {
+                        .poly_sym = poly_var,
+                        .ast_type = poly_type,
+                        .type     = NULL
+                    }));
+
+                    if (parser->curr->type != '}')
+                        expect_token(parser, ',');
+                }
+                expect_token(parser, '}');
+
+                retval = (AstTyped *) solid;
+                break;
+            }
 
             onyx_report_error(parser->curr->pos, "invalid directive in expression.");
             return NULL;
index 185480c75c91113e1597dc3534b134f1117f3281..e145dab67f275ab44626ba69bfab8c91e28e2e64 100644 (file)
@@ -3,7 +3,7 @@
 #include "onyxparser.h"
 #include "onyxutils.h"
 #include "onyxastnodes.h"
-
+#include "onyxerrors.h"
 
 static void scope_enter(Scope* new_scope);
 static void scope_leave();
@@ -21,6 +21,7 @@ static void symres_while(AstIfWhile* whilenode);
 static void symres_for(AstFor* fornode);
 static void symres_switch(AstSwitch* switchnode);
 static void symres_use(AstUse* use);
+static void symres_directive_solidify(AstDirectiveSolidify** psolid);
 static void symres_statement_chain(AstNode** walker);
 static b32  symres_statement(AstNode** stmt);
 static void symres_block(AstBlock* block);
@@ -468,6 +469,10 @@ static void symres_expression(AstTyped** expr) {
             symres_array_literal((AstArrayLiteral *)(*expr));
             break;
 
+        case Ast_Kind_Directive_Solidify:
+            symres_directive_solidify((AstDirectiveSolidify **) expr);
+            break;
+
         default: break;
     }
 }
@@ -593,6 +598,30 @@ cannot_use:
     onyx_report_error(use->token->pos, "Cannot use this.");
 }
 
+static void symres_directive_solidify(AstDirectiveSolidify** psolid) {
+    AstDirectiveSolidify* solid = *psolid;
+    if (solid->resolved_proc != NULL)
+        *psolid = (AstDirectiveSolidify *) solid->resolved_proc;
+
+    symres_expression((AstTyped **) &solid->poly_proc);
+    if (!solid->poly_proc || solid->poly_proc->kind != Ast_Kind_Polymorphic_Proc) {
+        onyx_report_error(solid->token->pos, "Expected polymorphic procedure in #solidify directive.");
+        return;
+    }
+
+    bh_arr_each(AstPolySolution, sln, solid->known_polyvars) {
+        sln->ast_type = symres_type(sln->ast_type);
+        sln->type = type_build_from_ast(semstate.node_allocator, sln->ast_type);
+        if (onyx_has_errors()) return;
+    }
+
+    solid->resolved_proc = polymorphic_proc_try_solidify(solid->poly_proc, solid->known_polyvars, solid->token->pos);
+
+    // NOTE: Not a DirectiveSolidify.
+    *psolid = (AstDirectiveSolidify *) solid->resolved_proc;
+    return;
+}
+
 // NOTE: Returns 1 if the statment should be removed
 static b32 symres_statement(AstNode** stmt) {
     switch ((*stmt)->kind) {
index 86562e25f94c717f7b29abedb9097f4f282672ae..a43d497dca62804d5f72b67634049da4d66c9aa7 100644 (file)
@@ -536,7 +536,18 @@ AstFunction* polymorphic_proc_lookup(AstPolyProc* pp, PolyProcLookupMethod pp_lo
     bh_arr(AstPolySolution) slns = NULL;
     bh_arr_new(global_heap_allocator, slns, bh_arr_length(pp->poly_params));
 
+    bh_arr_each(AstPolySolution, known_sln, pp->known_slns) bh_arr_push(slns, *known_sln);
+
     bh_arr_each(AstPolyParam, param, pp->poly_params) {
+        b32 already_solved = 0;
+        bh_arr_each(AstPolySolution, known_sln, pp->known_slns) {
+            if (token_equals(param->poly_sym->token, known_sln->poly_sym->token)) {
+                already_solved = 1;
+                break;
+            }
+        }
+        if (already_solved) continue;
+
         Type* actual_type;
 
         if (pp_lookup == PPLM_By_Call) {
@@ -654,6 +665,55 @@ AstFunction* polymorphic_proc_solidify(AstPolyProc* pp, bh_arr(AstPolySolution)
     return func;
 }
 
+// NOTE: This can return either a AstFunction or an AstPolyProc, depending if enough parameters were
+// supplied to remove all the polymorphic variables from the function.
+AstNode* polymorphic_proc_try_solidify(AstPolyProc* pp, bh_arr(AstPolySolution) slns, OnyxFilePos pos) {
+    i32 valid_argument_count = 0;
+
+    bh_arr_each(AstPolySolution, sln, slns) {
+        b32 found_match = 0;
+
+        bh_arr_each(AstPolyParam, param, pp->poly_params) {
+            if (token_equals(sln->poly_sym->token, param->poly_sym->token)) {
+                found_match = 1;
+                break;
+            }
+        }
+
+        if (found_match) {
+            valid_argument_count++;
+        } else {
+            onyx_report_error(pos, "'%b' is not a type variable of '%b'.",
+                sln->poly_sym->token->text, sln->poly_sym->token->length,
+                pp->token->text, pp->token->length);
+            return (AstNode *) pp;
+        }
+    }
+
+    if (valid_argument_count == bh_arr_length(pp->poly_params)) {
+        return (AstNode *) polymorphic_proc_solidify(pp, slns, pos);
+
+    } else {
+        // HACK: Some of these initializations assume that the entity for this polyproc has
+        // made it through the symbol resolution phase.
+        //                                                    - brendanfh 2020/12/25
+        AstPolyProc* new_pp = onyx_ast_node_new(semstate.node_allocator, sizeof(AstPolyProc), Ast_Kind_Polymorphic_Proc);
+        new_pp->token = pp->token;                            // TODO: Change this to be the solidify->token
+        new_pp->base_func = pp->base_func;
+        new_pp->poly_scope = new_pp->poly_scope;
+        new_pp->flags = pp->flags;
+        new_pp->poly_params = pp->poly_params;
+
+        new_pp->known_slns = NULL;
+        bh_arr_new(global_heap_allocator, new_pp->known_slns, bh_arr_length(pp->known_slns) + bh_arr_length(slns));
+
+        bh_arr_each(AstPolySolution, sln, pp->known_slns) bh_arr_push(new_pp->known_slns, *sln);
+        bh_arr_each(AstPolySolution, sln, slns)           bh_arr_push(new_pp->known_slns, *sln);
+
+        return (AstNode *) new_pp;
+    }
+}
+
 
 AstStructType* polymorphic_struct_lookup(AstPolyStructType* ps_type, bh_arr(Type *) params, OnyxFilePos pos) {
     // @Cleanup