added paste-able code blocks with '#insert' and '#{}'
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 3 Aug 2021 16:11:04 +0000 (11:11 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Tue, 3 Aug 2021 16:11:04 +0000 (11:11 -0500)
bin/onyx
core/builtin.onyx
include/onyxastnodes.h
include/onyxwasm.h
src/onyxastnodes.c
src/onyxbuiltins.c
src/onyxchecker.c
src/onyxclone.c
src/onyxparser.c
src/onyxsymres.c
src/onyxwasm.c

index b6eb58371979bdecd531b92fcde666f498fa5086..e51b1df8f55dba6658cf25ac742e7f846caf8787 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index 2b3aa3e12373dd69812b960c957dc3fa64cd908a..0787429ba43c9e839548a04e0e484954a0fa30b7 100644 (file)
@@ -187,3 +187,7 @@ any :: struct {
     data: rawptr;
     type: type_expr;
 }
+
+
+// Represents a code block. Not constructable outside of using a '#{}' block.
+Code :: struct {}
\ No newline at end of file
index 6273059ad71b99c40eefc5bf9e99a66671924503..ba0adc27974e64987f5288e948156a95f1c74780 100644 (file)
@@ -85,6 +85,9 @@
     NODE(Note)                 \
     NODE(CallSite)             \
                                \
+    NODE(CodeBlock)            \
+    NODE(DirectiveInsert)      \
+                               \
     NODE(Package)          
 
 #define NODE(name) typedef struct Ast ## name Ast ## name;
@@ -186,6 +189,9 @@ typedef enum AstKind {
     Ast_Kind_Directive_Defined,
     Ast_Kind_Call_Site,
 
+    Ast_Kind_Code_Block,
+    Ast_Kind_Directive_Insert,
+
     Ast_Kind_Note,
 
     Ast_Kind_Count
@@ -1005,6 +1011,19 @@ struct AstCallSite {
     AstNumLit* column;
 };
 
+// Represents a "pastable" block of code.
+struct AstCodeBlock {
+    AstTyped_base;
+
+    AstBlock *code;
+};
+
+struct AstDirectiveInsert {
+    AstNode_base;
+
+    AstTyped *code_expr;
+};
+
 typedef enum EntityState {
     Entity_State_Error,
     
@@ -1233,6 +1252,7 @@ extern AstType  *builtin_allocator_type;
 extern AstType  *builtin_iterator_type;
 extern AstType  *builtin_callsite_type;
 extern AstType  *builtin_any_type;
+extern AstType  *builtin_code_type;
 extern AstTyped *type_table_node;
 
 typedef struct BuiltinSymbol {
index 9f0cfffb14765e90948ced98cd8164c8620ed11b..29dc274cf6b38e8688ae763c81fa4b4a160ac656 100644 (file)
@@ -585,7 +585,6 @@ typedef struct OnyxWasmModule {
 } OnyxWasmModule;
 
 OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc);
-void onyx_wasm_module_compile(OnyxWasmModule* module);
 void onyx_wasm_module_free(OnyxWasmModule* module);
 void onyx_wasm_module_write_to_file(OnyxWasmModule* module, bh_file file);
 
index 1b4d186d8be252591681546aee8af8ba4a6da4a5..9944f63a1e1791375249f9da5000349e0fd49fce 100644 (file)
@@ -87,6 +87,9 @@ static const char* ast_node_names[] = {
     "DEFINED",
     "CALL SITE",
 
+    "CODE BLOCK",
+    "DIRECTIVE INSERT"
+
     "NOTE",
 
     "AST_NODE_KIND_COUNT",
index 161022fc02c73e1a9eced96e10bcda18b1e30288..e33d011c826ee18dd35976cc557ed73d42507a85 100644 (file)
@@ -48,6 +48,7 @@ AstType  *builtin_allocator_type;
 AstType  *builtin_iterator_type;
 AstType  *builtin_callsite_type;
 AstType  *builtin_any_type;
+AstType  *builtin_code_type;
 
 AstTyped *type_table_node = NULL;
 
@@ -398,6 +399,12 @@ void initialize_builtins(bh_allocator a) {
         return;
     }
 
+    builtin_code_type = (AstType *) symbol_raw_resolve(p->scope, "Code");
+    if (builtin_code_type == NULL) {
+        onyx_report_error((OnyxFilePos) { 0 }, "'Code' struct not found in builtin package.");
+        return;
+    }
+
     p = package_lookup("builtin.type_info");
     if (p != NULL) {
         type_table_node = (AstTyped *) symbol_raw_resolve(p->scope, "type_table");
index d9367e79ee75a6bd7ed331f804992866b98d5a04..2d4620c2739146e8c35ba9030c8f5760f1c687b5 100644 (file)
@@ -16,6 +16,7 @@ typedef enum CheckStatus {
     Check_Complete, // The node is done processing
 
     Check_Errors_Start,
+    Check_Return_To_Symres, // Return this node for further symres processing
     Check_Yield_Macro,
     Check_Error,    // There was an error when checking the node
 } CheckStatus;
@@ -1660,6 +1661,11 @@ CheckStatus check_expression(AstTyped** pexpr) {
             expr->type = ((AstAlias *) expr)->alias->type;
             break;
 
+        case Ast_Kind_Code_Block:
+            expr->flags |= Ast_Flag_Comptime;
+            fill_in_type(expr);
+            break;
+
         case Ast_Kind_StrLit: break;
         case Ast_Kind_File_Contents: break;
         case Ast_Kind_Overloaded_Function: break;
@@ -1696,6 +1702,42 @@ CheckStatus check_global(AstGlobal* global) {
     return Check_Success;
 }
 
+CheckStatus check_insert_directive(AstDirectiveInsert* insert) {
+    if (insert->flags & Ast_Flag_Has_Been_Checked) return Check_Success;
+
+    CHECK(expression, &insert->code_expr);
+    if (insert->code_expr->type == NULL) return Check_Yield_Macro;
+
+    Type* code_type = type_build_from_ast(context.ast_alloc, builtin_code_type);
+
+    if (!type_check_or_auto_cast(&insert->code_expr, code_type)) {
+        onyx_report_error(insert->token->pos, "#insert expected a value of type 'Code', got '%s'.",
+            type_get_name(insert->code_expr->type));
+
+        return Check_Error;
+    }
+
+    AstCodeBlock* code_block = (AstCodeBlock *) insert->code_expr;
+    while (code_block->kind == Ast_Kind_Alias) {
+        code_block = (AstCodeBlock *) ((AstAlias *) code_block)->alias;
+    }
+
+    assert(code_block->kind == Ast_Kind_Code_Block);
+
+    AstBlock* cloned_block = (AstBlock *) ast_clone(context.ast_alloc, code_block->code);
+
+    AstNode* next = insert->next;
+    insert->next = (AstNode *) cloned_block->body;
+
+    AstNode* last_stmt = insert->next;
+    while (last_stmt->next != NULL) last_stmt = last_stmt->next;
+    last_stmt->next = next;
+
+    insert->flags |= Ast_Flag_Has_Been_Checked;
+
+    return Check_Return_To_Symres;
+}
+
 CheckStatus check_statement(AstNode** pstmt) {
     AstNode* stmt = *pstmt;
 
@@ -1711,6 +1753,8 @@ CheckStatus check_statement(AstNode** pstmt) {
         case Ast_Kind_Block:      return check_block((AstBlock *) stmt);
         case Ast_Kind_Defer:      return check_statement(&((AstDefer *) stmt)->stmt);
 
+        case Ast_Kind_Directive_Insert: return check_insert_directive((AstDirectiveInsert *) stmt);
+
         case Ast_Kind_Binary_Op:
             CHECK(binaryop, (AstBinaryOp **) pstmt, 1);
             (*pstmt)->flags |= Ast_Flag_Expr_Ignored;
@@ -2148,9 +2192,10 @@ void check_entity(Entity* ent) {
         default: break;
     }
 
-    if (cs == Check_Success)     ent->state = Entity_State_Code_Gen;
-    if (cs == Check_Complete)    ent->state = Entity_State_Finalized;
-    if (cs == Check_Yield_Macro) ent->macro_attempts++;
+    if (cs == Check_Success)          ent->state = Entity_State_Code_Gen;
+    if (cs == Check_Complete)         ent->state = Entity_State_Finalized;
+    if (cs == Check_Return_To_Symres) ent->state = Entity_State_Resolve_Symbols;
+    if (cs == Check_Yield_Macro)      ent->macro_attempts++;
     else {
         ent->macro_attempts = 0;
         ent->micro_attempts = 0;
index 3130808dc1636d79b62b16a43ba8d7eed9ad64d3..e470b57ddd25208744b43a79d12991b567c7e8c2 100644 (file)
@@ -16,6 +16,7 @@ static inline b32 should_clone(AstNode* node) {
                case Ast_Kind_Overloaded_Function:
                case Ast_Kind_Polymorphic_Proc:
                case Ast_Kind_Alias:
+               case Ast_Kind_Code_Block:
                        return 0;
 
                default: return 1;
@@ -93,6 +94,7 @@ static inline i32 ast_kind_to_size(AstNode* node) {
         case Ast_Kind_Call_Site: return sizeof(AstCallSite);
         case Ast_Kind_Static_If: return sizeof(AstIfWhile);
         case Ast_Kind_If_Expression: return sizeof(AstIfExpression);
+        case Ast_Kind_Directive_Insert: return sizeof(AstDirectiveInsert);
         case Ast_Kind_Count: return 0;
        }
 
@@ -433,6 +435,11 @@ AstNode* ast_clone(bh_allocator a, void* n) {
             ((AstIfExpression *) nn)->false_expr = (AstTyped *) ast_clone(a, ((AstIfExpression *) node)->false_expr);
             break;
         }
+
+               case Ast_Kind_Directive_Insert: {
+                       ((AstDirectiveInsert *) nn)->code_expr = (AstTyped *) ast_clone(a, ((AstDirectiveInsert *) node)->code_expr);
+                       break;
+               }
        }
 
        return nn;
index 93b25c2b58dc04cd27ce52e52878ed5e09d42cb0..2ae6c8d48b4d1a97e987e434f9b0fac8d6e2bade 100644 (file)
@@ -605,6 +605,21 @@ static AstTyped* parse_factor(OnyxParser* parser) {
                 retval = (AstTyped *) defined;
                 break;
             }
+            else if (next_tokens_are(parser, 2, '#', '{')) {
+                OnyxToken* code_token = expect_token(parser, '#');
+                // expect_token(parser, '{');
+
+                AstCodeBlock* code_block = make_node(AstCodeBlock, Ast_Kind_Code_Block);
+                code_block->token = code_token;
+
+                assert(builtin_code_type != NULL);
+                code_block->type_node = builtin_code_type;
+
+                code_block->code = parse_block(parser, 1);
+
+                retval = (AstTyped *) code_block;
+                break;
+            }
 
             onyx_report_error(parser->curr->pos, "Invalid directive in expression.");
             return NULL;
@@ -1390,6 +1405,15 @@ static AstNode* parse_statement(OnyxParser* parser) {
                 ENTITY_SUBMIT(binding);
                 break;
             }
+
+            if (parse_possible_directive(parser, "insert")) {
+                AstDirectiveInsert* insert = make_node(AstDirectiveInsert, Ast_Kind_Directive_Insert);
+                insert->token = parser->curr - 1;
+                insert->code_expr = parse_expression(parser, 0);
+
+                retval = (AstNode *) insert;
+                break;
+            }
         }
 
         default:
index 3934e308b4ff22b3fbbae6592dc4d5453868652f..e130e50c2c2f74279285d27e332a2323d3cace1e 100644 (file)
@@ -757,6 +757,11 @@ static SymresStatus symres_directive_defined(AstDirectiveDefined** pdefined) {
     return Symres_Success;
 }
 
+static SymresStatus symres_directive_insert(AstDirectiveInsert* insert) {
+    SYMRES(expression, &insert->code_expr);
+    return Symres_Success;
+}
+
 static SymresStatus symres_statement(AstNode** stmt, b32 *remove) {
     if (remove) *remove = 0;
 
@@ -773,6 +778,8 @@ static SymresStatus symres_statement(AstNode** stmt, b32 *remove) {
         case Ast_Kind_Defer:       SYMRES(statement, &((AstDefer *) *stmt)->stmt, NULL); break;
         case Ast_Kind_Jump:        break;
 
+        case Ast_Kind_Directive_Insert: SYMRES(directive_insert, (AstDirectiveInsert *) *stmt); break;
+
         case Ast_Kind_Local:
             // if (remove) *remove = 1;
             SYMRES(local, (AstLocal **) stmt);
index 6d90994b2cc841d53616cbc24d5c55f292ef2e6c..9a6af36422b4e3d571d739bce033e9f76a35a9a1 100644 (file)
@@ -400,6 +400,9 @@ EMIT_FUNC(statement, AstNode* stmt) {
         case Ast_Kind_Block:      emit_block(mod, &code, (AstBlock *) stmt, 1); break;
         case Ast_Kind_Defer:      emit_defer(mod, &code, (AstDefer *) stmt); break;
         case Ast_Kind_Local:      emit_local_allocation(mod, &code, (AstTyped *) stmt); break;
+        
+        case Ast_Kind_Directive_Insert: break;
+
         default:                  emit_expression(mod, &code, (AstTyped *) stmt); break;
     }