authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-30 19:58:53-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-30 20:00:39-07:00
log55b8472374eede496b59396dbe253b05b16063e1
treec2d9be8780e272d4fc6fc1a59b20e9a8c1dab755
parentef482ece7c047e898fdc2ea15ba4216c15309d0c

refactor code to prepare for multiple files

verbose compiler output is now behind --verbose flag

26 files changed, 490 insertions(+), 303 deletions(-)

CMakeLists.txt+4-4
...@@ -22,16 +22,16 @@ include_directories(...@@ -22,16 +22,16 @@ include_directories(
22)22)
2323
24set(ZIG_SOURCES24set(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)
3636
37set(TEST_SOURCES37set(TEST_SOURCES
README.md+3-1
...@@ -79,7 +79,9 @@ zig | C equivalent | Description...@@ -79,7 +79,9 @@ zig | C equivalent | Description
79```79```
80Root : many(TopLevelDecl) token(EOF)80Root : many(TopLevelDecl) token(EOF)
8181
82TopLevelDecl : FnDef | ExternBlock | RootExportDecl82TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use
83
84Use : many(Directive) token(Use) token(String) token(Semicolon)
8385
84RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon)86RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon)
8587
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 finish7 finish
8endif8endif
99
10syn keyword zigKeyword fn return mut const extern unreachable export pub as10syn keyword zigKeyword fn return mut const extern unreachable export pub as use
11syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void11syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void
1212
13syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell13syn 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=
1919
20syn keyword zigTodo contained TODO XXX20syn keyword zigTodo contained TODO XXX
2121
22syn match zigEscapeError display contained /\\./
23syn match zigEscape display contained /\\\([nrt0\\'"]\|x\x\{2}\)/
24syn match zigEscapeUnicode display contained /\\\(u\x\{4}\|U\x\{8}\)/
25syn match zigEscapeUnicode display contained /\\u{\x\{1,6}}/
26syn match zigStringContinuation display contained /\\\n\s*/
27syn region zigString start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=zigEscape,zigEscapeError,zigStringContinuation
28syn region zigString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=zigEscape,zigEscapeUnicode,zigEscapeError,zigStringContinuation,@Spell
29syn region zigString start='b\?r\z(#*\)"' end='"\z1' contains=@Spell
30
22let b:current_syntax = "zig"31let b:current_syntax = "zig"
2332
24hi def link zigKeyword Keyword33hi def link zigKeyword Keyword
...@@ -28,4 +37,8 @@ hi def link zigCommentLineDoc SpecialComment...@@ -28,4 +37,8 @@ hi def link zigCommentLineDoc SpecialComment
28hi def link zigCommentBlock zigCommentLine37hi def link zigCommentBlock zigCommentLine
29hi def link zigCommentBlockDoc zigCommentLineDoc38hi def link zigCommentBlockDoc zigCommentLineDoc
30hi def link zigTodo Todo39hi def link zigTodo Todo
3140hi def link zigStringContinuation Special
41hi def link zigString String
42hi def link zigEscape Special
43hi def link zigEscapeUnicode zigEscape
44hi def link zigEscapeError Error
example/hello.zig deleted-12
...@@ -1,12 +0,0 @@
1export executable "hello";
2
3#link("c")
4extern {
5 fn puts(s: *mut u8) -> i32;
6 fn exit(code: i32) -> unreachable;
7}
8
9export fn _start() -> unreachable {
10 puts("Hello, world!");
11 exit(0);
12}
example/hello_world/hello.zig created+12
...@@ -0,0 +1,12 @@
1export executable "hello";
2
3#link("c")
4extern {
5 fn puts(s: *mut u8) -> i32;
6 fn exit(code: i32) -> unreachable;
7}
8
9export 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")
2export library "mathtest";
3
4export fn add(a: i32, b: i32) -> i32 {
5 return a + b;
6}
example/multiple_files/foo.zig created+5
...@@ -0,0 +1,5 @@
1use "libc.zig";
2
3fn print_text() {
4 puts("it works!");
5}
example/multiple_files/libc.zig created+5
...@@ -0,0 +1,5 @@
1#link("c")
2extern {
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 @@
1export executable "test";
2
3use "libc.zig";
4use "foo.zig";
5
6fn _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")
2export library "mathtest";
3
4export 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
4int main(int argc, char **argv) {
5 printf("%d\n", add(42, 1137));
6 return 0;
7}
src/analyze.cpp+15-90
...@@ -113,7 +113,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node) {...@@ -113,7 +113,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node) {
113 resolve_type(g, node->data.fn_proto.return_type);113 resolve_type(g, node->data.fn_proto.return_type);
114}114}
115115
116static void preview_function_declarations(CodeGen *g, AstNode *node) {116static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, AstNode *node) {
117 switch (node->type) {117 switch (node->type) {
118 case NodeTypeExternBlock:118 case NodeTypeExternBlock:
119 for (int i = 0; i < node->data.extern_block.directives->length; i += 1) {119 for (int i = 0; i < node->data.extern_block.directives->length; i += 1) {
...@@ -139,6 +139,7 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {...@@ -139,6 +139,7 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {
139 fn_table_entry->proto_node = fn_proto;139 fn_table_entry->proto_node = fn_proto;
140 fn_table_entry->is_extern = true;140 fn_table_entry->is_extern = true;
141 fn_table_entry->calling_convention = LLVMCCallConv;141 fn_table_entry->calling_convention = LLVMCCallConv;
142 fn_table_entry->import_entry = import;
142 g->fn_table.put(name, fn_table_entry);143 g->fn_table.put(name, fn_table_entry);
143 }144 }
144 break;145 break;
...@@ -156,6 +157,7 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {...@@ -156,6 +157,7 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {
156 node->codegen_node->data.fn_def_node.skip = true;157 node->codegen_node->data.fn_def_node.skip = true;
157 } else {158 } else {
158 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);159 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
160 fn_table_entry->import_entry = import;
159 fn_table_entry->proto_node = proto_node;161 fn_table_entry->proto_node = proto_node;
160 fn_table_entry->fn_def_node = node;162 fn_table_entry->fn_def_node = node;
161 fn_table_entry->internal_linkage = proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport;163 fn_table_entry->internal_linkage = proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport;
...@@ -190,8 +192,8 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {...@@ -190,8 +192,8 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {
190 } else {192 } else {
191 g->root_export_decl = node;193 g->root_export_decl = node;
192194
193 if (!g->out_name)195 if (!g->root_out_name)
194 g->out_name = &node->data.root_export_decl.name;196 g->root_out_name = &node->data.root_export_decl.name;
195197
196 Buf *out_type = &node->data.root_export_decl.type;198 Buf *out_type = &node->data.root_export_decl.type;
197 OutType export_out_type;199 OutType export_out_type;
...@@ -209,6 +211,9 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {...@@ -209,6 +211,9 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {
209 g->out_type = export_out_type;211 g->out_type = export_out_type;
210 }212 }
211 break;213 break;
214 case NodeTypeUse:
215 zig_panic("TODO use");
216 break;
212 case NodeTypeDirective:217 case NodeTypeDirective:
213 case NodeTypeParamDecl:218 case NodeTypeParamDecl:
214 case NodeTypeFnProto:219 case NodeTypeFnProto:
...@@ -346,6 +351,7 @@ static void analyze_expression(CodeGen *g, AstNode *node) {...@@ -346,6 +351,7 @@ static void analyze_expression(CodeGen *g, AstNode *node) {
346 case NodeTypeRootExportDecl:351 case NodeTypeRootExportDecl:
347 case NodeTypeExternBlock:352 case NodeTypeExternBlock:
348 case NodeTypeFnDef:353 case NodeTypeFnDef:
354 case NodeTypeUse:
349 zig_unreachable();355 zig_unreachable();
350 }356 }
351}357}
...@@ -377,9 +383,9 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {...@@ -377,9 +383,9 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
377383
378 case NodeTypeRootExportDecl:384 case NodeTypeRootExportDecl:
379 case NodeTypeExternBlock:385 case NodeTypeExternBlock:
386 case NodeTypeUse:
380 // already looked at these in the preview pass387 // already looked at these in the preview pass
381 break;388 break;
382
383 case NodeTypeDirective:389 case NodeTypeDirective:
384 case NodeTypeParamDecl:390 case NodeTypeParamDecl:
385 case NodeTypeFnProto:391 case NodeTypeFnProto:
...@@ -400,13 +406,13 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {...@@ -400,13 +406,13 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
400 }406 }
401}407}
402408
403static void analyze_root(CodeGen *g, AstNode *node) {409static void analyze_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
404 assert(node->type == NodeTypeRoot);410 assert(node->type == NodeTypeRoot);
405411
406 // find function declarations412 // find function declarations
407 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {413 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
408 AstNode *child = node->data.root.top_level_decls.at(i);414 AstNode *child = node->data.root.top_level_decls.at(i);
409 preview_function_declarations(g, child);415 preview_function_declarations(g, import, child);
410 }416 }
411417
412 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {418 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
...@@ -414,7 +420,7 @@ static void analyze_root(CodeGen *g, AstNode *node) {...@@ -414,7 +420,7 @@ static void analyze_root(CodeGen *g, AstNode *node) {
414 analyze_top_level_declaration(g, child);420 analyze_top_level_declaration(g, child);
415 }421 }
416422
417 if (!g->out_name) {423 if (!g->root_out_name) {
418 add_node_error(g, node,424 add_node_error(g, node,
419 buf_sprintf("missing export declaration and output name not provided"));425 buf_sprintf("missing export declaration and output name not provided"));
420 } else if (g->out_type == OutTypeUnknown) {426 } else if (g->out_type == OutTypeUnknown) {
...@@ -423,88 +429,7 @@ static void analyze_root(CodeGen *g, AstNode *node) {...@@ -423,88 +429,7 @@ static void analyze_root(CodeGen *g, AstNode *node) {
423 }429 }
424}430}
425431
426static void define_primitive_types(CodeGen *g) {432void semantic_analyze(CodeGen *g, ImportTableEntry *import_table_entry) {
427 {433 analyze_root(g, import_table_entry, import_table_entry->root);
428 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
429 entry->type_ref = LLVMInt8Type();
430 buf_init_from_str(&entry->name, "u8");
431 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 8, 8,
432 LLVMZigEncoding_DW_ATE_unsigned());
433 g->type_table.put(&entry->name, entry);
434 g->builtin_types.entry_u8 = entry;
435 }
436 {
437 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
438 entry->type_ref = LLVMInt32Type();
439 buf_init_from_str(&entry->name, "i32");
440 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 32, 32,
441 LLVMZigEncoding_DW_ATE_signed());
442 g->type_table.put(&entry->name, entry);
443 g->builtin_types.entry_i32 = entry;
444 }
445 {
446 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
447 entry->type_ref = LLVMVoidType();
448 buf_init_from_str(&entry->name, "void");
449 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 0, 0,
450 LLVMZigEncoding_DW_ATE_unsigned());
451 g->type_table.put(&entry->name, entry);
452 g->builtin_types.entry_void = entry;
453
454 // invalid types are void
455 g->builtin_types.entry_invalid = entry;
456 }
457 {
458 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
459 entry->type_ref = LLVMVoidType();
460 buf_init_from_str(&entry->name, "unreachable");
461 entry->di_type = g->builtin_types.entry_invalid->di_type;
462 g->type_table.put(&entry->name, entry);
463 g->builtin_types.entry_unreachable = entry;
464 }
465}
466
467
468void semantic_analyze(CodeGen *g) {
469 LLVMInitializeAllTargets();
470 LLVMInitializeAllTargetMCs();
471 LLVMInitializeAllAsmPrinters();
472 LLVMInitializeAllAsmParsers();
473 LLVMInitializeNativeTarget();
474
475 g->is_native_target = true;
476 char *native_triple = LLVMGetDefaultTargetTriple();
477
478 LLVMTargetRef target_ref;
479 char *err_msg = nullptr;
480 if (LLVMGetTargetFromTriple(native_triple, &target_ref, &err_msg)) {
481 zig_panic("unable to get target from triple: %s", err_msg);
482 }
483
484 char *native_cpu = LLVMZigGetHostCPUName();
485 char *native_features = LLVMZigGetNativeFeatures();
486
487 LLVMCodeGenOptLevel opt_level = (g->build_type == CodeGenBuildTypeDebug) ?
488 LLVMCodeGenLevelNone : LLVMCodeGenLevelAggressive;
489
490 LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC;
491
492 g->target_machine = LLVMCreateTargetMachine(target_ref, native_triple,
493 native_cpu, native_features, opt_level, reloc_mode, LLVMCodeModelDefault);
494
495 g->target_data_ref = LLVMGetTargetMachineData(g->target_machine);
496
497
498 g->module = LLVMModuleCreateWithName("ZigModule");
499
500 g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref);
501
502 g->builder = LLVMCreateBuilder();
503 g->dbuilder = LLVMZigCreateDIBuilder(g->module, true);
504
505
506 define_primitive_types(g);
507
508 analyze_root(g, g->root);
509}434}
510435
src/analyze.hpp+2-1
...@@ -9,7 +9,8 @@...@@ -9,7 +9,8 @@
9#define ZIG_ANALYZE_HPP9#define ZIG_ANALYZE_HPP
1010
11struct CodeGen;11struct CodeGen;
12struct ImportTableEntry;
1213
13void semantic_analyze(CodeGen *g);14void semantic_analyze(CodeGen *g, ImportTableEntry *entry);
1415
15#endif16#endif
src/codegen.cpp+213-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"
1616
17#include <stdio.h>17#include <stdio.h>
18#include <errno.h>18#include <errno.h>
1919
20CodeGen *create_codegen(AstNode *root, Buf *in_full_path) {20CodeGen *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}
3631
...@@ -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}
4439
40void codegen_set_verbose(CodeGen *g, bool verbose) {
41 g->verbose = verbose;
42}
43
45void codegen_set_strip(CodeGen *g, bool strip) {44void 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}
5251
53void codegen_set_out_name(CodeGen *g, Buf *out_name) {52void codegen_set_out_name(CodeGen *g, Buf *out_name) {
54 g->out_name = out_name;53 g->root_out_name = out_name;
55}54}
5655
57static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);56static 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}
432432
433static void gen_block(CodeGen *g, AstNode *block_node, bool add_implicit_return) {433static 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);
435435
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));
439439
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}
468468
469void code_gen(CodeGen *g) {469static void do_code_gen(CodeGen *g) {
470 assert(!g->errors.length);470 assert(!g->errors.length);
471471
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));
482473
483 g->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&g->in_file), buf_ptr(&g->in_dir));
484
485474
486 // Generate function prototypes475 // 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;
533523
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);
544535
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);
556547
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);
559550
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) {
563554
564 LLVMZigDIBuilderFinalize(g->dbuilder);555 LLVMZigDIBuilderFinalize(g->dbuilder);
565556
566 LLVMDumpModule(g->module);557 if (g->verbose) {
558 LLVMDumpModule(g->module);
559 }
567560
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,168 @@ void code_gen(CodeGen *g) {...@@ -573,13 +566,168 @@ void code_gen(CodeGen *g) {
573#endif566#endif
574}567}
575568
576void code_gen_optimize(CodeGen *g) {569static void define_primitive_types(CodeGen *g) {
577 LLVMZigOptimizeModule(g->target_machine, g->module);570 {
578 LLVMDumpModule(g->module);571 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
572 entry->type_ref = LLVMInt8Type();
573 buf_init_from_str(&entry->name, "u8");
574 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 8, 8,
575 LLVMZigEncoding_DW_ATE_unsigned());
576 g->type_table.put(&entry->name, entry);
577 g->builtin_types.entry_u8 = entry;
578 }
579 {
580 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
581 entry->type_ref = LLVMInt32Type();
582 buf_init_from_str(&entry->name, "i32");
583 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 32, 32,
584 LLVMZigEncoding_DW_ATE_signed());
585 g->type_table.put(&entry->name, entry);
586 g->builtin_types.entry_i32 = entry;
587 }
588 {
589 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
590 entry->type_ref = LLVMVoidType();
591 buf_init_from_str(&entry->name, "void");
592 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 0, 0,
593 LLVMZigEncoding_DW_ATE_unsigned());
594 g->type_table.put(&entry->name, entry);
595 g->builtin_types.entry_void = entry;
596
597 // invalid types are void
598 g->builtin_types.entry_invalid = entry;
599 }
600 {
601 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
602 entry->type_ref = LLVMVoidType();
603 buf_init_from_str(&entry->name, "unreachable");
604 entry->di_type = g->builtin_types.entry_invalid->di_type;
605 g->type_table.put(&entry->name, entry);
606 g->builtin_types.entry_unreachable = entry;
607 }
579}608}
580609
581ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g) {610
582 return &g->errors;611
612static void init(CodeGen *g, Buf *source_path) {
613 LLVMInitializeAllTargets();
614 LLVMInitializeAllTargetMCs();
615 LLVMInitializeAllAsmPrinters();
616 LLVMInitializeAllAsmParsers();
617 LLVMInitializeNativeTarget();
618
619 g->is_native_target = true;
620 char *native_triple = LLVMGetDefaultTargetTriple();
621
622 LLVMTargetRef target_ref;
623 char *err_msg = nullptr;
624 if (LLVMGetTargetFromTriple(native_triple, &target_ref, &err_msg)) {
625 zig_panic("unable to get target from triple: %s", err_msg);
626 }
627
628 char *native_cpu = LLVMZigGetHostCPUName();
629 char *native_features = LLVMZigGetNativeFeatures();
630
631 LLVMCodeGenOptLevel opt_level = (g->build_type == CodeGenBuildTypeDebug) ?
632 LLVMCodeGenLevelNone : LLVMCodeGenLevelAggressive;
633
634 LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC;
635
636 g->target_machine = LLVMCreateTargetMachine(target_ref, native_triple,
637 native_cpu, native_features, opt_level, reloc_mode, LLVMCodeModelDefault);
638
639 g->target_data_ref = LLVMGetTargetMachineData(g->target_machine);
640
641
642 g->module = LLVMModuleCreateWithName("ZigModule");
643
644 g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref);
645
646 g->builder = LLVMCreateBuilder();
647 g->dbuilder = LLVMZigCreateDIBuilder(g->module, true);
648
649
650 define_primitive_types(g);
651
652 Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING);
653 bool is_optimized = g->build_type == CodeGenBuildTypeRelease;
654 const char *flags = "";
655 unsigned runtime_version = 0;
656 g->compile_unit = LLVMZigCreateCompileUnit(g->dbuilder, LLVMZigLang_DW_LANG_C99(),
657 buf_ptr(source_path), buf_ptr(g->root_source_dir),
658 buf_ptr(producer), is_optimized, flags, runtime_version,
659 "", 0, !g->strip_debug_symbols);
660
661
662}
663
664void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
665 if (!g->initialized) {
666 g->initialized = true;
667 init(g, source_path);
668 }
669
670 Buf full_path = BUF_INIT;
671 os_path_join(g->root_source_dir, source_path, &full_path);
672
673 Buf dirname = BUF_INIT;
674 Buf basename = BUF_INIT;
675 os_path_split(&full_path, &dirname, &basename);
676
677 if (g->verbose) {
678 fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(source_path));
679 fprintf(stderr, "----------------\n");
680 fprintf(stderr, "%s\n", buf_ptr(source_code));
681
682 fprintf(stderr, "\nTokens:\n");
683 fprintf(stderr, "---------\n");
684 }
685
686 ZigList<Token> *tokens = tokenize(source_code);
687
688 if (g->verbose) {
689 print_tokens(source_code, tokens);
690
691 fprintf(stderr, "\nAST:\n");
692 fprintf(stderr, "------\n");
693 }
694
695 ImportTableEntry *import_entry = allocate<ImportTableEntry>(1);
696 import_entry->root = ast_parse(source_code, tokens);
697 assert(import_entry->root);
698 if (g->verbose) {
699 ast_print(import_entry->root, 0);
700
701 fprintf(stderr, "\nSemantic Analysis:\n");
702 fprintf(stderr, "--------------------\n");
703 }
704
705 import_entry->path = source_path;
706 import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&basename), buf_ptr(&dirname));
707 g->import_table.put(source_path, import_entry);
708
709 semantic_analyze(g, import_entry);
710
711 if (g->errors.length == 0) {
712 if (g->verbose) {
713 fprintf(stderr, "OK\n");
714 }
715 } else {
716 for (int i = 0; i < g->errors.length; i += 1) {
717 ErrorMsg *err = &g->errors.at(i);
718 fprintf(stderr, "Error: Line %d, column %d: %s\n",
719 err->line_start + 1, err->column_start + 1,
720 buf_ptr(err->msg));
721 }
722 exit(1);
723 }
724
725 if (g->verbose) {
726 fprintf(stderr, "\nCode Generation:\n");
727 fprintf(stderr, "------------------\n");
728 }
729
730 do_code_gen(g);
583}731}
584732
585static Buf *to_c_type(CodeGen *g, AstNode *type_node) {733static Buf *to_c_type(CodeGen *g, AstNode *type_node) {
...@@ -601,15 +749,15 @@ static Buf *to_c_type(CodeGen *g, AstNode *type_node) {...@@ -601,15 +749,15 @@ static Buf *to_c_type(CodeGen *g, AstNode *type_node) {
601}749}
602750
603static void generate_h_file(CodeGen *g) {751static void generate_h_file(CodeGen *g) {
604 Buf *h_file_out_path = buf_sprintf("%s.h", buf_ptr(g->out_name));752 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");753 FILE *out_h = fopen(buf_ptr(h_file_out_path), "wb");
606 if (!out_h)754 if (!out_h)
607 zig_panic("unable to open %s: %s", buf_ptr(h_file_out_path), strerror(errno));755 zig_panic("unable to open %s: %s", buf_ptr(h_file_out_path), strerror(errno));
608756
609 Buf *export_macro = buf_sprintf("%s_EXPORT", buf_ptr(g->out_name));757 Buf *export_macro = buf_sprintf("%s_EXPORT", buf_ptr(g->root_out_name));
610 buf_upcase(export_macro);758 buf_upcase(export_macro);
611759
612 Buf *extern_c_macro = buf_sprintf("%s_EXTERN_C", buf_ptr(g->out_name));760 Buf *extern_c_macro = buf_sprintf("%s_EXTERN_C", buf_ptr(g->root_out_name));
613 buf_upcase(extern_c_macro);761 buf_upcase(extern_c_macro);
614762
615 Buf h_buf = BUF_INIT;763 Buf h_buf = BUF_INIT;
...@@ -644,7 +792,8 @@ static void generate_h_file(CodeGen *g) {...@@ -644,7 +792,8 @@ static void generate_h_file(CodeGen *g) {
644 }792 }
645 }793 }
646794
647 Buf *ifdef_dance_name = buf_sprintf("%s_%s_H", buf_ptr(g->out_name), buf_ptr(g->out_name));795 Buf *ifdef_dance_name = buf_sprintf("%s_%s_H",
796 buf_ptr(g->root_out_name), buf_ptr(g->root_out_name));
648 buf_upcase(ifdef_dance_name);797 buf_upcase(ifdef_dance_name);
649798
650 fprintf(out_h, "#ifndef %s\n", buf_ptr(ifdef_dance_name));799 fprintf(out_h, "#ifndef %s\n", buf_ptr(ifdef_dance_name));
...@@ -677,9 +826,27 @@ static void generate_h_file(CodeGen *g) {...@@ -677,9 +826,27 @@ static void generate_h_file(CodeGen *g) {
677 zig_panic("unable to close h file: %s", strerror(errno));826 zig_panic("unable to close h file: %s", strerror(errno));
678}827}
679828
680void code_gen_link(CodeGen *g, const char *out_file) {829void codegen_link(CodeGen *g, const char *out_file) {
830 bool is_optimized = (g->build_type == CodeGenBuildTypeRelease);
831 if (is_optimized) {
832 if (g->verbose) {
833 fprintf(stderr, "\nOptimization:\n");
834 fprintf(stderr, "---------------\n");
835 }
836
837 LLVMZigOptimizeModule(g->target_machine, g->module);
838
839 if (g->verbose) {
840 LLVMDumpModule(g->module);
841 }
842 }
843 if (g->verbose) {
844 fprintf(stderr, "\nLink:\n");
845 fprintf(stderr, "-------\n");
846 }
847
681 if (!out_file) {848 if (!out_file) {
682 out_file = buf_ptr(g->out_name);849 out_file = buf_ptr(g->root_out_name);
683 }850 }
684851
685 Buf out_file_o = BUF_INIT;852 Buf out_file_o = BUF_INIT;
...@@ -728,8 +895,8 @@ void code_gen_link(CodeGen *g, const char *out_file) {...@@ -728,8 +895,8 @@ void code_gen_link(CodeGen *g, const char *out_file) {
728895
729 if (g->out_type == OutTypeLib) {896 if (g->out_type == OutTypeLib) {
730 Buf *out_lib_so = buf_sprintf("lib%s.so.%d.%d.%d",897 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);898 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);899 Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->root_out_name), g->version_major);
733 args.append("-shared");900 args.append("-shared");
734 args.append("-soname");901 args.append("-soname");
735 args.append(buf_ptr(soname));902 args.append(buf_ptr(soname));
...@@ -756,4 +923,8 @@ void code_gen_link(CodeGen *g, const char *out_file) {...@@ -756,4 +923,8 @@ void code_gen_link(CodeGen *g, const char *out_file) {
756 if (g->out_type == OutTypeLib) {923 if (g->out_type == OutTypeLib) {
757 generate_h_file(g);924 generate_h_file(g);
758 }925 }
926
927 if (g->verbose) {
928 fprintf(stderr, "OK\n");
929 }
759}930}
src/codegen.hpp+4-7
...@@ -29,7 +29,7 @@ struct ErrorMsg {...@@ -29,7 +29,7 @@ struct ErrorMsg {
29};29};
3030
3131
32CodeGen *create_codegen(AstNode *root, Buf *in_file);32CodeGen *codegen_create(Buf *root_source_dir);
3333
34enum CodeGenBuildType {34enum CodeGenBuildType {
35 CodeGenBuildTypeDebug,35 CodeGenBuildTypeDebug,
...@@ -38,15 +38,12 @@ enum CodeGenBuildType {...@@ -38,15 +38,12 @@ enum CodeGenBuildType {
38void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type);38void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type);
39void codegen_set_is_static(CodeGen *codegen, bool is_static);39void codegen_set_is_static(CodeGen *codegen, bool is_static);
40void codegen_set_strip(CodeGen *codegen, bool strip);40void codegen_set_strip(CodeGen *codegen, bool strip);
41void codegen_set_verbose(CodeGen *codegen, bool verbose);
41void codegen_set_out_type(CodeGen *codegen, OutType out_type);42void codegen_set_out_type(CodeGen *codegen, OutType out_type);
42void codegen_set_out_name(CodeGen *codegen, Buf *out_name);43void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
4344
44void code_gen_optimize(CodeGen *g);45void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code);
4546
46void code_gen(CodeGen *g);47void codegen_link(CodeGen *g, const char *out_file);
47
48void code_gen_link(CodeGen *g, const char *out_file);
49
50ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g);
5148
52#endif49#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};
1617
17const char *err_str(int err);18const char *err_str(int err);
src/main.cpp+51-119
...@@ -6,25 +6,11 @@...@@ -6,25 +6,11 @@
6 */6 */
77
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"
1712
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>
2814
29static int usage(const char *arg0) {15static 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}
4936
50static Buf *fetch_file(FILE *f) {37struct 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;
5946};
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
68static 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];
7247
73 if (!in_file)48static int build(const char *arg0, Build *b) {
49 if (!b->in_file)
74 return usage(arg0);50 return usage(arg0);
7551
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 }
8754
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, "-")) {
9259 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 }
12766
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);
13170 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);
13776 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");
14278
143 return 0;79 return 0;
144}80}
...@@ -151,43 +87,39 @@ enum Cmd {...@@ -151,43 +87,39 @@ enum Cmd {
15187
152int main(int argc, char **argv) {88int 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;
16290
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>
1818
19void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached) {19void 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}
3939
40static void read_all_fd(int fd, Buf *out_buf) {40static 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}
7474
75void 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
75void os_exec_process(const char *exe, ZigList<const char *> &args,81void 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,
117123
118 waitpid(pid, return_code, 0);124 waitpid(pid, return_code, 0);
119125
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);
122128
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
143int 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
162int 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
171int 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"
1313
14#include <stdio.h>
15
14void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached);16void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached);
15void os_exec_process(const char *exe, ZigList<const char *> &args,17void 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);
1719
18void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);20void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
21void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);
1922
20void os_write_file(Buf *full_path, Buf *contents);23void os_write_file(Buf *full_path, Buf *contents);
2124
2225
26int os_fetch_file(FILE *file, Buf *out_contents);
27int os_fetch_file_path(Buf *full_path, Buf *out_contents);
28
29int os_get_cwd(Buf *out_cwd);
30
31
23#endif32#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}
246251
...@@ -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}
12321237
1233/*1238/*
1234TopLevelDecl : FnDef | ExternBlock | RootExportDecl1239Use : many(Directive) token(Use) token(String) token(Semicolon)
1240*/
1241static 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/*
1268TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use
1235*/1269*/
1236static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {1270static 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 }
12601294
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};
3940
40struct AstNodeRoot {41struct AstNodeRoot {
...@@ -158,6 +159,11 @@ struct AstNodePrefixOpExpr {...@@ -158,6 +159,11 @@ struct AstNodePrefixOpExpr {
158 AstNode *primary_expr;159 AstNode *primary_expr;
159};160};
160161
162struct AstNodeUse {
163 Buf path;
164 ZigList<AstNode *> *directives;
165};
166
161struct AstNode {167struct 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"
1414
15struct 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
24struct TypeTableEntry {15struct 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};
3526
27struct ImportTableEntry {
28 AstNode *root;
29 Buf *path; // relative to root_source_dir
30 LLVMZigDIFile *di_file;
31};
32
33struct 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
36struct CodeGen {43struct 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;
4756
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};
7786
78struct TypeNode {87struct 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 }
184186
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");
5051
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");
7375
74 test_cases.append(test_case);76 test_cases.append(test_case);
7577