added '#export_name'
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 30 Sep 2022 22:42:14 +0000 (17:42 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Fri, 30 Sep 2022 22:42:14 +0000 (17:42 -0500)
compiler/include/astnodes.h
compiler/src/astnodes.c
compiler/src/checker.c
compiler/src/clone.c
compiler/src/parser.c
compiler/src/symres.c
compiler/src/wasm_emit.c
core/alloc/arena.onyx
tests/aoc-2021/day18.onyx

index 5246f1147bd3c005c4921c23a5cb98c69f25e284..246d4dc1b09a672c351f584ef6afad16dc404418 100644 (file)
@@ -43,6 +43,7 @@
     NODE(DirectiveLibrary)     \
     NODE(DirectiveRemove)      \
     NODE(DirectiveFirst)       \
+    NODE(DirectiveExportName)  \
                                \
     NODE(Return)               \
     NODE(Jump)                 \
@@ -219,6 +220,7 @@ typedef enum AstKind {
     Ast_Kind_Directive_Library,
     Ast_Kind_Directive_Remove,
     Ast_Kind_Directive_First,
+    Ast_Kind_Directive_Export_Name,
     Ast_Kind_Call_Site,
 
     Ast_Kind_Code_Block,
@@ -1337,6 +1339,13 @@ struct AstDirectiveFirst {
     AstFor *for_node;
 };
 
+struct AstDirectiveExportName {
+    AstTyped_base;
+    AstFunction *func;
+    AstStrLit   *name;
+    b32 created_export_entity : 1;
+};
+
 struct AstNote {
     AstNode_base;
 };
index 7c9d79242dd584275e26e51072e816fb53e6944b..54837f9d908c9007d4e6be67ac6550f637e7c8bf 100644 (file)
@@ -99,6 +99,7 @@ static const char* ast_node_names[] = {
     "LIBRARY",
     "REMOVE",
     "FIRST",
+    "EXPORT NAME",
     "CALL SITE",
 
     "CODE BLOCK",
index ed8674a7538c150f62be0d2168ed86dcb0369e60..f3e4d26886a1a980acf9819618e8f5569b855add 100644 (file)
@@ -109,6 +109,7 @@ CheckStatus check_constraint(AstConstraint *constraint);
 CheckStatus check_constraint_context(ConstraintContext *cc, Scope *scope, OnyxFilePos pos);
 CheckStatus check_polyquery(AstPolyQuery *query);
 CheckStatus check_directive_first(AstDirectiveFirst *first);
+CheckStatus check_directive_export_name(AstDirectiveExportName *ename);
 
 // HACK HACK HACK
 b32 expression_types_must_be_known = 0;
@@ -2017,6 +2018,10 @@ CheckStatus check_expression(AstTyped** pexpr) {
             if (expr->type == NULL) YIELD(expr->token->pos, "Waiting to know constraint sentinel's type.");
             break;
 
+        case Ast_Kind_Directive_Export_Name:
+            retval = check_directive_export_name((AstDirectiveExportName *) expr);
+            break;
+
         case Ast_Kind_StrLit: break;
         case Ast_Kind_File_Contents: break;
         case Ast_Kind_Overloaded_Function: break;
@@ -2131,6 +2136,69 @@ CheckStatus check_directive_first(AstDirectiveFirst *first) {
     return Check_Success;
 }
 
+CheckStatus check_directive_export_name(AstDirectiveExportName *ename) {
+    if (ename->func->kind != Ast_Kind_Function) {
+        ERROR(ename->token->pos, "#export_name can only be used on functions.");
+    }
+
+    if (ename->type == NULL) YIELD(ename->token->pos, "This should never yield here...");
+
+    ename->flags |= Ast_Flag_Comptime;
+
+    //
+    // TODO: Cleanup this code. I feel like there should be some convenience functions
+    // to make string literals, tokens, exports, etc...
+    if (ename->func->exported_name == NULL) {
+        if (ename->created_export_entity) {
+            return Check_Yield_Macro;
+        }
+
+        // In this case, we know the function is not exported.
+        assert(ename->func->is_exported == 0);
+
+        char *random_name = bh_alloc_array(context.ast_alloc, char, 16);
+        random_name[15] = 0;
+        fori (i, 0, 15) random_name[i] = (rand() % 26) + 'a';
+
+        OnyxToken *name_token = bh_alloc_item(context.ast_alloc, OnyxToken);
+        memset(name_token, 0, sizeof(*name_token));
+        name_token->type = Token_Type_Literal_String;
+        name_token->length = 15;
+        name_token->text = random_name;
+
+        AstStrLit* name = bh_alloc_item(context.ast_alloc, AstStrLit);
+        memset(name, 0, sizeof(AstStrLit));
+        name->kind  = Ast_Kind_StrLit;
+        name->token = name_token;
+        name->type_node = builtin_string_type;
+
+        add_entities_for_node(NULL, (AstNode *) name, NULL, NULL);
+        ename->name = name;
+
+        AstDirectiveExport *export = onyx_ast_node_new(context.ast_alloc, sizeof(AstDirectiveExport), Ast_Kind_Directive_Export);
+        export->token = ename->token;
+        export->export_name_expr = (AstTyped *) name;
+        export->export = (AstTyped *) ename->func;
+
+        add_entities_for_node(NULL, (AstNode *) export, NULL, NULL);
+
+        ename->created_export_entity = 1;
+        return Check_Yield_Macro;
+
+    } else {
+        AstStrLit* name = bh_alloc_item(context.ast_alloc, AstStrLit);
+        memset(name, 0, sizeof(AstStrLit));
+        name->kind  = Ast_Kind_StrLit;
+        name->token = ename->func->exported_name;
+        name->type_node = builtin_string_type;
+
+        add_entities_for_node(NULL, (AstNode *) name, NULL, NULL);
+        ename->name = name;
+    }
+
+    return Check_Success;
+}
+
 CheckStatus check_statement(AstNode** pstmt) {
     AstNode* stmt = *pstmt;
 
@@ -2773,6 +2841,11 @@ CheckStatus check_process_directive(AstNode* directive) {
         }
 
         export->export_name = export->export_name_expr->token;
+
+        AstFunction *exported_func = (AstFunction *) export->export;
+        if (exported_func->exported_name == NULL) {
+            exported_func->exported_name = export->export_name;
+        }
     }
 
     if (directive->kind == Ast_Kind_Directive_Init) {
index 2c3a49fc729e6f533561957c7d76ad3381e6b2a3..6b708f8e781ec26e6c54c57818348c305a2af230 100644 (file)
@@ -114,6 +114,7 @@ static inline i32 ast_kind_to_size(AstNode* node) {
         case Ast_Kind_Constraint: return sizeof(AstConstraint);
         case Ast_Kind_Directive_Remove: return sizeof(AstDirectiveRemove);
         case Ast_Kind_Directive_First: return sizeof(AstDirectiveFirst);
+        case Ast_Kind_Directive_Export_Name: return sizeof(AstDirectiveExportName);
         case Ast_Kind_Count: return 0;
     }
 
@@ -577,6 +578,10 @@ AstNode* ast_clone(bh_allocator a, void* n) {
             C(AstFileContents, filename_expr);
             E(nn);
             break;
+
+        case Ast_Kind_Directive_Export_Name:
+            C(AstDirectiveExportName, func);
+            break;
     }
 
     clone_depth--;
index 6e6f3b0e7cd8ba8c5bbce309b1bf7b2ac0a8738c..912312e9829f707a23862e44f5a21dbd078fcf51 100644 (file)
@@ -764,6 +764,15 @@ static AstTyped* parse_factor(OnyxParser* parser) {
                 retval = (AstTyped *) first;
                 break;
             }
+            else if (parse_possible_directive(parser, "export_name")) {
+                AstDirectiveExportName *export_name = make_node(AstDirectiveExportName, Ast_Kind_Directive_Export_Name);
+                export_name->token = parser->curr - 1;
+                export_name->func  = (AstFunction *) parse_factor(parser);
+                export_name->type_node = builtin_string_type;
+                
+                retval = (AstTyped *) export_name;
+                break;
+            }
 
             onyx_report_error(parser->curr->pos, Error_Critical, "Invalid directive in expression.");
             return NULL;
index e8433bd1a6d92963d225a9a08c5ce1020b8c6c4b..1fc9c4e5de7e5afc58bf1c07bb5e5cbeeaedc6be 100644 (file)
@@ -646,6 +646,12 @@ static SymresStatus symres_expression(AstTyped** expr) {
             break;
         }
 
+        case Ast_Kind_Directive_Export_Name: {
+            AstDirectiveExportName *ename = (AstDirectiveExportName *) *expr;
+            SYMRES(expression, (AstTyped **) &ename->func);
+            break;
+        }
+
         default: break;
     }
 
@@ -1412,19 +1418,16 @@ static SymresStatus symres_process_directive(AstNode* directive) {
 
             if (export->export->kind == Ast_Kind_Function) {
                 AstFunction *func = (AstFunction *) export->export;
-                func->exported_name = export->export_name;
                 func->is_exported = 1;
 
-                if (func->is_exported) {
-                    if (func->is_foreign) {
-                        onyx_report_error(export->token->pos, Error_Critical, "Cannot export a foreign function.");
-                        return Symres_Error;
-                    }
+                if (func->is_foreign) {
+                    onyx_report_error(export->token->pos, Error_Critical, "Cannot export a foreign function.");
+                    return Symres_Error;
+                }
 
-                    if (func->is_intrinsic) {
-                        onyx_report_error(export->token->pos, Error_Critical, "Cannot export an intrinsic function.");
-                        return Symres_Error;
-                    }
+                if (func->is_intrinsic) {
+                    onyx_report_error(export->token->pos, Error_Critical, "Cannot export an intrinsic function.");
+                    return Symres_Error;
                 }
             }
 
index 17e981a5b399ad720b365a555fa71abdfcc3ba45..db4673628455110d149f00a2c163444d7a5c5ecb 100644 (file)
@@ -3463,6 +3463,12 @@ EMIT_FUNC(expression, AstTyped* expr) {
             break;
         }
 
+        case Ast_Kind_Directive_Export_Name: {
+            AstDirectiveExportName *ename = (AstDirectiveExportName *) expr;
+            emit_expression(mod, &code, (AstTyped *) ename->name);
+            break;
+        }
+
         default:
             bh_printf("Unhandled case: %d\n", expr->kind);
             DEBUG_HERE;
@@ -4114,6 +4120,15 @@ static b32 emit_constexpr_(ConstExprContext *ctx, AstTyped *node, u32 offset) {
         break;
     }
 
+    case Ast_Kind_Directive_Export_Name: {
+        AstDirectiveExportName *ename = (AstDirectiveExportName *) node;
+        node = (AstTyped *) ename->name;
+
+        // This fallthrough is very intentional. This replaces the value of "node"
+        // so the case below thinks it is just generating the constexpr of a string.
+        // fallthrough
+    }
+
     case Ast_Kind_StrLit: {
         AstStrLit* sl = (AstStrLit *) node;
 
index 729b21256f983770977ffc116e624864ec0bfa4a..e92c430e7ae56b1cb537c2dfee7de11e9d7f33a4 100644 (file)
@@ -126,6 +126,21 @@ clear :: (arena: ^ArenaState) {
     arena.size = sizeof rawptr;
 }
 
+get_allocated_arenas :: (arena: ^ArenaState) -> u32 {
+    arenas := 0;
+    walker := arena.first_arena;
+    while walker != null {
+        arenas += 1;
+        walker = walker.next;
+    }
+
+    return arenas;
+}
+
+get_allocated_bytes :: (arena: ^ArenaState) -> u32 {
+    return get_allocated_arenas(arena) * (arena.arena_size - 1) + arena.size;
+}
+
 auto :: #match {
     macro (size := 32 * 1024, $dest: Code = #(context.allocator)) {
         alloc :: package core.alloc
index 09f08a0273199e6ff7447c2c2d5a982fb6c97011..afd606683f94c23e606aa81a7325b2b25dd07615 100644 (file)
@@ -62,25 +62,31 @@ SnailNum :: struct {
 
     reduce_explodes :: (use n: ^SnailNum, depth := 0) -> (reduced_something: bool, zero_node: bool) {
         if depth <= 3 {
-            did_reduce, zero_node := false, false;
-
             if left != null {
-                if did_reduce, zero_node = left->reduce_explodes(depth + 1); zero_node {
+                if did_reduce, zero_node := left->reduce_explodes(depth + 1); zero_node {
                     left = null;
+                    return true, false;
+
+                } elseif did_reduce {
+                    return true, false;
                 }
             }
 
-            if right != null && !did_reduce {
-                if did_reduce, zero_node = right->reduce_explodes(depth + 1); zero_node {
+            if right != null {
+                if did_reduce, zero_node := right->reduce_explodes(depth + 1); zero_node {
                     right = null;
+                    return true, false;
+
+                } elseif did_reduce {
+                    return true, false;
                 }
             }
 
-            return did_reduce, false;
+            return false, false;
         }
 
-        pleft  := n->pair_to_left();
-        pright := n->pair_to_right();
+        pleft  := n->number_to_left();
+        pright := n->number_to_right();
         if pleft  != null do *pleft += left_val;
         if pright != null do *pright += right_val;
 
@@ -135,7 +141,7 @@ SnailNum :: struct {
         if new_right != null do new_right.parent = parent;
     }
 
-    pair_to_left :: (n: ^SnailNum) -> ^u32 {
+    number_to_left :: (n: ^SnailNum) -> ^u32 {
         while n.parent != null && n.parent.left == n {
             n = n.parent;
         }
@@ -153,7 +159,7 @@ SnailNum :: struct {
         return ^n.right_val;
     }
 
-    pair_to_right :: (n: ^SnailNum) -> ^u32 {
+    number_to_right :: (n: ^SnailNum) -> ^u32 {
         while n.parent != null && n.parent.right == n {
             n = n.parent;
         }
@@ -222,7 +228,7 @@ SnailNum :: struct {
 
 
 main :: () {
-    num_arena := arena.make(context.allocator, 64 * 1024);
+    num_arena := arena.make(context.allocator, 256 * 1024);
     SnailNum.allocator = alloc.as_allocator(^num_arena);
     
     conv.register_custom_formatter(SnailNum.format);