| author | |
| committer | |
| log | 00f4c05784c05552e1e379b98c09161c936cfb31 |
| tree | 5b2234cae585c5ac3a2cb23503908b0a6e2a27e3 |
| parent | abbc3957019c3a12dacd54869ff18b91c3f07699 |
| parent | 55b8472374eede496b59396dbe253b05b16063e1 |
26 files changed, 562 insertions(+), 306 deletions(-)
CMakeLists.txt+4-4| ... | @@ -22,16 +22,16 @@ include_directories( | ... | @@ -22,16 +22,16 @@ include_directories( |
| 22 | ) | 22 | ) |
| 23 | 23 | ||
| 24 | set(ZIG_SOURCES | 24 | set(ZIG_SOURCES |
| 25 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" | ||
| 26 | "${CMAKE_SOURCE_DIR}/src/parser.cpp" | ||
| 25 | "${CMAKE_SOURCE_DIR}/src/analyze.cpp" | 27 | "${CMAKE_SOURCE_DIR}/src/analyze.cpp" |
| 28 | "${CMAKE_SOURCE_DIR}/src/codegen.cpp" | ||
| 26 | "${CMAKE_SOURCE_DIR}/src/buffer.cpp" | 29 | "${CMAKE_SOURCE_DIR}/src/buffer.cpp" |
| 27 | "${CMAKE_SOURCE_DIR}/src/error.cpp" | 30 | "${CMAKE_SOURCE_DIR}/src/error.cpp" |
| 28 | "${CMAKE_SOURCE_DIR}/src/main.cpp" | 31 | "${CMAKE_SOURCE_DIR}/src/main.cpp" |
| 29 | "${CMAKE_SOURCE_DIR}/src/parser.cpp" | 32 | "${CMAKE_SOURCE_DIR}/src/os.cpp" |
| 30 | "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" | ||
| 31 | "${CMAKE_SOURCE_DIR}/src/util.cpp" | 33 | "${CMAKE_SOURCE_DIR}/src/util.cpp" |
| 32 | "${CMAKE_SOURCE_DIR}/src/codegen.cpp" | ||
| 33 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" | 34 | "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" |
| 34 | "${CMAKE_SOURCE_DIR}/src/os.cpp" | ||
| 35 | ) | 35 | ) |
| 36 | 36 | ||
| 37 | set(TEST_SOURCES | 37 | set(TEST_SOURCES |
README.md+3-1| ... | @@ -79,7 +79,9 @@ zig | C equivalent | Description | ... | @@ -79,7 +79,9 @@ zig | C equivalent | Description |
| 79 | ``` | 79 | ``` |
| 80 | Root : many(TopLevelDecl) token(EOF) | 80 | Root : many(TopLevelDecl) token(EOF) |
| 81 | 81 | ||
| 82 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | 82 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use |
| 83 | |||
| 84 | Use : many(Directive) token(Use) token(String) token(Semicolon) | ||
| 83 | 85 | ||
| 84 | RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon) | 86 | RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon) |
| 85 | 87 |
doc/vim/syntax/zig.vim+15-2| ... | @@ -7,7 +7,7 @@ if exists("b:current_syntax") | ... | @@ -7,7 +7,7 @@ if exists("b:current_syntax") |
| 7 | finish | 7 | finish |
| 8 | endif | 8 | endif |
| 9 | 9 | ||
| 10 | syn keyword zigKeyword fn return mut const extern unreachable export pub as | 10 | syn keyword zigKeyword fn return mut const extern unreachable export pub as use |
| 11 | syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void | 11 | syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void |
| 12 | 12 | ||
| 13 | syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell | 13 | syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell |
| ... | @@ -19,6 +19,15 @@ syn region zigCommentBlockDocNest matchgroup=zigCommentBlockDoc start="/\*" end= | ... | @@ -19,6 +19,15 @@ syn region zigCommentBlockDocNest matchgroup=zigCommentBlockDoc start="/\*" end= |
| 19 | 19 | ||
| 20 | syn keyword zigTodo contained TODO XXX | 20 | syn keyword zigTodo contained TODO XXX |
| 21 | 21 | ||
| 22 | syn match zigEscapeError display contained /\\./ | ||
| 23 | syn match zigEscape display contained /\\\([nrt0\\'"]\|x\x\{2}\)/ | ||
| 24 | syn match zigEscapeUnicode display contained /\\\(u\x\{4}\|U\x\{8}\)/ | ||
| 25 | syn match zigEscapeUnicode display contained /\\u{\x\{1,6}}/ | ||
| 26 | syn match zigStringContinuation display contained /\\\n\s*/ | ||
| 27 | syn region zigString start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=zigEscape,zigEscapeError,zigStringContinuation | ||
| 28 | syn region zigString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=zigEscape,zigEscapeUnicode,zigEscapeError,zigStringContinuation,@Spell | ||
| 29 | syn region zigString start='b\?r\z(#*\)"' end='"\z1' contains=@Spell | ||
| 30 | |||
| 22 | let b:current_syntax = "zig" | 31 | let b:current_syntax = "zig" |
| 23 | 32 | ||
| 24 | hi def link zigKeyword Keyword | 33 | hi def link zigKeyword Keyword |
| ... | @@ -28,4 +37,8 @@ hi def link zigCommentLineDoc SpecialComment | ... | @@ -28,4 +37,8 @@ hi def link zigCommentLineDoc SpecialComment |
| 28 | hi def link zigCommentBlock zigCommentLine | 37 | hi def link zigCommentBlock zigCommentLine |
| 29 | hi def link zigCommentBlockDoc zigCommentLineDoc | 38 | hi def link zigCommentBlockDoc zigCommentLineDoc |
| 30 | hi def link zigTodo Todo | 39 | hi def link zigTodo Todo |
| 31 | 40 | hi def link zigStringContinuation Special | |
| 41 | hi def link zigString String | ||
| 42 | hi def link zigEscape Special | ||
| 43 | hi def link zigEscapeUnicode zigEscape | ||
| 44 | hi def link zigEscapeError Error |
example/hello.zig deleted-12| ... | @@ -1,12 +0,0 @@ | ||
| 1 | export executable "hello"; | ||
| 2 | |||
| 3 | #link("c") | ||
| 4 | extern { | ||
| 5 | fn puts(s: *mut u8) -> i32; | ||
| 6 | fn exit(code: i32) -> unreachable; | ||
| 7 | } | ||
| 8 | |||
| 9 | export fn _start() -> unreachable { | ||
| 10 | puts("Hello, world!"); | ||
| 11 | exit(0); | ||
| 12 | } | ||
example/hello_world/hello.zig created+12| ... | @@ -0,0 +1,12 @@ | ||
| 1 | export executable "hello"; | ||
| 2 | |||
| 3 | #link("c") | ||
| 4 | extern { | ||
| 5 | fn puts(s: *mut u8) -> i32; | ||
| 6 | fn exit(code: i32) -> unreachable; | ||
| 7 | } | ||
| 8 | |||
| 9 | export fn _start() -> unreachable { | ||
| 10 | puts("Hello, world!"); | ||
| 11 | exit(0); | ||
| 12 | } | ||
example/mathtest.zig deleted-6| ... | @@ -1,6 +0,0 @@ | ||
| 1 | #version("2.0.0") | ||
| 2 | export library "mathtest"; | ||
| 3 | |||
| 4 | export fn add(a: i32, b: i32) -> i32 { | ||
| 5 | return a + b; | ||
| 6 | } | ||
example/multiple_files/foo.zig created+5| ... | @@ -0,0 +1,5 @@ | ||
| 1 | use "libc.zig"; | ||
| 2 | |||
| 3 | fn print_text() { | ||
| 4 | puts("it works!"); | ||
| 5 | } | ||
example/multiple_files/libc.zig created+5| ... | @@ -0,0 +1,5 @@ | ||
| 1 | #link("c") | ||
| 2 | extern { | ||
| 3 | fn puts(s: *mut u8) -> i32; | ||
| 4 | fn exit(code: i32) -> unreachable; | ||
| 5 | } | ||
example/multiple_files/main.zig created+9| ... | @@ -0,0 +1,9 @@ | ||
| 1 | export executable "test"; | ||
| 2 | |||
| 3 | use "libc.zig"; | ||
| 4 | use "foo.zig"; | ||
| 5 | |||
| 6 | fn _start() -> unreachable { | ||
| 7 | print_text(); | ||
| 8 | exit(0); | ||
| 9 | } | ||
example/shared_library/mathtest.zig created+6| ... | @@ -0,0 +1,6 @@ | ||
| 1 | #version("2.0.0") | ||
| 2 | export library "mathtest"; | ||
| 3 | |||
| 4 | export fn add(a: i32, b: i32) -> i32 { | ||
| 5 | return a + b; | ||
| 6 | } | ||
example/shared_library/test.c created+7| ... | @@ -0,0 +1,7 @@ | ||
| 1 | #include "mathtest.h" | ||
| 2 | #include <stdio.h> | ||
| 3 | |||
| 4 | int main(int argc, char **argv) { | ||
| 5 | printf("%d\n", add(42, 1137)); | ||
| 6 | return 0; | ||
| 7 | } | ||
src/analyze.cpp+84-93| ... | @@ -119,7 +119,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node) { | ... | @@ -119,7 +119,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node) { |
| 119 | resolve_type(g, node->data.fn_proto.return_type); | 119 | resolve_type(g, node->data.fn_proto.return_type); |
| 120 | } | 120 | } |
| 121 | 121 | ||
| 122 | static void preview_function_declarations(CodeGen *g, AstNode *node) { | 122 | static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 123 | switch (node->type) { | 123 | switch (node->type) { |
| 124 | case NodeTypeExternBlock: | 124 | case NodeTypeExternBlock: |
| 125 | for (int i = 0; i < node->data.extern_block.directives->length; i += 1) { | 125 | for (int i = 0; i < node->data.extern_block.directives->length; i += 1) { |
| ... | @@ -145,6 +145,7 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) { | ... | @@ -145,6 +145,7 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) { |
| 145 | fn_table_entry->proto_node = fn_proto; | 145 | fn_table_entry->proto_node = fn_proto; |
| 146 | fn_table_entry->is_extern = true; | 146 | fn_table_entry->is_extern = true; |
| 147 | fn_table_entry->calling_convention = LLVMCCallConv; | 147 | fn_table_entry->calling_convention = LLVMCCallConv; |
| 148 | fn_table_entry->import_entry = import; | ||
| 148 | g->fn_table.put(name, fn_table_entry); | 149 | g->fn_table.put(name, fn_table_entry); |
| 149 | } | 150 | } |
| 150 | break; | 151 | break; |
| ... | @@ -162,6 +163,7 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) { | ... | @@ -162,6 +163,7 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) { |
| 162 | node->codegen_node->data.fn_def_node.skip = true; | 163 | node->codegen_node->data.fn_def_node.skip = true; |
| 163 | } else { | 164 | } else { |
| 164 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); | 165 | FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); |
| 166 | fn_table_entry->import_entry = import; | ||
| 165 | fn_table_entry->proto_node = proto_node; | 167 | fn_table_entry->proto_node = proto_node; |
| 166 | fn_table_entry->fn_def_node = node; | 168 | fn_table_entry->fn_def_node = node; |
| 167 | fn_table_entry->internal_linkage = proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport; | 169 | fn_table_entry->internal_linkage = proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport; |
| ... | @@ -196,8 +198,8 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) { | ... | @@ -196,8 +198,8 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) { |
| 196 | } else { | 198 | } else { |
| 197 | g->root_export_decl = node; | 199 | g->root_export_decl = node; |
| 198 | 200 | ||
| 199 | if (!g->out_name) | 201 | if (!g->root_out_name) |
| 200 | g->out_name = &node->data.root_export_decl.name; | 202 | g->root_out_name = &node->data.root_export_decl.name; |
| 201 | 203 | ||
| 202 | Buf *out_type = &node->data.root_export_decl.type; | 204 | Buf *out_type = &node->data.root_export_decl.type; |
| 203 | OutType export_out_type; | 205 | OutType export_out_type; |
| ... | @@ -215,6 +217,9 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) { | ... | @@ -215,6 +217,9 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) { |
| 215 | g->out_type = export_out_type; | 217 | g->out_type = export_out_type; |
| 216 | } | 218 | } |
| 217 | break; | 219 | break; |
| 220 | case NodeTypeUse: | ||
| 221 | zig_panic("TODO use"); | ||
| 222 | break; | ||
| 218 | case NodeTypeDirective: | 223 | case NodeTypeDirective: |
| 219 | case NodeTypeParamDecl: | 224 | case NodeTypeParamDecl: |
| 220 | case NodeTypeFnProto: | 225 | case NodeTypeFnProto: |
| ... | @@ -379,6 +384,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty | ... | @@ -379,6 +384,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty |
| 379 | case NodeTypeRootExportDecl: | 384 | case NodeTypeRootExportDecl: |
| 380 | case NodeTypeExternBlock: | 385 | case NodeTypeExternBlock: |
| 381 | case NodeTypeFnDef: | 386 | case NodeTypeFnDef: |
| 387 | case NodeTypeUse: | ||
| 382 | zig_unreachable(); | 388 | zig_unreachable(); |
| 383 | } | 389 | } |
| 384 | zig_unreachable(); | 390 | zig_unreachable(); |
| ... | @@ -437,6 +443,75 @@ static void check_fn_def_control_flow(CodeGen *g, AstNode *node) { | ... | @@ -437,6 +443,75 @@ static void check_fn_def_control_flow(CodeGen *g, AstNode *node) { |
| 437 | } | 443 | } |
| 438 | } | 444 | } |
| 439 | 445 | ||
| 446 | static void analyze_expression(CodeGen *g, AstNode *node) { | ||
| 447 | switch (node->type) { | ||
| 448 | case NodeTypeBlock: | ||
| 449 | for (int i = 0; i < node->data.block.statements.length; i += 1) { | ||
| 450 | AstNode *child = node->data.block.statements.at(i); | ||
| 451 | analyze_expression(g, child); | ||
| 452 | } | ||
| 453 | break; | ||
| 454 | case NodeTypeReturnExpr: | ||
| 455 | if (node->data.return_expr.expr) { | ||
| 456 | analyze_expression(g, node->data.return_expr.expr); | ||
| 457 | } | ||
| 458 | break; | ||
| 459 | case NodeTypeBinOpExpr: | ||
| 460 | analyze_expression(g, node->data.bin_op_expr.op1); | ||
| 461 | analyze_expression(g, node->data.bin_op_expr.op2); | ||
| 462 | break; | ||
| 463 | case NodeTypeFnCallExpr: | ||
| 464 | { | ||
| 465 | Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr); | ||
| 466 | |||
| 467 | auto entry = g->fn_table.maybe_get(name); | ||
| 468 | if (!entry) { | ||
| 469 | add_node_error(g, node, | ||
| 470 | buf_sprintf("undefined function: '%s'", buf_ptr(name))); | ||
| 471 | } else { | ||
| 472 | FnTableEntry *fn_table_entry = entry->value; | ||
| 473 | assert(fn_table_entry->proto_node->type == NodeTypeFnProto); | ||
| 474 | int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length; | ||
| 475 | int actual_param_count = node->data.fn_call_expr.params.length; | ||
| 476 | if (expected_param_count != actual_param_count) { | ||
| 477 | add_node_error(g, node, | ||
| 478 | buf_sprintf("wrong number of arguments. Expected %d, got %d.", | ||
| 479 | expected_param_count, actual_param_count)); | ||
| 480 | } | ||
| 481 | } | ||
| 482 | |||
| 483 | for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) { | ||
| 484 | AstNode *child = node->data.fn_call_expr.params.at(i); | ||
| 485 | analyze_expression(g, child); | ||
| 486 | } | ||
| 487 | break; | ||
| 488 | } | ||
| 489 | case NodeTypeCastExpr: | ||
| 490 | zig_panic("TODO"); | ||
| 491 | break; | ||
| 492 | case NodeTypePrefixOpExpr: | ||
| 493 | zig_panic("TODO"); | ||
| 494 | break; | ||
| 495 | case NodeTypeNumberLiteral: | ||
| 496 | case NodeTypeStringLiteral: | ||
| 497 | case NodeTypeUnreachable: | ||
| 498 | case NodeTypeSymbol: | ||
| 499 | // nothing to do | ||
| 500 | break; | ||
| 501 | case NodeTypeDirective: | ||
| 502 | case NodeTypeFnDecl: | ||
| 503 | case NodeTypeFnProto: | ||
| 504 | case NodeTypeParamDecl: | ||
| 505 | case NodeTypeType: | ||
| 506 | case NodeTypeRoot: | ||
| 507 | case NodeTypeRootExportDecl: | ||
| 508 | case NodeTypeExternBlock: | ||
| 509 | case NodeTypeFnDef: | ||
| 510 | case NodeTypeUse: | ||
| 511 | zig_unreachable(); | ||
| 512 | } | ||
| 513 | } | ||
| 514 | |||
| 440 | static void analyze_top_level_declaration(CodeGen *g, AstNode *node) { | 515 | static void analyze_top_level_declaration(CodeGen *g, AstNode *node) { |
| 441 | switch (node->type) { | 516 | switch (node->type) { |
| 442 | case NodeTypeFnDef: | 517 | case NodeTypeFnDef: |
| ... | @@ -470,9 +545,9 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) { | ... | @@ -470,9 +545,9 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) { |
| 470 | 545 | ||
| 471 | case NodeTypeRootExportDecl: | 546 | case NodeTypeRootExportDecl: |
| 472 | case NodeTypeExternBlock: | 547 | case NodeTypeExternBlock: |
| 548 | case NodeTypeUse: | ||
| 473 | // already looked at these in the preview pass | 549 | // already looked at these in the preview pass |
| 474 | break; | 550 | break; |
| 475 | |||
| 476 | case NodeTypeDirective: | 551 | case NodeTypeDirective: |
| 477 | case NodeTypeParamDecl: | 552 | case NodeTypeParamDecl: |
| 478 | case NodeTypeFnProto: | 553 | case NodeTypeFnProto: |
| ... | @@ -493,13 +568,13 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) { | ... | @@ -493,13 +568,13 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) { |
| 493 | } | 568 | } |
| 494 | } | 569 | } |
| 495 | 570 | ||
| 496 | static void analyze_root(CodeGen *g, AstNode *node) { | 571 | static void analyze_root(CodeGen *g, ImportTableEntry *import, AstNode *node) { |
| 497 | assert(node->type == NodeTypeRoot); | 572 | assert(node->type == NodeTypeRoot); |
| 498 | 573 | ||
| 499 | // find function declarations | 574 | // find function declarations |
| 500 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { | 575 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { |
| 501 | AstNode *child = node->data.root.top_level_decls.at(i); | 576 | AstNode *child = node->data.root.top_level_decls.at(i); |
| 502 | preview_function_declarations(g, child); | 577 | preview_function_declarations(g, import, child); |
| 503 | } | 578 | } |
| 504 | 579 | ||
| 505 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { | 580 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { |
| ... | @@ -507,7 +582,7 @@ static void analyze_root(CodeGen *g, AstNode *node) { | ... | @@ -507,7 +582,7 @@ static void analyze_root(CodeGen *g, AstNode *node) { |
| 507 | analyze_top_level_declaration(g, child); | 582 | analyze_top_level_declaration(g, child); |
| 508 | } | 583 | } |
| 509 | 584 | ||
| 510 | if (!g->out_name) { | 585 | if (!g->root_out_name) { |
| 511 | add_node_error(g, node, | 586 | add_node_error(g, node, |
| 512 | buf_sprintf("missing export declaration and output name not provided")); | 587 | buf_sprintf("missing export declaration and output name not provided")); |
| 513 | } else if (g->out_type == OutTypeUnknown) { | 588 | } else if (g->out_type == OutTypeUnknown) { |
| ... | @@ -516,91 +591,7 @@ static void analyze_root(CodeGen *g, AstNode *node) { | ... | @@ -516,91 +591,7 @@ static void analyze_root(CodeGen *g, AstNode *node) { |
| 516 | } | 591 | } |
| 517 | } | 592 | } |
| 518 | 593 | ||
| 519 | static void define_primitive_types(CodeGen *g) { | 594 | void semantic_analyze(CodeGen *g, ImportTableEntry *import_table_entry) { |
| 520 | { | 595 | analyze_root(g, import_table_entry, import_table_entry->root); |
| 521 | // if this type is anywhere in the AST, we should never hit codegen. | ||
| 522 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | ||
| 523 | buf_init_from_str(&entry->name, "(invalid)"); | ||
| 524 | g->builtin_types.entry_invalid = entry; | ||
| 525 | } | ||
| 526 | { | ||
| 527 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | ||
| 528 | entry->type_ref = LLVMInt8Type(); | ||
| 529 | buf_init_from_str(&entry->name, "u8"); | ||
| 530 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 8, 8, | ||
| 531 | LLVMZigEncoding_DW_ATE_unsigned()); | ||
| 532 | g->type_table.put(&entry->name, entry); | ||
| 533 | g->builtin_types.entry_u8 = entry; | ||
| 534 | } | ||
| 535 | { | ||
| 536 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | ||
| 537 | entry->type_ref = LLVMInt32Type(); | ||
| 538 | buf_init_from_str(&entry->name, "i32"); | ||
| 539 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 32, 32, | ||
| 540 | LLVMZigEncoding_DW_ATE_signed()); | ||
| 541 | g->type_table.put(&entry->name, entry); | ||
| 542 | g->builtin_types.entry_i32 = entry; | ||
| 543 | } | ||
| 544 | { | ||
| 545 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | ||
| 546 | entry->type_ref = LLVMVoidType(); | ||
| 547 | buf_init_from_str(&entry->name, "void"); | ||
| 548 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 0, 0, | ||
| 549 | LLVMZigEncoding_DW_ATE_unsigned()); | ||
| 550 | g->type_table.put(&entry->name, entry); | ||
| 551 | g->builtin_types.entry_void = entry; | ||
| 552 | } | ||
| 553 | { | ||
| 554 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | ||
| 555 | entry->type_ref = LLVMVoidType(); | ||
| 556 | buf_init_from_str(&entry->name, "unreachable"); | ||
| 557 | entry->di_type = g->builtin_types.entry_void->di_type; | ||
| 558 | g->type_table.put(&entry->name, entry); | ||
| 559 | g->builtin_types.entry_unreachable = entry; | ||
| 560 | } | ||
| 561 | } | ||
| 562 | |||
| 563 | |||
| 564 | void semantic_analyze(CodeGen *g) { | ||
| 565 | LLVMInitializeAllTargets(); | ||
| 566 | LLVMInitializeAllTargetMCs(); | ||
| 567 | LLVMInitializeAllAsmPrinters(); | ||
| 568 | LLVMInitializeAllAsmParsers(); | ||
| 569 | LLVMInitializeNativeTarget(); | ||
| 570 | |||
| 571 | g->is_native_target = true; | ||
| 572 | char *native_triple = LLVMGetDefaultTargetTriple(); | ||
| 573 | |||
| 574 | LLVMTargetRef target_ref; | ||
| 575 | char *err_msg = nullptr; | ||
| 576 | if (LLVMGetTargetFromTriple(native_triple, &target_ref, &err_msg)) { | ||
| 577 | zig_panic("unable to get target from triple: %s", err_msg); | ||
| 578 | } | ||
| 579 | |||
| 580 | char *native_cpu = LLVMZigGetHostCPUName(); | ||
| 581 | char *native_features = LLVMZigGetNativeFeatures(); | ||
| 582 | |||
| 583 | LLVMCodeGenOptLevel opt_level = (g->build_type == CodeGenBuildTypeDebug) ? | ||
| 584 | LLVMCodeGenLevelNone : LLVMCodeGenLevelAggressive; | ||
| 585 | |||
| 586 | LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC; | ||
| 587 | |||
| 588 | g->target_machine = LLVMCreateTargetMachine(target_ref, native_triple, | ||
| 589 | native_cpu, native_features, opt_level, reloc_mode, LLVMCodeModelDefault); | ||
| 590 | |||
| 591 | g->target_data_ref = LLVMGetTargetMachineData(g->target_machine); | ||
| 592 | |||
| 593 | |||
| 594 | g->module = LLVMModuleCreateWithName("ZigModule"); | ||
| 595 | |||
| 596 | g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref); | ||
| 597 | |||
| 598 | g->builder = LLVMCreateBuilder(); | ||
| 599 | g->dbuilder = LLVMZigCreateDIBuilder(g->module, true); | ||
| 600 | |||
| 601 | |||
| 602 | define_primitive_types(g); | ||
| 603 | |||
| 604 | analyze_root(g, g->root); | ||
| 605 | } | 596 | } |
| 606 | 597 |
src/analyze.hpp+2-1| ... | @@ -9,7 +9,8 @@ | ... | @@ -9,7 +9,8 @@ |
| 9 | #define ZIG_ANALYZE_HPP | 9 | #define ZIG_ANALYZE_HPP |
| 10 | 10 | ||
| 11 | struct CodeGen; | 11 | struct CodeGen; |
| 12 | struct ImportTableEntry; | ||
| 12 | 13 | ||
| 13 | void semantic_analyze(CodeGen *g); | 14 | void semantic_analyze(CodeGen *g, ImportTableEntry *entry); |
| 14 | 15 | ||
| 15 | #endif | 16 | #endif |
src/codegen.cpp+216-42| ... | @@ -11,26 +11,21 @@ | ... | @@ -11,26 +11,21 @@ |
| 11 | #include "os.hpp" | 11 | #include "os.hpp" |
| 12 | #include "config.h" | 12 | #include "config.h" |
| 13 | #include "error.hpp" | 13 | #include "error.hpp" |
| 14 | |||
| 15 | #include "semantic_info.hpp" | 14 | #include "semantic_info.hpp" |
| 15 | #include "analyze.hpp" | ||
| 16 | 16 | ||
| 17 | #include <stdio.h> | 17 | #include <stdio.h> |
| 18 | #include <errno.h> | 18 | #include <errno.h> |
| 19 | 19 | ||
| 20 | CodeGen *create_codegen(AstNode *root, Buf *in_full_path) { | 20 | CodeGen *codegen_create(Buf *root_source_dir) { |
| 21 | CodeGen *g = allocate<CodeGen>(1); | 21 | CodeGen *g = allocate<CodeGen>(1); |
| 22 | g->root = root; | ||
| 23 | g->fn_table.init(32); | 22 | g->fn_table.init(32); |
| 24 | g->str_table.init(32); | 23 | g->str_table.init(32); |
| 25 | g->type_table.init(32); | 24 | g->type_table.init(32); |
| 26 | g->link_table.init(32); | 25 | g->link_table.init(32); |
| 27 | g->is_static = false; | 26 | g->import_table.init(32); |
| 28 | g->build_type = CodeGenBuildTypeDebug; | 27 | g->build_type = CodeGenBuildTypeDebug; |
| 29 | g->strip_debug_symbols = false; | 28 | g->root_source_dir = root_source_dir; |
| 30 | g->out_name = nullptr; | ||
| 31 | g->out_type = OutTypeUnknown; | ||
| 32 | |||
| 33 | os_path_split(in_full_path, &g->in_dir, &g->in_file); | ||
| 34 | return g; | 29 | return g; |
| 35 | } | 30 | } |
| 36 | 31 | ||
| ... | @@ -42,6 +37,10 @@ void codegen_set_is_static(CodeGen *g, bool is_static) { | ... | @@ -42,6 +37,10 @@ void codegen_set_is_static(CodeGen *g, bool is_static) { |
| 42 | g->is_static = is_static; | 37 | g->is_static = is_static; |
| 43 | } | 38 | } |
| 44 | 39 | ||
| 40 | void codegen_set_verbose(CodeGen *g, bool verbose) { | ||
| 41 | g->verbose = verbose; | ||
| 42 | } | ||
| 43 | |||
| 45 | void codegen_set_strip(CodeGen *g, bool strip) { | 44 | void codegen_set_strip(CodeGen *g, bool strip) { |
| 46 | g->strip_debug_symbols = strip; | 45 | g->strip_debug_symbols = strip; |
| 47 | } | 46 | } |
| ... | @@ -51,7 +50,7 @@ void codegen_set_out_type(CodeGen *g, OutType out_type) { | ... | @@ -51,7 +50,7 @@ void codegen_set_out_type(CodeGen *g, OutType out_type) { |
| 51 | } | 50 | } |
| 52 | 51 | ||
| 53 | void codegen_set_out_name(CodeGen *g, Buf *out_name) { | 52 | void codegen_set_out_name(CodeGen *g, Buf *out_name) { |
| 54 | g->out_name = out_name; | 53 | g->root_out_name = out_name; |
| 55 | } | 54 | } |
| 56 | 55 | ||
| 57 | static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node); | 56 | static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node); |
| ... | @@ -425,16 +424,17 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { | ... | @@ -425,16 +424,17 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 425 | case NodeTypeBlock: | 424 | case NodeTypeBlock: |
| 426 | case NodeTypeExternBlock: | 425 | case NodeTypeExternBlock: |
| 427 | case NodeTypeDirective: | 426 | case NodeTypeDirective: |
| 427 | case NodeTypeUse: | ||
| 428 | zig_unreachable(); | 428 | zig_unreachable(); |
| 429 | } | 429 | } |
| 430 | zig_unreachable(); | 430 | zig_unreachable(); |
| 431 | } | 431 | } |
| 432 | 432 | ||
| 433 | static void gen_block(CodeGen *g, AstNode *block_node, bool add_implicit_return) { | 433 | static void gen_block(CodeGen *g, ImportTableEntry *import, AstNode *block_node, bool add_implicit_return) { |
| 434 | assert(block_node->type == NodeTypeBlock); | 434 | assert(block_node->type == NodeTypeBlock); |
| 435 | 435 | ||
| 436 | LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder, g->block_scopes.last(), | 436 | LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder, g->block_scopes.last(), |
| 437 | g->di_file, block_node->line + 1, block_node->column + 1); | 437 | import->di_file, block_node->line + 1, block_node->column + 1); |
| 438 | g->block_scopes.append(LLVMZigLexicalBlockToScope(di_block)); | 438 | g->block_scopes.append(LLVMZigLexicalBlockToScope(di_block)); |
| 439 | 439 | ||
| 440 | add_debug_source_node(g, block_node); | 440 | add_debug_source_node(g, block_node); |
| ... | @@ -466,22 +466,11 @@ static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnPro | ... | @@ -466,22 +466,11 @@ static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnPro |
| 466 | return LLVMZigCreateSubroutineType(g->dbuilder, di_file, types, types_len, 0); | 466 | return LLVMZigCreateSubroutineType(g->dbuilder, di_file, types, types_len, 0); |
| 467 | } | 467 | } |
| 468 | 468 | ||
| 469 | void code_gen(CodeGen *g) { | 469 | static void do_code_gen(CodeGen *g) { |
| 470 | assert(!g->errors.length); | 470 | assert(!g->errors.length); |
| 471 | 471 | ||
| 472 | Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING); | ||
| 473 | bool is_optimized = g->build_type == CodeGenBuildTypeRelease; | ||
| 474 | const char *flags = ""; | ||
| 475 | unsigned runtime_version = 0; | ||
| 476 | g->compile_unit = LLVMZigCreateCompileUnit(g->dbuilder, LLVMZigLang_DW_LANG_C99(), | ||
| 477 | buf_ptr(&g->in_file), buf_ptr(&g->in_dir), | ||
| 478 | buf_ptr(producer), is_optimized, flags, runtime_version, | ||
| 479 | "", 0, !g->strip_debug_symbols); | ||
| 480 | |||
| 481 | g->block_scopes.append(LLVMZigCompileUnitToScope(g->compile_unit)); | 472 | g->block_scopes.append(LLVMZigCompileUnitToScope(g->compile_unit)); |
| 482 | 473 | ||
| 483 | g->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&g->in_file), buf_ptr(&g->in_dir)); | ||
| 484 | |||
| 485 | 474 | ||
| 486 | // Generate function prototypes | 475 | // Generate function prototypes |
| 487 | auto it = g->fn_table.entry_iterator(); | 476 | auto it = g->fn_table.entry_iterator(); |
| ... | @@ -523,6 +512,7 @@ void code_gen(CodeGen *g) { | ... | @@ -523,6 +512,7 @@ void code_gen(CodeGen *g) { |
| 523 | // Generate function definitions. | 512 | // Generate function definitions. |
| 524 | for (int i = 0; i < g->fn_defs.length; i += 1) { | 513 | for (int i = 0; i < g->fn_defs.length; i += 1) { |
| 525 | FnTableEntry *fn_table_entry = g->fn_defs.at(i); | 514 | FnTableEntry *fn_table_entry = g->fn_defs.at(i); |
| 515 | ImportTableEntry *import = fn_table_entry->import_entry; | ||
| 526 | AstNode *fn_def_node = fn_table_entry->fn_def_node; | 516 | AstNode *fn_def_node = fn_table_entry->fn_def_node; |
| 527 | LLVMValueRef fn = fn_table_entry->fn_value; | 517 | LLVMValueRef fn = fn_table_entry->fn_value; |
| 528 | g->cur_fn = fn_table_entry; | 518 | g->cur_fn = fn_table_entry; |
| ... | @@ -532,14 +522,15 @@ void code_gen(CodeGen *g) { | ... | @@ -532,14 +522,15 @@ void code_gen(CodeGen *g) { |
| 532 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; | 522 | AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; |
| 533 | 523 | ||
| 534 | // Add debug info. | 524 | // Add debug info. |
| 535 | LLVMZigDIScope *fn_scope = LLVMZigFileToScope(g->di_file); | 525 | LLVMZigDIScope *fn_scope = LLVMZigFileToScope(import->di_file); |
| 536 | unsigned line_number = fn_def_node->line + 1; | 526 | unsigned line_number = fn_def_node->line + 1; |
| 537 | unsigned scope_line = line_number; | 527 | unsigned scope_line = line_number; |
| 538 | bool is_definition = true; | 528 | bool is_definition = true; |
| 539 | unsigned flags = 0; | 529 | unsigned flags = 0; |
| 530 | bool is_optimized = g->build_type == CodeGenBuildTypeRelease; | ||
| 540 | LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, | 531 | LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, |
| 541 | fn_scope, buf_ptr(&fn_proto->name), "", g->di_file, line_number, | 532 | fn_scope, buf_ptr(&fn_proto->name), "", import->di_file, line_number, |
| 542 | create_di_function_type(g, fn_proto, g->di_file), fn_table_entry->internal_linkage, | 533 | create_di_function_type(g, fn_proto, import->di_file), fn_table_entry->internal_linkage, |
| 543 | is_definition, scope_line, flags, is_optimized, fn); | 534 | is_definition, scope_line, flags, is_optimized, fn); |
| 544 | 535 | ||
| 545 | g->block_scopes.append(LLVMZigSubprogramToScope(subprogram)); | 536 | g->block_scopes.append(LLVMZigSubprogramToScope(subprogram)); |
| ... | @@ -555,7 +546,7 @@ void code_gen(CodeGen *g) { | ... | @@ -555,7 +546,7 @@ void code_gen(CodeGen *g) { |
| 555 | LLVMGetParams(fn, codegen_fn_def->params); | 546 | LLVMGetParams(fn, codegen_fn_def->params); |
| 556 | 547 | ||
| 557 | bool add_implicit_return = codegen_fn_def->add_implicit_return; | 548 | bool add_implicit_return = codegen_fn_def->add_implicit_return; |
| 558 | gen_block(g, fn_def_node->data.fn_def.body, add_implicit_return); | 549 | gen_block(g, import, fn_def_node->data.fn_def.body, add_implicit_return); |
| 559 | 550 | ||
| 560 | g->block_scopes.pop(); | 551 | g->block_scopes.pop(); |
| 561 | } | 552 | } |
| ... | @@ -563,7 +554,9 @@ void code_gen(CodeGen *g) { | ... | @@ -563,7 +554,9 @@ void code_gen(CodeGen *g) { |
| 563 | 554 | ||
| 564 | LLVMZigDIBuilderFinalize(g->dbuilder); | 555 | LLVMZigDIBuilderFinalize(g->dbuilder); |
| 565 | 556 | ||
| 566 | LLVMDumpModule(g->module); | 557 | if (g->verbose) { |
| 558 | LLVMDumpModule(g->module); | ||
| 559 | } | ||
| 567 | 560 | ||
| 568 | // in release mode, we're sooooo confident that we've generated correct ir, | 561 | // in release mode, we're sooooo confident that we've generated correct ir, |
| 569 | // that we skip the verify module step in order to get better performance. | 562 | // that we skip the verify module step in order to get better performance. |
| ... | @@ -573,13 +566,171 @@ void code_gen(CodeGen *g) { | ... | @@ -573,13 +566,171 @@ void code_gen(CodeGen *g) { |
| 573 | #endif | 566 | #endif |
| 574 | } | 567 | } |
| 575 | 568 | ||
| 576 | void code_gen_optimize(CodeGen *g) { | 569 | static void define_primitive_types(CodeGen *g) { |
| 577 | LLVMZigOptimizeModule(g->target_machine, g->module); | 570 | { |
| 578 | LLVMDumpModule(g->module); | 571 | // if this type is anywhere in the AST, we should never hit codegen. |
| 572 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | ||
| 573 | buf_init_from_str(&entry->name, "(invalid)"); | ||
| 574 | g->builtin_types.entry_invalid = entry; | ||
| 575 | } | ||
| 576 | { | ||
| 577 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | ||
| 578 | entry->type_ref = LLVMInt8Type(); | ||
| 579 | buf_init_from_str(&entry->name, "u8"); | ||
| 580 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 8, 8, | ||
| 581 | LLVMZigEncoding_DW_ATE_unsigned()); | ||
| 582 | g->type_table.put(&entry->name, entry); | ||
| 583 | g->builtin_types.entry_u8 = entry; | ||
| 584 | } | ||
| 585 | { | ||
| 586 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | ||
| 587 | entry->type_ref = LLVMInt32Type(); | ||
| 588 | buf_init_from_str(&entry->name, "i32"); | ||
| 589 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 32, 32, | ||
| 590 | LLVMZigEncoding_DW_ATE_signed()); | ||
| 591 | g->type_table.put(&entry->name, entry); | ||
| 592 | g->builtin_types.entry_i32 = entry; | ||
| 593 | } | ||
| 594 | { | ||
| 595 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | ||
| 596 | entry->type_ref = LLVMVoidType(); | ||
| 597 | buf_init_from_str(&entry->name, "void"); | ||
| 598 | entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 0, 0, | ||
| 599 | LLVMZigEncoding_DW_ATE_unsigned()); | ||
| 600 | g->type_table.put(&entry->name, entry); | ||
| 601 | g->builtin_types.entry_void = entry; | ||
| 602 | } | ||
| 603 | { | ||
| 604 | TypeTableEntry *entry = allocate<TypeTableEntry>(1); | ||
| 605 | entry->type_ref = LLVMVoidType(); | ||
| 606 | buf_init_from_str(&entry->name, "unreachable"); | ||
| 607 | entry->di_type = g->builtin_types.entry_void->di_type; | ||
| 608 | g->type_table.put(&entry->name, entry); | ||
| 609 | g->builtin_types.entry_unreachable = entry; | ||
| 610 | } | ||
| 579 | } | 611 | } |
| 580 | 612 | ||
| 581 | ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g) { | 613 | |
| 582 | return &g->errors; | 614 | |
| 615 | static void init(CodeGen *g, Buf *source_path) { | ||
| 616 | LLVMInitializeAllTargets(); | ||
| 617 | LLVMInitializeAllTargetMCs(); | ||
| 618 | LLVMInitializeAllAsmPrinters(); | ||
| 619 | LLVMInitializeAllAsmParsers(); | ||
| 620 | LLVMInitializeNativeTarget(); | ||
| 621 | |||
| 622 | g->is_native_target = true; | ||
| 623 | char *native_triple = LLVMGetDefaultTargetTriple(); | ||
| 624 | |||
| 625 | LLVMTargetRef target_ref; | ||
| 626 | char *err_msg = nullptr; | ||
| 627 | if (LLVMGetTargetFromTriple(native_triple, &target_ref, &err_msg)) { | ||
| 628 | zig_panic("unable to get target from triple: %s", err_msg); | ||
| 629 | } | ||
| 630 | |||
| 631 | char *native_cpu = LLVMZigGetHostCPUName(); | ||
| 632 | char *native_features = LLVMZigGetNativeFeatures(); | ||
| 633 | |||
| 634 | LLVMCodeGenOptLevel opt_level = (g->build_type == CodeGenBuildTypeDebug) ? | ||
| 635 | LLVMCodeGenLevelNone : LLVMCodeGenLevelAggressive; | ||
| 636 | |||
| 637 | LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC; | ||
| 638 | |||
| 639 | g->target_machine = LLVMCreateTargetMachine(target_ref, native_triple, | ||
| 640 | native_cpu, native_features, opt_level, reloc_mode, LLVMCodeModelDefault); | ||
| 641 | |||
| 642 | g->target_data_ref = LLVMGetTargetMachineData(g->target_machine); | ||
| 643 | |||
| 644 | |||
| 645 | g->module = LLVMModuleCreateWithName("ZigModule"); | ||
| 646 | |||
| 647 | g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref); | ||
| 648 | |||
| 649 | g->builder = LLVMCreateBuilder(); | ||
| 650 | g->dbuilder = LLVMZigCreateDIBuilder(g->module, true); | ||
| 651 | |||
| 652 | |||
| 653 | define_primitive_types(g); | ||
| 654 | |||
| 655 | Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING); | ||
| 656 | bool is_optimized = g->build_type == CodeGenBuildTypeRelease; | ||
| 657 | const char *flags = ""; | ||
| 658 | unsigned runtime_version = 0; | ||
| 659 | g->compile_unit = LLVMZigCreateCompileUnit(g->dbuilder, LLVMZigLang_DW_LANG_C99(), | ||
| 660 | buf_ptr(source_path), buf_ptr(g->root_source_dir), | ||
| 661 | buf_ptr(producer), is_optimized, flags, runtime_version, | ||
| 662 | "", 0, !g->strip_debug_symbols); | ||
| 663 | |||
| 664 | |||
| 665 | } | ||
| 666 | |||
| 667 | void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) { | ||
| 668 | if (!g->initialized) { | ||
| 669 | g->initialized = true; | ||
| 670 | init(g, source_path); | ||
| 671 | } | ||
| 672 | |||
| 673 | Buf full_path = BUF_INIT; | ||
| 674 | os_path_join(g->root_source_dir, source_path, &full_path); | ||
| 675 | |||
| 676 | Buf dirname = BUF_INIT; | ||
| 677 | Buf basename = BUF_INIT; | ||
| 678 | os_path_split(&full_path, &dirname, &basename); | ||
| 679 | |||
| 680 | if (g->verbose) { | ||
| 681 | fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(source_path)); | ||
| 682 | fprintf(stderr, "----------------\n"); | ||
| 683 | fprintf(stderr, "%s\n", buf_ptr(source_code)); | ||
| 684 | |||
| 685 | fprintf(stderr, "\nTokens:\n"); | ||
| 686 | fprintf(stderr, "---------\n"); | ||
| 687 | } | ||
| 688 | |||
| 689 | ZigList<Token> *tokens = tokenize(source_code); | ||
| 690 | |||
| 691 | if (g->verbose) { | ||
| 692 | print_tokens(source_code, tokens); | ||
| 693 | |||
| 694 | fprintf(stderr, "\nAST:\n"); | ||
| 695 | fprintf(stderr, "------\n"); | ||
| 696 | } | ||
| 697 | |||
| 698 | ImportTableEntry *import_entry = allocate<ImportTableEntry>(1); | ||
| 699 | import_entry->root = ast_parse(source_code, tokens); | ||
| 700 | assert(import_entry->root); | ||
| 701 | if (g->verbose) { | ||
| 702 | ast_print(import_entry->root, 0); | ||
| 703 | |||
| 704 | fprintf(stderr, "\nSemantic Analysis:\n"); | ||
| 705 | fprintf(stderr, "--------------------\n"); | ||
| 706 | } | ||
| 707 | |||
| 708 | import_entry->path = source_path; | ||
| 709 | import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&basename), buf_ptr(&dirname)); | ||
| 710 | g->import_table.put(source_path, import_entry); | ||
| 711 | |||
| 712 | semantic_analyze(g, import_entry); | ||
| 713 | |||
| 714 | if (g->errors.length == 0) { | ||
| 715 | if (g->verbose) { | ||
| 716 | fprintf(stderr, "OK\n"); | ||
| 717 | } | ||
| 718 | } else { | ||
| 719 | for (int i = 0; i < g->errors.length; i += 1) { | ||
| 720 | ErrorMsg *err = &g->errors.at(i); | ||
| 721 | fprintf(stderr, "Error: Line %d, column %d: %s\n", | ||
| 722 | err->line_start + 1, err->column_start + 1, | ||
| 723 | buf_ptr(err->msg)); | ||
| 724 | } | ||
| 725 | exit(1); | ||
| 726 | } | ||
| 727 | |||
| 728 | if (g->verbose) { | ||
| 729 | fprintf(stderr, "\nCode Generation:\n"); | ||
| 730 | fprintf(stderr, "------------------\n"); | ||
| 731 | } | ||
| 732 | |||
| 733 | do_code_gen(g); | ||
| 583 | } | 734 | } |
| 584 | 735 | ||
| 585 | static Buf *to_c_type(CodeGen *g, AstNode *type_node) { | 736 | static Buf *to_c_type(CodeGen *g, AstNode *type_node) { |
| ... | @@ -601,15 +752,15 @@ static Buf *to_c_type(CodeGen *g, AstNode *type_node) { | ... | @@ -601,15 +752,15 @@ static Buf *to_c_type(CodeGen *g, AstNode *type_node) { |
| 601 | } | 752 | } |
| 602 | 753 | ||
| 603 | static void generate_h_file(CodeGen *g) { | 754 | static void generate_h_file(CodeGen *g) { |
| 604 | Buf *h_file_out_path = buf_sprintf("%s.h", buf_ptr(g->out_name)); | 755 | Buf *h_file_out_path = buf_sprintf("%s.h", buf_ptr(g->root_out_name)); |
| 605 | FILE *out_h = fopen(buf_ptr(h_file_out_path), "wb"); | 756 | FILE *out_h = fopen(buf_ptr(h_file_out_path), "wb"); |
| 606 | if (!out_h) | 757 | if (!out_h) |
| 607 | zig_panic("unable to open %s: %s", buf_ptr(h_file_out_path), strerror(errno)); | 758 | zig_panic("unable to open %s: %s", buf_ptr(h_file_out_path), strerror(errno)); |
| 608 | 759 | ||
| 609 | Buf *export_macro = buf_sprintf("%s_EXPORT", buf_ptr(g->out_name)); | 760 | Buf *export_macro = buf_sprintf("%s_EXPORT", buf_ptr(g->root_out_name)); |
| 610 | buf_upcase(export_macro); | 761 | buf_upcase(export_macro); |
| 611 | 762 | ||
| 612 | Buf *extern_c_macro = buf_sprintf("%s_EXTERN_C", buf_ptr(g->out_name)); | 763 | Buf *extern_c_macro = buf_sprintf("%s_EXTERN_C", buf_ptr(g->root_out_name)); |
| 613 | buf_upcase(extern_c_macro); | 764 | buf_upcase(extern_c_macro); |
| 614 | 765 | ||
| 615 | Buf h_buf = BUF_INIT; | 766 | Buf h_buf = BUF_INIT; |
| ... | @@ -644,7 +795,8 @@ static void generate_h_file(CodeGen *g) { | ... | @@ -644,7 +795,8 @@ static void generate_h_file(CodeGen *g) { |
| 644 | } | 795 | } |
| 645 | } | 796 | } |
| 646 | 797 | ||
| 647 | Buf *ifdef_dance_name = buf_sprintf("%s_%s_H", buf_ptr(g->out_name), buf_ptr(g->out_name)); | 798 | Buf *ifdef_dance_name = buf_sprintf("%s_%s_H", |
| 799 | buf_ptr(g->root_out_name), buf_ptr(g->root_out_name)); | ||
| 648 | buf_upcase(ifdef_dance_name); | 800 | buf_upcase(ifdef_dance_name); |
| 649 | 801 | ||
| 650 | fprintf(out_h, "#ifndef %s\n", buf_ptr(ifdef_dance_name)); | 802 | fprintf(out_h, "#ifndef %s\n", buf_ptr(ifdef_dance_name)); |
| ... | @@ -677,9 +829,27 @@ static void generate_h_file(CodeGen *g) { | ... | @@ -677,9 +829,27 @@ static void generate_h_file(CodeGen *g) { |
| 677 | zig_panic("unable to close h file: %s", strerror(errno)); | 829 | zig_panic("unable to close h file: %s", strerror(errno)); |
| 678 | } | 830 | } |
| 679 | 831 | ||
| 680 | void code_gen_link(CodeGen *g, const char *out_file) { | 832 | void codegen_link(CodeGen *g, const char *out_file) { |
| 833 | bool is_optimized = (g->build_type == CodeGenBuildTypeRelease); | ||
| 834 | if (is_optimized) { | ||
| 835 | if (g->verbose) { | ||
| 836 | fprintf(stderr, "\nOptimization:\n"); | ||
| 837 | fprintf(stderr, "---------------\n"); | ||
| 838 | } | ||
| 839 | |||
| 840 | LLVMZigOptimizeModule(g->target_machine, g->module); | ||
| 841 | |||
| 842 | if (g->verbose) { | ||
| 843 | LLVMDumpModule(g->module); | ||
| 844 | } | ||
| 845 | } | ||
| 846 | if (g->verbose) { | ||
| 847 | fprintf(stderr, "\nLink:\n"); | ||
| 848 | fprintf(stderr, "-------\n"); | ||
| 849 | } | ||
| 850 | |||
| 681 | if (!out_file) { | 851 | if (!out_file) { |
| 682 | out_file = buf_ptr(g->out_name); | 852 | out_file = buf_ptr(g->root_out_name); |
| 683 | } | 853 | } |
| 684 | 854 | ||
| 685 | Buf out_file_o = BUF_INIT; | 855 | Buf out_file_o = BUF_INIT; |
| ... | @@ -728,8 +898,8 @@ void code_gen_link(CodeGen *g, const char *out_file) { | ... | @@ -728,8 +898,8 @@ void code_gen_link(CodeGen *g, const char *out_file) { |
| 728 | 898 | ||
| 729 | if (g->out_type == OutTypeLib) { | 899 | if (g->out_type == OutTypeLib) { |
| 730 | Buf *out_lib_so = buf_sprintf("lib%s.so.%d.%d.%d", | 900 | Buf *out_lib_so = buf_sprintf("lib%s.so.%d.%d.%d", |
| 731 | buf_ptr(g->out_name), g->version_major, g->version_minor, g->version_patch); | 901 | buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch); |
| 732 | Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->out_name), g->version_major); | 902 | Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->root_out_name), g->version_major); |
| 733 | args.append("-shared"); | 903 | args.append("-shared"); |
| 734 | args.append("-soname"); | 904 | args.append("-soname"); |
| 735 | args.append(buf_ptr(soname)); | 905 | args.append(buf_ptr(soname)); |
| ... | @@ -756,4 +926,8 @@ void code_gen_link(CodeGen *g, const char *out_file) { | ... | @@ -756,4 +926,8 @@ void code_gen_link(CodeGen *g, const char *out_file) { |
| 756 | if (g->out_type == OutTypeLib) { | 926 | if (g->out_type == OutTypeLib) { |
| 757 | generate_h_file(g); | 927 | generate_h_file(g); |
| 758 | } | 928 | } |
| 929 | |||
| 930 | if (g->verbose) { | ||
| 931 | fprintf(stderr, "OK\n"); | ||
| 932 | } | ||
| 759 | } | 933 | } |
src/codegen.hpp+4-7| ... | @@ -29,7 +29,7 @@ struct ErrorMsg { | ... | @@ -29,7 +29,7 @@ struct ErrorMsg { |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
| 31 | 31 | ||
| 32 | CodeGen *create_codegen(AstNode *root, Buf *in_file); | 32 | CodeGen *codegen_create(Buf *root_source_dir); |
| 33 | 33 | ||
| 34 | enum CodeGenBuildType { | 34 | enum CodeGenBuildType { |
| 35 | CodeGenBuildTypeDebug, | 35 | CodeGenBuildTypeDebug, |
| ... | @@ -38,15 +38,12 @@ enum CodeGenBuildType { | ... | @@ -38,15 +38,12 @@ enum CodeGenBuildType { |
| 38 | void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type); | 38 | void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type); |
| 39 | void codegen_set_is_static(CodeGen *codegen, bool is_static); | 39 | void codegen_set_is_static(CodeGen *codegen, bool is_static); |
| 40 | void codegen_set_strip(CodeGen *codegen, bool strip); | 40 | void codegen_set_strip(CodeGen *codegen, bool strip); |
| 41 | void codegen_set_verbose(CodeGen *codegen, bool verbose); | ||
| 41 | void codegen_set_out_type(CodeGen *codegen, OutType out_type); | 42 | void codegen_set_out_type(CodeGen *codegen, OutType out_type); |
| 42 | void codegen_set_out_name(CodeGen *codegen, Buf *out_name); | 43 | void codegen_set_out_name(CodeGen *codegen, Buf *out_name); |
| 43 | 44 | ||
| 44 | void code_gen_optimize(CodeGen *g); | 45 | void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code); |
| 45 | 46 | ||
| 46 | void code_gen(CodeGen *g); | 47 | void codegen_link(CodeGen *g, const char *out_file); |
| 47 | |||
| 48 | void code_gen_link(CodeGen *g, const char *out_file); | ||
| 49 | |||
| 50 | ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g); | ||
| 51 | 48 | ||
| 52 | #endif | 49 | #endif |
src/error.cpp+1| ... | @@ -5,6 +5,7 @@ const char *err_str(int err) { | ... | @@ -5,6 +5,7 @@ const char *err_str(int err) { |
| 5 | case ErrorNone: return "(no error)"; | 5 | case ErrorNone: return "(no error)"; |
| 6 | case ErrorNoMem: return "out of memory"; | 6 | case ErrorNoMem: return "out of memory"; |
| 7 | case ErrorInvalidFormat: return "invalid format"; | 7 | case ErrorInvalidFormat: return "invalid format"; |
| 8 | case ErrorSemanticAnalyzeFail: return "semantic analyze failed"; | ||
| 8 | } | 9 | } |
| 9 | return "(invalid error)"; | 10 | return "(invalid error)"; |
| 10 | } | 11 | } |
src/error.hpp+1| ... | @@ -12,6 +12,7 @@ enum Error { | ... | @@ -12,6 +12,7 @@ enum Error { |
| 12 | ErrorNone, | 12 | ErrorNone, |
| 13 | ErrorNoMem, | 13 | ErrorNoMem, |
| 14 | ErrorInvalidFormat, | 14 | ErrorInvalidFormat, |
| 15 | ErrorSemanticAnalyzeFail, | ||
| 15 | }; | 16 | }; |
| 16 | 17 | ||
| 17 | const char *err_str(int err); | 18 | const char *err_str(int err); |
src/main.cpp+51-119| ... | @@ -6,25 +6,11 @@ | ... | @@ -6,25 +6,11 @@ |
| 6 | */ | 6 | */ |
| 7 | 7 | ||
| 8 | #include "config.h" | 8 | #include "config.h" |
| 9 | #include "util.hpp" | ||
| 10 | #include "list.hpp" | ||
| 11 | #include "buffer.hpp" | 9 | #include "buffer.hpp" |
| 12 | #include "parser.hpp" | ||
| 13 | #include "tokenizer.hpp" | ||
| 14 | #include "error.hpp" | ||
| 15 | #include "codegen.hpp" | 10 | #include "codegen.hpp" |
| 16 | #include "analyze.hpp" | 11 | #include "os.hpp" |
| 17 | 12 | ||
| 18 | #include <stdio.h> | 13 | #include <stdio.h> |
| 19 | #include <string.h> | ||
| 20 | #include <stdlib.h> | ||
| 21 | #include <limits.h> | ||
| 22 | #include <stdint.h> | ||
| 23 | #include <errno.h> | ||
| 24 | #include <sys/types.h> | ||
| 25 | #include <sys/stat.h> | ||
| 26 | #include <unistd.h> | ||
| 27 | #include <inttypes.h> | ||
| 28 | 14 | ||
| 29 | static int usage(const char *arg0) { | 15 | static int usage(const char *arg0) { |
| 30 | fprintf(stderr, "Usage: %s [command] [options] target\n" | 16 | fprintf(stderr, "Usage: %s [command] [options] target\n" |
| ... | @@ -38,6 +24,7 @@ static int usage(const char *arg0) { | ... | @@ -38,6 +24,7 @@ static int usage(const char *arg0) { |
| 38 | " --export [exe|lib|obj] override output type\n" | 24 | " --export [exe|lib|obj] override output type\n" |
| 39 | " --name [name] override output name\n" | 25 | " --name [name] override output name\n" |
| 40 | " --output [file] override destination path\n" | 26 | " --output [file] override destination path\n" |
| 27 | " --verbose turn on compiler debug output\n" | ||
| 41 | , arg0); | 28 | , arg0); |
| 42 | return EXIT_FAILURE; | 29 | return EXIT_FAILURE; |
| 43 | } | 30 | } |
| ... | @@ -47,98 +34,47 @@ static int version(void) { | ... | @@ -47,98 +34,47 @@ static int version(void) { |
| 47 | return EXIT_SUCCESS; | 34 | return EXIT_SUCCESS; |
| 48 | } | 35 | } |
| 49 | 36 | ||
| 50 | static Buf *fetch_file(FILE *f) { | 37 | struct Build { |
| 51 | int fd = fileno(f); | 38 | const char *in_file; |
| 52 | struct stat st; | 39 | const char *out_file; |
| 53 | if (fstat(fd, &st)) | 40 | bool release; |
| 54 | zig_panic("unable to stat file: %s", strerror(errno)); | 41 | bool strip; |
| 55 | off_t big_size = st.st_size; | 42 | bool is_static; |
| 56 | if (big_size > INT_MAX) | 43 | OutType out_type; |
| 57 | zig_panic("file too big"); | 44 | const char *out_name; |
| 58 | int size = (int)big_size; | 45 | bool verbose; |
| 59 | 46 | }; | |
| 60 | Buf *buf = buf_alloc_fixed(size); | ||
| 61 | size_t amt_read = fread(buf_ptr(buf), 1, buf_len(buf), f); | ||
| 62 | if (amt_read != (size_t)buf_len(buf)) | ||
| 63 | zig_panic("error reading: %s", strerror(errno)); | ||
| 64 | |||
| 65 | return buf; | ||
| 66 | } | ||
| 67 | |||
| 68 | static int build(const char *arg0, const char *in_file, const char *out_file, bool release, | ||
| 69 | bool strip, bool is_static, OutType out_type, char *out_name) | ||
| 70 | { | ||
| 71 | static char cur_dir[1024]; | ||
| 72 | 47 | ||
| 73 | if (!in_file) | 48 | static int build(const char *arg0, Build *b) { |
| 49 | if (!b->in_file) | ||
| 74 | return usage(arg0); | 50 | return usage(arg0); |
| 75 | 51 | ||
| 76 | FILE *in_f; | 52 | Buf in_file_buf = BUF_INIT; |
| 77 | if (strcmp(in_file, "-") == 0) { | 53 | buf_init_from_str(&in_file_buf, b->in_file); |
| 78 | in_f = stdin; | ||
| 79 | char *result = getcwd(cur_dir, sizeof(cur_dir)); | ||
| 80 | if (!result) | ||
| 81 | zig_panic("unable to get current working directory: %s", strerror(errno)); | ||
| 82 | } else { | ||
| 83 | in_f = fopen(in_file, "rb"); | ||
| 84 | if (!in_f) | ||
| 85 | zig_panic("unable to open %s for reading: %s\n", in_file, strerror(errno)); | ||
| 86 | } | ||
| 87 | 54 | ||
| 88 | fprintf(stderr, "Original source:\n"); | 55 | Buf root_source_dir = BUF_INIT; |
| 89 | fprintf(stderr, "----------------\n"); | 56 | Buf root_source_code = BUF_INIT; |
| 90 | Buf *in_data = fetch_file(in_f); | 57 | Buf root_source_name = BUF_INIT; |
| 91 | fprintf(stderr, "%s\n", buf_ptr(in_data)); | 58 | if (buf_eql_str(&in_file_buf, "-")) { |
| 92 | 59 | os_get_cwd(&root_source_dir); | |
| 93 | fprintf(stderr, "\nTokens:\n"); | 60 | os_fetch_file(stdin, &root_source_code); |
| 94 | fprintf(stderr, "---------\n"); | 61 | buf_init_from_str(&root_source_name, ""); |
| 95 | ZigList<Token> *tokens = tokenize(in_data); | ||
| 96 | print_tokens(in_data, tokens); | ||
| 97 | |||
| 98 | fprintf(stderr, "\nAST:\n"); | ||
| 99 | fprintf(stderr, "------\n"); | ||
| 100 | AstNode *root = ast_parse(in_data, tokens); | ||
| 101 | assert(root); | ||
| 102 | ast_print(root, 0); | ||
| 103 | |||
| 104 | fprintf(stderr, "\nSemantic Analysis:\n"); | ||
| 105 | fprintf(stderr, "--------------------\n"); | ||
| 106 | CodeGen *codegen = create_codegen(root, buf_create_from_str(in_file)); | ||
| 107 | codegen_set_build_type(codegen, release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug); | ||
| 108 | codegen_set_strip(codegen, strip); | ||
| 109 | codegen_set_is_static(codegen, is_static); | ||
| 110 | if (out_type != OutTypeUnknown) | ||
| 111 | codegen_set_out_type(codegen, out_type); | ||
| 112 | if (out_name) | ||
| 113 | codegen_set_out_name(codegen, buf_create_from_str(out_name)); | ||
| 114 | semantic_analyze(codegen); | ||
| 115 | ZigList<ErrorMsg> *errors = codegen_error_messages(codegen); | ||
| 116 | if (errors->length == 0) { | ||
| 117 | fprintf(stderr, "OK\n"); | ||
| 118 | } else { | 62 | } else { |
| 119 | for (int i = 0; i < errors->length; i += 1) { | 63 | os_path_split(&in_file_buf, &root_source_dir, &root_source_name); |
| 120 | ErrorMsg *err = &errors->at(i); | 64 | os_fetch_file_path(buf_create_from_str(b->in_file), &root_source_code); |
| 121 | fprintf(stderr, "Error: Line %d, column %d: %s\n", | ||
| 122 | err->line_start + 1, err->column_start + 1, | ||
| 123 | buf_ptr(err->msg)); | ||
| 124 | } | ||
| 125 | return 1; | ||
| 126 | } | 65 | } |
| 127 | 66 | ||
| 128 | fprintf(stderr, "\nCode Generation:\n"); | 67 | CodeGen *g = codegen_create(&root_source_dir); |
| 129 | fprintf(stderr, "------------------\n"); | 68 | codegen_set_build_type(g, b->release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug); |
| 130 | code_gen(codegen); | 69 | codegen_set_strip(g, b->strip); |
| 131 | 70 | codegen_set_is_static(g, b->is_static); | |
| 132 | if (release) { | 71 | if (b->out_type != OutTypeUnknown) |
| 133 | fprintf(stderr, "\nOptimization:\n"); | 72 | codegen_set_out_type(g, b->out_type); |
| 134 | fprintf(stderr, "---------------\n"); | 73 | if (b->out_name) |
| 135 | code_gen_optimize(codegen); | 74 | codegen_set_out_name(g, buf_create_from_str(b->out_name)); |
| 136 | } | 75 | codegen_set_verbose(g, b->verbose); |
| 137 | 76 | codegen_add_code(g, &root_source_name, &root_source_code); | |
| 138 | fprintf(stderr, "\nLink:\n"); | 77 | codegen_link(g, b->out_file); |
| 139 | fprintf(stderr, "-------\n"); | ||
| 140 | code_gen_link(codegen, out_file); | ||
| 141 | fprintf(stderr, "OK\n"); | ||
| 142 | 78 | ||
| 143 | return 0; | 79 | return 0; |
| 144 | } | 80 | } |
| ... | @@ -151,43 +87,39 @@ enum Cmd { | ... | @@ -151,43 +87,39 @@ enum Cmd { |
| 151 | 87 | ||
| 152 | int main(int argc, char **argv) { | 88 | int main(int argc, char **argv) { |
| 153 | char *arg0 = argv[0]; | 89 | char *arg0 = argv[0]; |
| 154 | char *in_file = NULL; | ||
| 155 | char *out_file = NULL; | ||
| 156 | bool release = false; | ||
| 157 | bool strip = false; | ||
| 158 | bool is_static = false; | ||
| 159 | |||
| 160 | OutType out_type = OutTypeUnknown; | ||
| 161 | char *out_name = NULL; | ||
| 162 | 90 | ||
| 91 | Build b = {0}; | ||
| 163 | Cmd cmd = CmdNone; | 92 | Cmd cmd = CmdNone; |
| 93 | |||
| 164 | for (int i = 1; i < argc; i += 1) { | 94 | for (int i = 1; i < argc; i += 1) { |
| 165 | char *arg = argv[i]; | 95 | char *arg = argv[i]; |
| 166 | if (arg[0] == '-' && arg[1] == '-') { | 96 | if (arg[0] == '-' && arg[1] == '-') { |
| 167 | if (strcmp(arg, "--release") == 0) { | 97 | if (strcmp(arg, "--release") == 0) { |
| 168 | release = true; | 98 | b.release = true; |
| 169 | } else if (strcmp(arg, "--strip") == 0) { | 99 | } else if (strcmp(arg, "--strip") == 0) { |
| 170 | strip = true; | 100 | b.strip = true; |
| 171 | } else if (strcmp(arg, "--static") == 0) { | 101 | } else if (strcmp(arg, "--static") == 0) { |
| 172 | is_static = true; | 102 | b.is_static = true; |
| 103 | } else if (strcmp(arg, "--verbose") == 0) { | ||
| 104 | b.verbose = true; | ||
| 173 | } else if (i + 1 >= argc) { | 105 | } else if (i + 1 >= argc) { |
| 174 | return usage(arg0); | 106 | return usage(arg0); |
| 175 | } else { | 107 | } else { |
| 176 | i += 1; | 108 | i += 1; |
| 177 | if (strcmp(arg, "--output") == 0) { | 109 | if (strcmp(arg, "--output") == 0) { |
| 178 | out_file = argv[i]; | 110 | b.out_file = argv[i]; |
| 179 | } else if (strcmp(arg, "--export") == 0) { | 111 | } else if (strcmp(arg, "--export") == 0) { |
| 180 | if (strcmp(argv[i], "exe") == 0) { | 112 | if (strcmp(argv[i], "exe") == 0) { |
| 181 | out_type = OutTypeExe; | 113 | b.out_type = OutTypeExe; |
| 182 | } else if (strcmp(argv[i], "lib") == 0) { | 114 | } else if (strcmp(argv[i], "lib") == 0) { |
| 183 | out_type = OutTypeLib; | 115 | b.out_type = OutTypeLib; |
| 184 | } else if (strcmp(argv[i], "obj") == 0) { | 116 | } else if (strcmp(argv[i], "obj") == 0) { |
| 185 | out_type = OutTypeObj; | 117 | b.out_type = OutTypeObj; |
| 186 | } else { | 118 | } else { |
| 187 | return usage(arg0); | 119 | return usage(arg0); |
| 188 | } | 120 | } |
| 189 | } else if (strcmp(arg, "--name") == 0) { | 121 | } else if (strcmp(arg, "--name") == 0) { |
| 190 | out_name = argv[i]; | 122 | b.out_name = argv[i]; |
| 191 | } else { | 123 | } else { |
| 192 | return usage(arg0); | 124 | return usage(arg0); |
| 193 | } | 125 | } |
| ... | @@ -206,8 +138,8 @@ int main(int argc, char **argv) { | ... | @@ -206,8 +138,8 @@ int main(int argc, char **argv) { |
| 206 | case CmdNone: | 138 | case CmdNone: |
| 207 | zig_unreachable(); | 139 | zig_unreachable(); |
| 208 | case CmdBuild: | 140 | case CmdBuild: |
| 209 | if (!in_file) { | 141 | if (!b.in_file) { |
| 210 | in_file = arg; | 142 | b.in_file = arg; |
| 211 | } else { | 143 | } else { |
| 212 | return usage(arg0); | 144 | return usage(arg0); |
| 213 | } | 145 | } |
| ... | @@ -222,7 +154,7 @@ int main(int argc, char **argv) { | ... | @@ -222,7 +154,7 @@ int main(int argc, char **argv) { |
| 222 | case CmdNone: | 154 | case CmdNone: |
| 223 | return usage(arg0); | 155 | return usage(arg0); |
| 224 | case CmdBuild: | 156 | case CmdBuild: |
| 225 | return build(arg0, in_file, out_file, release, strip, is_static, out_type, out_name); | 157 | return build(arg0, &b); |
| 226 | case CmdVersion: | 158 | case CmdVersion: |
| 227 | return version(); | 159 | return version(); |
| 228 | } | 160 | } |
src/os.cpp+51-4| ... | @@ -13,8 +13,8 @@ | ... | @@ -13,8 +13,8 @@ |
| 13 | #include <sys/types.h> | 13 | #include <sys/types.h> |
| 14 | #include <sys/stat.h> | 14 | #include <sys/stat.h> |
| 15 | #include <sys/wait.h> | 15 | #include <sys/wait.h> |
| 16 | #include <stdio.h> | ||
| 17 | #include <fcntl.h> | 16 | #include <fcntl.h> |
| 17 | #include <limits.h> | ||
| 18 | 18 | ||
| 19 | void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached) { | 19 | void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached) { |
| 20 | pid_t pid = fork(); | 20 | pid_t pid = fork(); |
| ... | @@ -37,7 +37,7 @@ void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detache | ... | @@ -37,7 +37,7 @@ void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detache |
| 37 | zig_panic("execvp failed: %s", strerror(errno)); | 37 | zig_panic("execvp failed: %s", strerror(errno)); |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | static void read_all_fd(int fd, Buf *out_buf) { | 40 | static void read_all_fd_stream(int fd, Buf *out_buf) { |
| 41 | static const ssize_t buf_size = 0x2000; | 41 | static const ssize_t buf_size = 0x2000; |
| 42 | buf_resize(out_buf, buf_size); | 42 | buf_resize(out_buf, buf_size); |
| 43 | ssize_t actual_buf_len = 0; | 43 | ssize_t actual_buf_len = 0; |
| ... | @@ -72,6 +72,12 @@ void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) { | ... | @@ -72,6 +72,12 @@ void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) { |
| 72 | buf_init_from_buf(out_basename, full_path); | 72 | buf_init_from_buf(out_basename, full_path); |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) { | ||
| 76 | buf_init_from_buf(out_full_path, dirname); | ||
| 77 | buf_append_char(out_full_path, '/'); | ||
| 78 | buf_append_buf(out_full_path, basename); | ||
| 79 | } | ||
| 80 | |||
| 75 | void os_exec_process(const char *exe, ZigList<const char *> &args, | 81 | void os_exec_process(const char *exe, ZigList<const char *> &args, |
| 76 | int *return_code, Buf *out_stderr, Buf *out_stdout) | 82 | int *return_code, Buf *out_stderr, Buf *out_stdout) |
| 77 | { | 83 | { |
| ... | @@ -117,8 +123,8 @@ void os_exec_process(const char *exe, ZigList<const char *> &args, | ... | @@ -117,8 +123,8 @@ void os_exec_process(const char *exe, ZigList<const char *> &args, |
| 117 | 123 | ||
| 118 | waitpid(pid, return_code, 0); | 124 | waitpid(pid, return_code, 0); |
| 119 | 125 | ||
| 120 | read_all_fd(stdout_pipe[0], out_stdout); | 126 | read_all_fd_stream(stdout_pipe[0], out_stdout); |
| 121 | read_all_fd(stderr_pipe[0], out_stderr); | 127 | read_all_fd_stream(stderr_pipe[0], out_stderr); |
| 122 | 128 | ||
| 123 | } | 129 | } |
| 124 | } | 130 | } |
| ... | @@ -133,3 +139,44 @@ void os_write_file(Buf *full_path, Buf *contents) { | ... | @@ -133,3 +139,44 @@ void os_write_file(Buf *full_path, Buf *contents) { |
| 133 | if (close(fd) == -1) | 139 | if (close(fd) == -1) |
| 134 | zig_panic("close failed"); | 140 | zig_panic("close failed"); |
| 135 | } | 141 | } |
| 142 | |||
| 143 | int os_fetch_file(FILE *f, Buf *out_contents) { | ||
| 144 | int fd = fileno(f); | ||
| 145 | struct stat st; | ||
| 146 | if (fstat(fd, &st)) | ||
| 147 | zig_panic("unable to stat file: %s", strerror(errno)); | ||
| 148 | off_t big_size = st.st_size; | ||
| 149 | if (big_size > INT_MAX) | ||
| 150 | zig_panic("file too big"); | ||
| 151 | int size = (int)big_size; | ||
| 152 | |||
| 153 | buf_resize(out_contents, size); | ||
| 154 | ssize_t ret = read(fd, buf_ptr(out_contents), size); | ||
| 155 | |||
| 156 | if (ret != size) | ||
| 157 | zig_panic("unable to read file: %s", strerror(errno)); | ||
| 158 | |||
| 159 | return 0; | ||
| 160 | } | ||
| 161 | |||
| 162 | int os_fetch_file_path(Buf *full_path, Buf *out_contents) { | ||
| 163 | FILE *f = fopen(buf_ptr(full_path), "rb"); | ||
| 164 | if (!f) | ||
| 165 | zig_panic("unable to open %s: %s\n", buf_ptr(full_path), strerror(errno)); | ||
| 166 | int result = os_fetch_file(f, out_contents); | ||
| 167 | fclose(f); | ||
| 168 | return result; | ||
| 169 | } | ||
| 170 | |||
| 171 | int os_get_cwd(Buf *out_cwd) { | ||
| 172 | int err = ERANGE; | ||
| 173 | buf_resize(out_cwd, 512); | ||
| 174 | while (err == ERANGE) { | ||
| 175 | buf_resize(out_cwd, buf_len(out_cwd) * 2); | ||
| 176 | err = getcwd(buf_ptr(out_cwd), buf_len(out_cwd)) ? 0 : errno; | ||
| 177 | } | ||
| 178 | if (err) | ||
| 179 | zig_panic("unable to get cwd: %s", strerror(err)); | ||
| 180 | |||
| 181 | return 0; | ||
| 182 | } |
src/os.hpp+9| ... | @@ -11,13 +11,22 @@ | ... | @@ -11,13 +11,22 @@ |
| 11 | #include "list.hpp" | 11 | #include "list.hpp" |
| 12 | #include "buffer.hpp" | 12 | #include "buffer.hpp" |
| 13 | 13 | ||
| 14 | #include <stdio.h> | ||
| 15 | |||
| 14 | void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached); | 16 | void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached); |
| 15 | void os_exec_process(const char *exe, ZigList<const char *> &args, | 17 | void os_exec_process(const char *exe, ZigList<const char *> &args, |
| 16 | int *return_code, Buf *out_stderr, Buf *out_stdout); | 18 | int *return_code, Buf *out_stderr, Buf *out_stdout); |
| 17 | 19 | ||
| 18 | void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename); | 20 | void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename); |
| 21 | void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path); | ||
| 19 | 22 | ||
| 20 | void os_write_file(Buf *full_path, Buf *contents); | 23 | void os_write_file(Buf *full_path, Buf *contents); |
| 21 | 24 | ||
| 22 | 25 | ||
| 26 | int os_fetch_file(FILE *file, Buf *out_contents); | ||
| 27 | int os_fetch_file_path(Buf *full_path, Buf *out_contents); | ||
| 28 | |||
| 29 | int os_get_cwd(Buf *out_cwd); | ||
| 30 | |||
| 31 | |||
| 23 | #endif | 32 | #endif |
src/parser.cpp+41-1| ... | @@ -100,6 +100,8 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -100,6 +100,8 @@ const char *node_type_str(NodeType node_type) { |
| 100 | return "Symbol"; | 100 | return "Symbol"; |
| 101 | case NodeTypePrefixOpExpr: | 101 | case NodeTypePrefixOpExpr: |
| 102 | return "PrefixOpExpr"; | 102 | return "PrefixOpExpr"; |
| 103 | case NodeTypeUse: | ||
| 104 | return "Use"; | ||
| 103 | } | 105 | } |
| 104 | zig_unreachable(); | 106 | zig_unreachable(); |
| 105 | } | 107 | } |
| ... | @@ -241,6 +243,9 @@ void ast_print(AstNode *node, int indent) { | ... | @@ -241,6 +243,9 @@ void ast_print(AstNode *node, int indent) { |
| 241 | fprintf(stderr, "PrimaryExpr Symbol %s\n", | 243 | fprintf(stderr, "PrimaryExpr Symbol %s\n", |
| 242 | buf_ptr(&node->data.symbol)); | 244 | buf_ptr(&node->data.symbol)); |
| 243 | break; | 245 | break; |
| 246 | case NodeTypeUse: | ||
| 247 | fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.use.path)); | ||
| 248 | break; | ||
| 244 | } | 249 | } |
| 245 | } | 250 | } |
| 246 | 251 | ||
| ... | @@ -1231,7 +1236,36 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b | ... | @@ -1231,7 +1236,36 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b |
| 1231 | } | 1236 | } |
| 1232 | 1237 | ||
| 1233 | /* | 1238 | /* |
| 1234 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | 1239 | Use : many(Directive) token(Use) token(String) token(Semicolon) |
| 1240 | */ | ||
| 1241 | static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory) { | ||
| 1242 | assert(mandatory == false); | ||
| 1243 | |||
| 1244 | Token *use_kw = &pc->tokens->at(*token_index); | ||
| 1245 | if (use_kw->id != TokenIdKeywordUse) | ||
| 1246 | return nullptr; | ||
| 1247 | *token_index += 1; | ||
| 1248 | |||
| 1249 | Token *use_name = &pc->tokens->at(*token_index); | ||
| 1250 | *token_index += 1; | ||
| 1251 | ast_expect_token(pc, use_name, TokenIdStringLiteral); | ||
| 1252 | |||
| 1253 | Token *semicolon = &pc->tokens->at(*token_index); | ||
| 1254 | *token_index += 1; | ||
| 1255 | ast_expect_token(pc, semicolon, TokenIdSemicolon); | ||
| 1256 | |||
| 1257 | AstNode *node = ast_create_node(NodeTypeUse, use_kw); | ||
| 1258 | |||
| 1259 | parse_string_literal(pc, use_name, &node->data.use.path); | ||
| 1260 | |||
| 1261 | node->data.use.directives = pc->directive_list; | ||
| 1262 | pc->directive_list = nullptr; | ||
| 1263 | |||
| 1264 | return node; | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | /* | ||
| 1268 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | ||
| 1235 | */ | 1269 | */ |
| 1236 | static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) { | 1270 | static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) { |
| 1237 | for (;;) { | 1271 | for (;;) { |
| ... | @@ -1258,6 +1292,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis | ... | @@ -1258,6 +1292,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis |
| 1258 | continue; | 1292 | continue; |
| 1259 | } | 1293 | } |
| 1260 | 1294 | ||
| 1295 | AstNode *use_node = ast_parse_use(pc, token_index, false); | ||
| 1296 | if (use_node) { | ||
| 1297 | top_level_decls->append(use_node); | ||
| 1298 | continue; | ||
| 1299 | } | ||
| 1300 | |||
| 1261 | if (pc->directive_list->length > 0) { | 1301 | if (pc->directive_list->length > 0) { |
| 1262 | ast_error(directive_token, "invalid directive"); | 1302 | ast_error(directive_token, "invalid directive"); |
| 1263 | } | 1303 | } |
src/parser.hpp+7| ... | @@ -35,6 +35,7 @@ enum NodeType { | ... | @@ -35,6 +35,7 @@ enum NodeType { |
| 35 | NodeTypeSymbol, | 35 | NodeTypeSymbol, |
| 36 | NodeTypePrefixOpExpr, | 36 | NodeTypePrefixOpExpr, |
| 37 | NodeTypeFnCallExpr, | 37 | NodeTypeFnCallExpr, |
| 38 | NodeTypeUse, | ||
| 38 | }; | 39 | }; |
| 39 | 40 | ||
| 40 | struct AstNodeRoot { | 41 | struct AstNodeRoot { |
| ... | @@ -158,6 +159,11 @@ struct AstNodePrefixOpExpr { | ... | @@ -158,6 +159,11 @@ struct AstNodePrefixOpExpr { |
| 158 | AstNode *primary_expr; | 159 | AstNode *primary_expr; |
| 159 | }; | 160 | }; |
| 160 | 161 | ||
| 162 | struct AstNodeUse { | ||
| 163 | Buf path; | ||
| 164 | ZigList<AstNode *> *directives; | ||
| 165 | }; | ||
| 166 | |||
| 161 | struct AstNode { | 167 | struct AstNode { |
| 162 | enum NodeType type; | 168 | enum NodeType type; |
| 163 | AstNode *parent; | 169 | AstNode *parent; |
| ... | @@ -180,6 +186,7 @@ struct AstNode { | ... | @@ -180,6 +186,7 @@ struct AstNode { |
| 180 | AstNodeCastExpr cast_expr; | 186 | AstNodeCastExpr cast_expr; |
| 181 | AstNodePrefixOpExpr prefix_op_expr; | 187 | AstNodePrefixOpExpr prefix_op_expr; |
| 182 | AstNodeFnCallExpr fn_call_expr; | 188 | AstNodeFnCallExpr fn_call_expr; |
| 189 | AstNodeUse use; | ||
| 183 | Buf number; | 190 | Buf number; |
| 184 | Buf string; | 191 | Buf string; |
| 185 | Buf symbol; | 192 | Buf symbol; |
src/semantic_info.hpp+23-14| ... | @@ -12,15 +12,6 @@ | ... | @@ -12,15 +12,6 @@ |
| 12 | #include "hash_map.hpp" | 12 | #include "hash_map.hpp" |
| 13 | #include "zig_llvm.hpp" | 13 | #include "zig_llvm.hpp" |
| 14 | 14 | ||
| 15 | struct FnTableEntry { | ||
| 16 | LLVMValueRef fn_value; | ||
| 17 | AstNode *proto_node; | ||
| 18 | AstNode *fn_def_node; | ||
| 19 | bool is_extern; | ||
| 20 | bool internal_linkage; | ||
| 21 | unsigned calling_convention; | ||
| 22 | }; | ||
| 23 | |||
| 24 | struct TypeTableEntry { | 15 | struct TypeTableEntry { |
| 25 | LLVMTypeRef type_ref; | 16 | LLVMTypeRef type_ref; |
| 26 | LLVMZigDIType *di_type; | 17 | LLVMZigDIType *di_type; |
| ... | @@ -33,17 +24,35 @@ struct TypeTableEntry { | ... | @@ -33,17 +24,35 @@ struct TypeTableEntry { |
| 33 | TypeTableEntry *pointer_mut_parent; | 24 | TypeTableEntry *pointer_mut_parent; |
| 34 | }; | 25 | }; |
| 35 | 26 | ||
| 27 | struct ImportTableEntry { | ||
| 28 | AstNode *root; | ||
| 29 | Buf *path; // relative to root_source_dir | ||
| 30 | LLVMZigDIFile *di_file; | ||
| 31 | }; | ||
| 32 | |||
| 33 | struct FnTableEntry { | ||
| 34 | LLVMValueRef fn_value; | ||
| 35 | AstNode *proto_node; | ||
| 36 | AstNode *fn_def_node; | ||
| 37 | bool is_extern; | ||
| 38 | bool internal_linkage; | ||
| 39 | unsigned calling_convention; | ||
| 40 | ImportTableEntry *import_entry; | ||
| 41 | }; | ||
| 42 | |||
| 36 | struct CodeGen { | 43 | struct CodeGen { |
| 37 | LLVMModuleRef module; | 44 | LLVMModuleRef module; |
| 38 | AstNode *root; | ||
| 39 | ZigList<ErrorMsg> errors; | 45 | ZigList<ErrorMsg> errors; |
| 40 | LLVMBuilderRef builder; | 46 | LLVMBuilderRef builder; |
| 41 | LLVMZigDIBuilder *dbuilder; | 47 | LLVMZigDIBuilder *dbuilder; |
| 42 | LLVMZigDICompileUnit *compile_unit; | 48 | LLVMZigDICompileUnit *compile_unit; |
| 49 | |||
| 50 | // reminder: hash tables must be initialized before use | ||
| 43 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; | 51 | HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; |
| 44 | HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table; | 52 | HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table; |
| 45 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table; | 53 | HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table; |
| 46 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table; | 54 | HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table; |
| 55 | HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table; | ||
| 47 | 56 | ||
| 48 | struct { | 57 | struct { |
| 49 | TypeTableEntry *entry_u8; | 58 | TypeTableEntry *entry_u8; |
| ... | @@ -60,12 +69,10 @@ struct CodeGen { | ... | @@ -60,12 +69,10 @@ struct CodeGen { |
| 60 | CodeGenBuildType build_type; | 69 | CodeGenBuildType build_type; |
| 61 | LLVMTargetMachineRef target_machine; | 70 | LLVMTargetMachineRef target_machine; |
| 62 | bool is_native_target; | 71 | bool is_native_target; |
| 63 | Buf in_file; | 72 | Buf *root_source_dir; |
| 64 | Buf in_dir; | 73 | Buf *root_out_name; |
| 65 | ZigList<LLVMZigDIScope *> block_scopes; | 74 | ZigList<LLVMZigDIScope *> block_scopes; |
| 66 | LLVMZigDIFile *di_file; | ||
| 67 | ZigList<FnTableEntry *> fn_defs; | 75 | ZigList<FnTableEntry *> fn_defs; |
| 68 | Buf *out_name; | ||
| 69 | OutType out_type; | 76 | OutType out_type; |
| 70 | FnTableEntry *cur_fn; | 77 | FnTableEntry *cur_fn; |
| 71 | bool c_stdint_used; | 78 | bool c_stdint_used; |
| ... | @@ -73,6 +80,8 @@ struct CodeGen { | ... | @@ -73,6 +80,8 @@ struct CodeGen { |
| 73 | int version_major; | 80 | int version_major; |
| 74 | int version_minor; | 81 | int version_minor; |
| 75 | int version_patch; | 82 | int version_patch; |
| 83 | bool verbose; | ||
| 84 | bool initialized; | ||
| 76 | }; | 85 | }; |
| 77 | 86 | ||
| 78 | struct TypeNode { | 87 | struct TypeNode { |
src/tokenizer.cpp+3| ... | @@ -180,6 +180,8 @@ static void end_token(Tokenize *t) { | ... | @@ -180,6 +180,8 @@ static void end_token(Tokenize *t) { |
| 180 | t->cur_tok->id = TokenIdKeywordExport; | 180 | t->cur_tok->id = TokenIdKeywordExport; |
| 181 | } else if (mem_eql_str(token_mem, token_len, "as")) { | 181 | } else if (mem_eql_str(token_mem, token_len, "as")) { |
| 182 | t->cur_tok->id = TokenIdKeywordAs; | 182 | t->cur_tok->id = TokenIdKeywordAs; |
| 183 | } else if (mem_eql_str(token_mem, token_len, "use")) { | ||
| 184 | t->cur_tok->id = TokenIdKeywordUse; | ||
| 183 | } | 185 | } |
| 184 | 186 | ||
| 185 | t->cur_tok = nullptr; | 187 | t->cur_tok = nullptr; |
| ... | @@ -562,6 +564,7 @@ static const char * token_name(Token *token) { | ... | @@ -562,6 +564,7 @@ static const char * token_name(Token *token) { |
| 562 | case TokenIdKeywordPub: return "Pub"; | 564 | case TokenIdKeywordPub: return "Pub"; |
| 563 | case TokenIdKeywordExport: return "Export"; | 565 | case TokenIdKeywordExport: return "Export"; |
| 564 | case TokenIdKeywordAs: return "As"; | 566 | case TokenIdKeywordAs: return "As"; |
| 567 | case TokenIdKeywordUse: return "Use"; | ||
| 565 | case TokenIdLParen: return "LParen"; | 568 | case TokenIdLParen: return "LParen"; |
| 566 | case TokenIdRParen: return "RParen"; | 569 | case TokenIdRParen: return "RParen"; |
| 567 | case TokenIdComma: return "Comma"; | 570 | case TokenIdComma: return "Comma"; |
src/tokenizer.hpp+1| ... | @@ -22,6 +22,7 @@ enum TokenId { | ... | @@ -22,6 +22,7 @@ enum TokenId { |
| 22 | TokenIdKeywordPub, | 22 | TokenIdKeywordPub, |
| 23 | TokenIdKeywordExport, | 23 | TokenIdKeywordExport, |
| 24 | TokenIdKeywordAs, | 24 | TokenIdKeywordAs, |
| 25 | TokenIdKeywordUse, | ||
| 25 | TokenIdLParen, | 26 | TokenIdLParen, |
| 26 | TokenIdRParen, | 27 | TokenIdRParen, |
| 27 | TokenIdComma, | 28 | TokenIdComma, |
test/run_tests.cpp+2| ... | @@ -47,6 +47,7 @@ static void add_simple_case(const char *case_name, const char *source, const cha | ... | @@ -47,6 +47,7 @@ static void add_simple_case(const char *case_name, const char *source, const cha |
| 47 | test_case->compiler_args.append(tmp_exe_path); | 47 | test_case->compiler_args.append(tmp_exe_path); |
| 48 | test_case->compiler_args.append("--release"); | 48 | test_case->compiler_args.append("--release"); |
| 49 | test_case->compiler_args.append("--strip"); | 49 | test_case->compiler_args.append("--strip"); |
| 50 | test_case->compiler_args.append("--verbose"); | ||
| 50 | 51 | ||
| 51 | test_cases.append(test_case); | 52 | test_cases.append(test_case); |
| 52 | } | 53 | } |
| ... | @@ -70,6 +71,7 @@ static void add_compile_fail_case(const char *case_name, const char *source, int | ... | @@ -70,6 +71,7 @@ static void add_compile_fail_case(const char *case_name, const char *source, int |
| 70 | test_case->compiler_args.append(tmp_exe_path); | 71 | test_case->compiler_args.append(tmp_exe_path); |
| 71 | test_case->compiler_args.append("--release"); | 72 | test_case->compiler_args.append("--release"); |
| 72 | test_case->compiler_args.append("--strip"); | 73 | test_case->compiler_args.append("--strip"); |
| 74 | test_case->compiler_args.append("--verbose"); | ||
| 73 | 75 | ||
| 74 | test_cases.append(test_case); | 76 | test_cases.append(test_case); |
| 75 | 77 |