| author | |
| committer | |
| log | b3459f64e795118c4c12890ed0fec75638b74a2c |
| tree | d5730790d1b61f71a606e30023d68cc36071cce4 |
| parent | 6b2e29c6ac58d5f4370828bfa0f54b83d1931a97 |
5 files changed, 159 insertions(+), 18 deletions(-)
src/analyze.cpp+2| ... | ... | @@ -29,6 +29,7 @@ static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, |
| 29 | 29 | static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node); |
| 30 | 30 | static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn); |
| 31 | 31 | static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *node); |
| 32 | static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, AstNode *node); | |
| 32 | 33 | |
| 33 | 34 | static AstNode *first_executing_node(AstNode *node) { |
| 34 | 35 | switch (node->type) { |
| ... | ... | @@ -1251,6 +1252,7 @@ static void resolve_c_import_decl(CodeGen *g, ImportTableEntry *parent_import, A |
| 1251 | 1252 | child_import->importers.append({parent_import, node}); |
| 1252 | 1253 | |
| 1253 | 1254 | detect_top_level_decl_deps(g, child_import, child_import->root); |
| 1255 | analyze_top_level_decls_root(g, child_import, child_import->root); | |
| 1254 | 1256 | } |
| 1255 | 1257 | |
| 1256 | 1258 | static void satisfy_dep(CodeGen *g, AstNode *node) { |
src/ast_render.cpp+53-7| ... | ... | @@ -582,15 +582,34 @@ static void render_node(AstRender *ar, AstNode *node) { |
| 582 | 582 | break; |
| 583 | 583 | } |
| 584 | 584 | case NodeTypeFnDef: |
| 585 | zig_panic("TODO"); | |
| 585 | for (int i = 0; i < node->data.fn_def.fn_proto->data.fn_proto.directives->length; i += 1) { | |
| 586 | render_node(ar, node->data.fn_def.fn_proto->data.fn_proto.directives->at(i)); | |
| 587 | } | |
| 588 | render_node(ar, node->data.fn_def.fn_proto); | |
| 589 | fprintf(ar->f, " "); | |
| 590 | render_node(ar, node->data.fn_def.body); | |
| 591 | break; | |
| 586 | 592 | case NodeTypeFnDecl: |
| 587 | 593 | zig_panic("TODO"); |
| 588 | 594 | case NodeTypeParamDecl: |
| 589 | 595 | zig_panic("TODO"); |
| 590 | 596 | case NodeTypeBlock: |
| 591 | zig_panic("TODO"); | |
| 597 | fprintf(ar->f, "{\n"); | |
| 598 | ar->indent += ar->indent_size; | |
| 599 | for (int i = 0; i < node->data.block.statements.length; i += 1) { | |
| 600 | AstNode *statement = node->data.block.statements.at(i); | |
| 601 | print_indent(ar); | |
| 602 | render_node(ar, statement); | |
| 603 | } | |
| 604 | ar->indent -= ar->indent_size; | |
| 605 | fprintf(ar->f, "\n"); | |
| 606 | print_indent(ar); | |
| 607 | fprintf(ar->f, "}"); | |
| 608 | break; | |
| 592 | 609 | case NodeTypeDirective: |
| 593 | zig_panic("TODO"); | |
| 610 | fprintf(ar->f, "#%s(\"%s\")\n", buf_ptr(&node->data.directive.name), | |
| 611 | buf_ptr(&node->data.directive.param)); | |
| 612 | break; | |
| 594 | 613 | case NodeTypeReturnExpr: |
| 595 | 614 | zig_panic("TODO"); |
| 596 | 615 | case NodeTypeVariableDeclaration: |
| ... | ... | @@ -621,7 +640,12 @@ static void render_node(AstRender *ar, AstNode *node) { |
| 621 | 640 | case NodeTypeErrorValueDecl: |
| 622 | 641 | zig_panic("TODO"); |
| 623 | 642 | case NodeTypeBinOpExpr: |
| 624 | zig_panic("TODO"); | |
| 643 | fprintf(ar->f, "("); | |
| 644 | render_node(ar, node->data.bin_op_expr.op1); | |
| 645 | fprintf(ar->f, " %s ", bin_op_str(node->data.bin_op_expr.bin_op)); | |
| 646 | render_node(ar, node->data.bin_op_expr.op2); | |
| 647 | fprintf(ar->f, ")"); | |
| 648 | break; | |
| 625 | 649 | case NodeTypeUnwrapErrorExpr: |
| 626 | 650 | zig_panic("TODO"); |
| 627 | 651 | case NodeTypeNumberLiteral: |
| ... | ... | @@ -635,7 +659,11 @@ static void render_node(AstRender *ar, AstNode *node) { |
| 635 | 659 | } |
| 636 | 660 | break; |
| 637 | 661 | case NodeTypeStringLiteral: |
| 638 | zig_panic("TODO"); | |
| 662 | if (node->data.string_literal.c) { | |
| 663 | fprintf(ar->f, "c"); | |
| 664 | } | |
| 665 | fprintf(ar->f, "\"%s\"", buf_ptr(&node->data.string_literal.buf)); | |
| 666 | break; | |
| 639 | 667 | case NodeTypeCharLiteral: |
| 640 | 668 | { |
| 641 | 669 | uint8_t c = node->data.char_literal.value; |
| ... | ... | @@ -665,7 +693,20 @@ static void render_node(AstRender *ar, AstNode *node) { |
| 665 | 693 | break; |
| 666 | 694 | } |
| 667 | 695 | case NodeTypeFnCallExpr: |
| 668 | zig_panic("TODO"); | |
| 696 | if (node->data.fn_call_expr.is_builtin) { | |
| 697 | fprintf(ar->f, "@"); | |
| 698 | } | |
| 699 | render_node(ar, node->data.fn_call_expr.fn_ref_expr); | |
| 700 | fprintf(ar->f, "("); | |
| 701 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { | |
| 702 | AstNode *param = node->data.fn_call_expr.params.at(i); | |
| 703 | if (i != 0) { | |
| 704 | fprintf(ar->f, ", "); | |
| 705 | } | |
| 706 | render_node(ar, param); | |
| 707 | } | |
| 708 | fprintf(ar->f, ")"); | |
| 709 | break; | |
| 669 | 710 | case NodeTypeArrayAccessExpr: |
| 670 | 711 | zig_panic("TODO"); |
| 671 | 712 | case NodeTypeSliceExpr: |
| ... | ... | @@ -739,7 +780,12 @@ static void render_node(AstRender *ar, AstNode *node) { |
| 739 | 780 | case NodeTypeStructField: |
| 740 | 781 | zig_panic("TODO"); |
| 741 | 782 | case NodeTypeContainerInitExpr: |
| 742 | zig_panic("TODO"); | |
| 783 | fprintf(ar->f, "("); | |
| 784 | render_node(ar, node->data.container_init_expr.type); | |
| 785 | fprintf(ar->f, "){"); | |
| 786 | assert(node->data.container_init_expr.entries.length == 0); | |
| 787 | fprintf(ar->f, "}"); | |
| 788 | break; | |
| 743 | 789 | case NodeTypeStructValueField: |
| 744 | 790 | zig_panic("TODO"); |
| 745 | 791 | case NodeTypeArrayType: |
src/codegen.cpp+3| ... | ... | @@ -612,6 +612,8 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { |
| 612 | 612 | return LLVMBuildUnreachable(g->builder); |
| 613 | 613 | } else if (first_arg_ret) { |
| 614 | 614 | return node->data.fn_call_expr.tmp_ptr; |
| 615 | } else if (src_return_type->size_in_bits == 0) { | |
| 616 | return nullptr; | |
| 615 | 617 | } else { |
| 616 | 618 | return result; |
| 617 | 619 | } |
| ... | ... | @@ -2767,6 +2769,7 @@ static void do_code_gen(CodeGen *g) { |
| 2767 | 2769 | } |
| 2768 | 2770 | |
| 2769 | 2771 | VariableTableEntry *variable = param_decl->data.param_decl.variable; |
| 2772 | assert(variable); | |
| 2770 | 2773 | |
| 2771 | 2774 | LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(param_decl->line + 1, param_decl->column + 1, |
| 2772 | 2775 | fn_def_node->data.fn_def.block_context->di_scope); |
src/parseh.cpp+93| ... | ... | @@ -51,6 +51,7 @@ struct Context { |
| 51 | 51 | AstNode *source_node; |
| 52 | 52 | |
| 53 | 53 | CodeGen *codegen; |
| 54 | bool transform_extern_fn_ptr; | |
| 54 | 55 | }; |
| 55 | 56 | |
| 56 | 57 | static TypeTableEntry *resolve_qual_type_with_table(Context *c, QualType qt, const Decl *decl, |
| ... | ... | @@ -196,6 +197,13 @@ static AstNode *create_num_lit_signed(Context *c, int64_t x) { |
| 196 | 197 | return create_prefix_node(c, PrefixOpNegation, num_lit_node); |
| 197 | 198 | } |
| 198 | 199 | |
| 200 | static AstNode *create_directive_node(Context *c, const char *name, const char *value) { | |
| 201 | AstNode *node = create_node(c, NodeTypeDirective); | |
| 202 | buf_init_from_str(&node->data.directive.name, name); | |
| 203 | buf_init_from_str(&node->data.directive.param, value); | |
| 204 | return node; | |
| 205 | } | |
| 206 | ||
| 199 | 207 | static AstNode *create_type_decl_node(Context *c, const char *name, AstNode *child_type_node) { |
| 200 | 208 | AstNode *node = create_node(c, NodeTypeTypeDecl); |
| 201 | 209 | buf_init_from_str(&node->data.type_decl.symbol, name); |
| ... | ... | @@ -213,6 +221,80 @@ static AstNode *make_type_node(Context *c, TypeTableEntry *type_entry) { |
| 213 | 221 | return node; |
| 214 | 222 | } |
| 215 | 223 | |
| 224 | static AstNode *create_fn_proto_node(Context *c, Buf *name, TypeTableEntry *fn_type) { | |
| 225 | assert(fn_type->id == TypeTableEntryIdFn); | |
| 226 | AstNode *node = create_node(c, NodeTypeFnProto); | |
| 227 | node->data.fn_proto.directives = create_empty_directives(c); | |
| 228 | node->data.fn_proto.directives->append(create_directive_node(c, "attribute", "inline")); | |
| 229 | node->data.fn_proto.visib_mod = c->visib_mod; | |
| 230 | buf_init_from_buf(&node->data.fn_proto.name, name); | |
| 231 | node->data.fn_proto.return_type = make_type_node(c, fn_type->data.fn.fn_type_id.return_type); | |
| 232 | ||
| 233 | for (int i = 0; i < fn_type->data.fn.fn_type_id.param_count; i += 1) { | |
| 234 | FnTypeParamInfo *info = &fn_type->data.fn.fn_type_id.param_info[i]; | |
| 235 | Buf *name = buf_sprintf("arg_%d", i); | |
| 236 | node->data.fn_proto.params.append(create_param_decl_node(c, buf_ptr(name), | |
| 237 | make_type_node(c, info->type), info->is_noalias)); | |
| 238 | } | |
| 239 | ||
| 240 | normalize_parent_ptrs(node); | |
| 241 | return node; | |
| 242 | } | |
| 243 | ||
| 244 | static AstNode *create_one_statement_block(Context *c, AstNode *statement) { | |
| 245 | AstNode *node = create_node(c, NodeTypeBlock); | |
| 246 | node->data.block.statements.append(statement); | |
| 247 | ||
| 248 | normalize_parent_ptrs(node); | |
| 249 | return node; | |
| 250 | } | |
| 251 | ||
| 252 | static AstNode *create_container_init_node(Context *c, AstNode *type_node) { | |
| 253 | AstNode *node = create_node(c, NodeTypeContainerInitExpr); | |
| 254 | node->data.container_init_expr.kind = ContainerInitKindArray; | |
| 255 | node->data.container_init_expr.type = type_node; | |
| 256 | ||
| 257 | normalize_parent_ptrs(node); | |
| 258 | return node; | |
| 259 | } | |
| 260 | ||
| 261 | static AstNode *create_bin_op_node(Context *c, AstNode *lhs, BinOpType op, AstNode *rhs) { | |
| 262 | AstNode *node = create_node(c, NodeTypeBinOpExpr); | |
| 263 | node->data.bin_op_expr.op1 = lhs; | |
| 264 | node->data.bin_op_expr.bin_op = op; | |
| 265 | node->data.bin_op_expr.op2 = rhs; | |
| 266 | ||
| 267 | normalize_parent_ptrs(node); | |
| 268 | return node; | |
| 269 | } | |
| 270 | ||
| 271 | static AstNode *create_inline_fn_node(Context *c, Buf *fn_name, Buf *var_name, TypeTableEntry *fn_type) { | |
| 272 | AstNode *node = create_node(c, NodeTypeFnDef); | |
| 273 | node->data.fn_def.fn_proto = create_fn_proto_node(c, fn_name, fn_type); | |
| 274 | ||
| 275 | AstNode *unreach_type_node = make_type_node(c, c->codegen->builtin_types.entry_unreachable); | |
| 276 | AstNode *unreach_node = create_container_init_node(c, unreach_type_node); | |
| 277 | AstNode *unwrap_node = create_bin_op_node(c, create_symbol_node(c, buf_ptr(var_name)), | |
| 278 | BinOpTypeUnwrapMaybe, unreach_node); | |
| 279 | ||
| 280 | AstNode *fn_call_node = create_node(c, NodeTypeFnCallExpr); | |
| 281 | fn_call_node->data.fn_call_expr.fn_ref_expr = unwrap_node; | |
| 282 | for (int i = 0; i < fn_type->data.fn.fn_type_id.param_count; i += 1) { | |
| 283 | AstNode *decl_node = node->data.fn_def.fn_proto->data.fn_proto.params.at(i); | |
| 284 | Buf *param_name = &decl_node->data.param_decl.name; | |
| 285 | fn_call_node->data.fn_call_expr.params.append(create_symbol_node(c, buf_ptr(param_name))); | |
| 286 | } | |
| 287 | ||
| 288 | normalize_parent_ptrs(fn_call_node); | |
| 289 | ||
| 290 | node->data.fn_def.body = create_one_statement_block(c, fn_call_node); | |
| 291 | ||
| 292 | normalize_parent_ptrs(node); | |
| 293 | return node; | |
| 294 | } | |
| 295 | ||
| 296 | ||
| 297 | ||
| 216 | 298 | static const char *decl_name(const Decl *decl) { |
| 217 | 299 | const NamedDecl *named_decl = static_cast<const NamedDecl *>(decl); |
| 218 | 300 | return (const char *)named_decl->getName().bytes_begin(); |
| ... | ... | @@ -1257,6 +1339,17 @@ static void process_symbol_macros(Context *c) { |
| 1257 | 1339 | AstNode *var_node = create_var_decl_node(c, buf_ptr(ms.name), |
| 1258 | 1340 | create_symbol_node(c, buf_ptr(ms.value))); |
| 1259 | 1341 | c->macro_table.put(ms.name, var_node); |
| 1342 | } else if (c->transform_extern_fn_ptr || true) { // TODO take off the || true | |
| 1343 | if (auto entry = c->global_value_table.maybe_get(ms.value)) { | |
| 1344 | TypeTableEntry *maybe_type = entry->value.type; | |
| 1345 | if (maybe_type->id == TypeTableEntryIdMaybe) { | |
| 1346 | TypeTableEntry *fn_type = maybe_type->data.maybe.child_type; | |
| 1347 | if (fn_type->id == TypeTableEntryIdFn) { | |
| 1348 | AstNode *fn_node = create_inline_fn_node(c, ms.name, ms.value, fn_type); | |
| 1349 | c->macro_table.put(ms.name, fn_node); | |
| 1350 | } | |
| 1351 | } | |
| 1352 | } | |
| 1260 | 1353 | } |
| 1261 | 1354 | } |
| 1262 | 1355 | } |
test/run_tests.cpp+8-11| ... | ... | @@ -2109,18 +2109,15 @@ Foo fun(Foo *a); |
| 2109 | 2109 | "pub const Foo = c_void;", |
| 2110 | 2110 | "pub extern fn fun(a: ?&c_void);"); |
| 2111 | 2111 | |
| 2112 | add_parseh_case("ignore #define for non-const", R"SOURCE( | |
| 2113 | struct Foo { | |
| 2114 | int x; | |
| 2115 | }; | |
| 2112 | add_parseh_case("generate inline func for #define global extern fn", R"SOURCE( | |
| 2116 | 2113 | extern void (*fn_ptr)(void); |
| 2117 | #define Foo fn_ptr | |
| 2118 | )SOURCE", 3, | |
| 2119 | "pub type c_void = u8;", | |
| 2120 | "pub const Foo = struct_Foo;", | |
| 2121 | R"OUTPUT(export struct struct_Foo { | |
| 2122 | x: c_int, | |
| 2123 | })OUTPUT"); | |
| 2114 | #define foo fn_ptr | |
| 2115 | )SOURCE", 2, | |
| 2116 | "pub extern var fn_ptr: ?extern fn();", | |
| 2117 | R"SOURCE(#attribute("inline") | |
| 2118 | pub fn foo() { | |
| 2119 | (fn_ptr ?? (unreachable){})() | |
| 2120 | })SOURCE"); | |
| 2124 | 2121 | } |
| 2125 | 2122 | |
| 2126 | 2123 | static void print_compiler_invocation(TestCase *test_case) { |