From 55b8472374eede496b59396dbe253b05b16063e1 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Mon, 30 Nov 2015 19:58:53 -0700 Subject: [PATCH] refactor code to prepare for multiple files verbose compiler output is now behind --verbose flag --- CMakeLists.txt | 10 +- README.md | 4 +- doc/vim/syntax/zig.vim | 17 +- example/{ => hello_world}/hello.zig | 0 example/multiple_files/foo.zig | 5 + example/multiple_files/libc.zig | 5 + example/multiple_files/main.zig | 9 + example/{ => shared_library}/mathtest.zig | 0 example/shared_library/test.c | 7 + src/analyze.cpp | 105 ++------- src/analyze.hpp | 3 +- src/codegen.cpp | 255 ++++++++++++++++++---- src/codegen.hpp | 11 +- src/error.cpp | 1 + src/error.hpp | 1 + src/main.cpp | 172 +++++---------- src/os.cpp | 55 ++++- src/os.hpp | 9 + src/parser.cpp | 42 +++- src/parser.hpp | 7 + src/semantic_info.hpp | 37 ++-- src/tokenizer.cpp | 3 + src/tokenizer.hpp | 1 + test/run_tests.cpp | 2 + 24 files changed, 474 insertions(+), 287 deletions(-) rename example/{ => hello_world}/hello.zig (100%) create mode 100644 example/multiple_files/foo.zig create mode 100644 example/multiple_files/libc.zig create mode 100644 example/multiple_files/main.zig rename example/{ => shared_library}/mathtest.zig (100%) create mode 100644 example/shared_library/test.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 44e7c43170..e8c78213ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,16 +22,16 @@ include_directories( ) set(ZIG_SOURCES + "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" + "${CMAKE_SOURCE_DIR}/src/parser.cpp" "${CMAKE_SOURCE_DIR}/src/analyze.cpp" + "${CMAKE_SOURCE_DIR}/src/codegen.cpp" "${CMAKE_SOURCE_DIR}/src/buffer.cpp" "${CMAKE_SOURCE_DIR}/src/error.cpp" "${CMAKE_SOURCE_DIR}/src/main.cpp" - "${CMAKE_SOURCE_DIR}/src/parser.cpp" - "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp" - "${CMAKE_SOURCE_DIR}/src/util.cpp" - "${CMAKE_SOURCE_DIR}/src/codegen.cpp" - "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" "${CMAKE_SOURCE_DIR}/src/os.cpp" + "${CMAKE_SOURCE_DIR}/src/util.cpp" + "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp" ) set(TEST_SOURCES diff --git a/README.md b/README.md index 8e4bc96d61..6311010156 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,9 @@ zig | C equivalent | Description ``` Root : many(TopLevelDecl) token(EOF) -TopLevelDecl : FnDef | ExternBlock | RootExportDecl +TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use + +Use : many(Directive) token(Use) token(String) token(Semicolon) RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon) diff --git a/doc/vim/syntax/zig.vim b/doc/vim/syntax/zig.vim index ab51dfc996..1527cb8049 100644 --- a/doc/vim/syntax/zig.vim +++ b/doc/vim/syntax/zig.vim @@ -7,7 +7,7 @@ if exists("b:current_syntax") finish endif -syn keyword zigKeyword fn return mut const extern unreachable export pub as +syn keyword zigKeyword fn return mut const extern unreachable export pub as use syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell @@ -19,6 +19,15 @@ syn region zigCommentBlockDocNest matchgroup=zigCommentBlockDoc start="/\*" end= syn keyword zigTodo contained TODO XXX +syn match zigEscapeError display contained /\\./ +syn match zigEscape display contained /\\\([nrt0\\'"]\|x\x\{2}\)/ +syn match zigEscapeUnicode display contained /\\\(u\x\{4}\|U\x\{8}\)/ +syn match zigEscapeUnicode display contained /\\u{\x\{1,6}}/ +syn match zigStringContinuation display contained /\\\n\s*/ +syn region zigString start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=zigEscape,zigEscapeError,zigStringContinuation +syn region zigString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=zigEscape,zigEscapeUnicode,zigEscapeError,zigStringContinuation,@Spell +syn region zigString start='b\?r\z(#*\)"' end='"\z1' contains=@Spell + let b:current_syntax = "zig" hi def link zigKeyword Keyword @@ -28,4 +37,8 @@ hi def link zigCommentLineDoc SpecialComment hi def link zigCommentBlock zigCommentLine hi def link zigCommentBlockDoc zigCommentLineDoc hi def link zigTodo Todo - +hi def link zigStringContinuation Special +hi def link zigString String +hi def link zigEscape Special +hi def link zigEscapeUnicode zigEscape +hi def link zigEscapeError Error diff --git a/example/hello.zig b/example/hello_world/hello.zig similarity index 100% rename from example/hello.zig rename to example/hello_world/hello.zig diff --git a/example/multiple_files/foo.zig b/example/multiple_files/foo.zig new file mode 100644 index 0000000000..aacc49a556 --- /dev/null +++ b/example/multiple_files/foo.zig @@ -0,0 +1,5 @@ +use "libc.zig"; + +fn print_text() { + puts("it works!"); +} diff --git a/example/multiple_files/libc.zig b/example/multiple_files/libc.zig new file mode 100644 index 0000000000..7d1a5bebd9 --- /dev/null +++ b/example/multiple_files/libc.zig @@ -0,0 +1,5 @@ +#link("c") +extern { + fn puts(s: *mut u8) -> i32; + fn exit(code: i32) -> unreachable; +} diff --git a/example/multiple_files/main.zig b/example/multiple_files/main.zig new file mode 100644 index 0000000000..993d4234c2 --- /dev/null +++ b/example/multiple_files/main.zig @@ -0,0 +1,9 @@ +export executable "test"; + +use "libc.zig"; +use "foo.zig"; + +fn _start() -> unreachable { + print_text(); + exit(0); +} diff --git a/example/mathtest.zig b/example/shared_library/mathtest.zig similarity index 100% rename from example/mathtest.zig rename to example/shared_library/mathtest.zig diff --git a/example/shared_library/test.c b/example/shared_library/test.c new file mode 100644 index 0000000000..4fff250f08 --- /dev/null +++ b/example/shared_library/test.c @@ -0,0 +1,7 @@ +#include "mathtest.h" +#include + +int main(int argc, char **argv) { + printf("%d\n", add(42, 1137)); + return 0; +} diff --git a/src/analyze.cpp b/src/analyze.cpp index 8dae356e81..131bc22e52 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -113,7 +113,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node) { resolve_type(g, node->data.fn_proto.return_type); } -static void preview_function_declarations(CodeGen *g, AstNode *node) { +static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, AstNode *node) { switch (node->type) { case NodeTypeExternBlock: 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) { fn_table_entry->proto_node = fn_proto; fn_table_entry->is_extern = true; fn_table_entry->calling_convention = LLVMCCallConv; + fn_table_entry->import_entry = import; g->fn_table.put(name, fn_table_entry); } break; @@ -156,6 +157,7 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) { node->codegen_node->data.fn_def_node.skip = true; } else { FnTableEntry *fn_table_entry = allocate(1); + fn_table_entry->import_entry = import; fn_table_entry->proto_node = proto_node; fn_table_entry->fn_def_node = node; 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) { } else { g->root_export_decl = node; - if (!g->out_name) - g->out_name = &node->data.root_export_decl.name; + if (!g->root_out_name) + g->root_out_name = &node->data.root_export_decl.name; Buf *out_type = &node->data.root_export_decl.type; OutType export_out_type; @@ -209,6 +211,9 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) { g->out_type = export_out_type; } break; + case NodeTypeUse: + zig_panic("TODO use"); + break; case NodeTypeDirective: case NodeTypeParamDecl: case NodeTypeFnProto: @@ -346,6 +351,7 @@ static void analyze_expression(CodeGen *g, AstNode *node) { case NodeTypeRootExportDecl: case NodeTypeExternBlock: case NodeTypeFnDef: + case NodeTypeUse: zig_unreachable(); } } @@ -377,9 +383,9 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) { case NodeTypeRootExportDecl: case NodeTypeExternBlock: + case NodeTypeUse: // already looked at these in the preview pass break; - case NodeTypeDirective: case NodeTypeParamDecl: case NodeTypeFnProto: @@ -400,13 +406,13 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) { } } -static void analyze_root(CodeGen *g, AstNode *node) { +static void analyze_root(CodeGen *g, ImportTableEntry *import, AstNode *node) { assert(node->type == NodeTypeRoot); // find function declarations for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { AstNode *child = node->data.root.top_level_decls.at(i); - preview_function_declarations(g, child); + preview_function_declarations(g, import, child); } 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) { analyze_top_level_declaration(g, child); } - if (!g->out_name) { + if (!g->root_out_name) { add_node_error(g, node, buf_sprintf("missing export declaration and output name not provided")); } else if (g->out_type == OutTypeUnknown) { @@ -423,88 +429,7 @@ static void analyze_root(CodeGen *g, AstNode *node) { } } -static void define_primitive_types(CodeGen *g) { - { - TypeTableEntry *entry = allocate(1); - entry->type_ref = LLVMInt8Type(); - buf_init_from_str(&entry->name, "u8"); - entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 8, 8, - LLVMZigEncoding_DW_ATE_unsigned()); - g->type_table.put(&entry->name, entry); - g->builtin_types.entry_u8 = entry; - } - { - TypeTableEntry *entry = allocate(1); - entry->type_ref = LLVMInt32Type(); - buf_init_from_str(&entry->name, "i32"); - entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 32, 32, - LLVMZigEncoding_DW_ATE_signed()); - g->type_table.put(&entry->name, entry); - g->builtin_types.entry_i32 = entry; - } - { - TypeTableEntry *entry = allocate(1); - entry->type_ref = LLVMVoidType(); - buf_init_from_str(&entry->name, "void"); - entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 0, 0, - LLVMZigEncoding_DW_ATE_unsigned()); - g->type_table.put(&entry->name, entry); - g->builtin_types.entry_void = entry; - - // invalid types are void - g->builtin_types.entry_invalid = entry; - } - { - TypeTableEntry *entry = allocate(1); - entry->type_ref = LLVMVoidType(); - buf_init_from_str(&entry->name, "unreachable"); - entry->di_type = g->builtin_types.entry_invalid->di_type; - g->type_table.put(&entry->name, entry); - g->builtin_types.entry_unreachable = entry; - } -} - - -void semantic_analyze(CodeGen *g) { - LLVMInitializeAllTargets(); - LLVMInitializeAllTargetMCs(); - LLVMInitializeAllAsmPrinters(); - LLVMInitializeAllAsmParsers(); - LLVMInitializeNativeTarget(); - - g->is_native_target = true; - char *native_triple = LLVMGetDefaultTargetTriple(); - - LLVMTargetRef target_ref; - char *err_msg = nullptr; - if (LLVMGetTargetFromTriple(native_triple, &target_ref, &err_msg)) { - zig_panic("unable to get target from triple: %s", err_msg); - } - - char *native_cpu = LLVMZigGetHostCPUName(); - char *native_features = LLVMZigGetNativeFeatures(); - - LLVMCodeGenOptLevel opt_level = (g->build_type == CodeGenBuildTypeDebug) ? - LLVMCodeGenLevelNone : LLVMCodeGenLevelAggressive; - - LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC; - - g->target_machine = LLVMCreateTargetMachine(target_ref, native_triple, - native_cpu, native_features, opt_level, reloc_mode, LLVMCodeModelDefault); - - g->target_data_ref = LLVMGetTargetMachineData(g->target_machine); - - - g->module = LLVMModuleCreateWithName("ZigModule"); - - g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref); - - g->builder = LLVMCreateBuilder(); - g->dbuilder = LLVMZigCreateDIBuilder(g->module, true); - - - define_primitive_types(g); - - analyze_root(g, g->root); +void semantic_analyze(CodeGen *g, ImportTableEntry *import_table_entry) { + analyze_root(g, import_table_entry, import_table_entry->root); } diff --git a/src/analyze.hpp b/src/analyze.hpp index 0dca23194d..374fcad748 100644 --- a/src/analyze.hpp +++ b/src/analyze.hpp @@ -9,7 +9,8 @@ #define ZIG_ANALYZE_HPP struct CodeGen; +struct ImportTableEntry; -void semantic_analyze(CodeGen *g); +void semantic_analyze(CodeGen *g, ImportTableEntry *entry); #endif diff --git a/src/codegen.cpp b/src/codegen.cpp index c5e90cf75a..b854f343f0 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -11,26 +11,21 @@ #include "os.hpp" #include "config.h" #include "error.hpp" - #include "semantic_info.hpp" +#include "analyze.hpp" #include #include -CodeGen *create_codegen(AstNode *root, Buf *in_full_path) { +CodeGen *codegen_create(Buf *root_source_dir) { CodeGen *g = allocate(1); - g->root = root; g->fn_table.init(32); g->str_table.init(32); g->type_table.init(32); g->link_table.init(32); - g->is_static = false; + g->import_table.init(32); g->build_type = CodeGenBuildTypeDebug; - g->strip_debug_symbols = false; - g->out_name = nullptr; - g->out_type = OutTypeUnknown; - - os_path_split(in_full_path, &g->in_dir, &g->in_file); + g->root_source_dir = root_source_dir; return g; } @@ -42,6 +37,10 @@ void codegen_set_is_static(CodeGen *g, bool is_static) { g->is_static = is_static; } +void codegen_set_verbose(CodeGen *g, bool verbose) { + g->verbose = verbose; +} + void codegen_set_strip(CodeGen *g, bool strip) { g->strip_debug_symbols = strip; } @@ -51,7 +50,7 @@ void codegen_set_out_type(CodeGen *g, OutType out_type) { } void codegen_set_out_name(CodeGen *g, Buf *out_name) { - g->out_name = out_name; + g->root_out_name = out_name; } static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node); @@ -425,16 +424,17 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { case NodeTypeBlock: case NodeTypeExternBlock: case NodeTypeDirective: + case NodeTypeUse: zig_unreachable(); } zig_unreachable(); } -static void gen_block(CodeGen *g, AstNode *block_node, bool add_implicit_return) { +static void gen_block(CodeGen *g, ImportTableEntry *import, AstNode *block_node, bool add_implicit_return) { assert(block_node->type == NodeTypeBlock); LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder, g->block_scopes.last(), - g->di_file, block_node->line + 1, block_node->column + 1); + import->di_file, block_node->line + 1, block_node->column + 1); g->block_scopes.append(LLVMZigLexicalBlockToScope(di_block)); add_debug_source_node(g, block_node); @@ -466,22 +466,11 @@ static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnPro return LLVMZigCreateSubroutineType(g->dbuilder, di_file, types, types_len, 0); } -void code_gen(CodeGen *g) { +static void do_code_gen(CodeGen *g) { assert(!g->errors.length); - Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING); - bool is_optimized = g->build_type == CodeGenBuildTypeRelease; - const char *flags = ""; - unsigned runtime_version = 0; - g->compile_unit = LLVMZigCreateCompileUnit(g->dbuilder, LLVMZigLang_DW_LANG_C99(), - buf_ptr(&g->in_file), buf_ptr(&g->in_dir), - buf_ptr(producer), is_optimized, flags, runtime_version, - "", 0, !g->strip_debug_symbols); - g->block_scopes.append(LLVMZigCompileUnitToScope(g->compile_unit)); - g->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&g->in_file), buf_ptr(&g->in_dir)); - // Generate function prototypes auto it = g->fn_table.entry_iterator(); @@ -523,6 +512,7 @@ void code_gen(CodeGen *g) { // Generate function definitions. for (int i = 0; i < g->fn_defs.length; i += 1) { FnTableEntry *fn_table_entry = g->fn_defs.at(i); + ImportTableEntry *import = fn_table_entry->import_entry; AstNode *fn_def_node = fn_table_entry->fn_def_node; LLVMValueRef fn = fn_table_entry->fn_value; g->cur_fn = fn_table_entry; @@ -532,14 +522,15 @@ void code_gen(CodeGen *g) { AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; // Add debug info. - LLVMZigDIScope *fn_scope = LLVMZigFileToScope(g->di_file); + LLVMZigDIScope *fn_scope = LLVMZigFileToScope(import->di_file); unsigned line_number = fn_def_node->line + 1; unsigned scope_line = line_number; bool is_definition = true; unsigned flags = 0; + bool is_optimized = g->build_type == CodeGenBuildTypeRelease; LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, - fn_scope, buf_ptr(&fn_proto->name), "", g->di_file, line_number, - create_di_function_type(g, fn_proto, g->di_file), fn_table_entry->internal_linkage, + fn_scope, buf_ptr(&fn_proto->name), "", import->di_file, line_number, + create_di_function_type(g, fn_proto, import->di_file), fn_table_entry->internal_linkage, is_definition, scope_line, flags, is_optimized, fn); g->block_scopes.append(LLVMZigSubprogramToScope(subprogram)); @@ -555,7 +546,7 @@ void code_gen(CodeGen *g) { LLVMGetParams(fn, codegen_fn_def->params); bool add_implicit_return = codegen_fn_def->add_implicit_return; - gen_block(g, fn_def_node->data.fn_def.body, add_implicit_return); + gen_block(g, import, fn_def_node->data.fn_def.body, add_implicit_return); g->block_scopes.pop(); } @@ -563,7 +554,9 @@ void code_gen(CodeGen *g) { LLVMZigDIBuilderFinalize(g->dbuilder); - LLVMDumpModule(g->module); + if (g->verbose) { + LLVMDumpModule(g->module); + } // in release mode, we're sooooo confident that we've generated correct ir, // that we skip the verify module step in order to get better performance. @@ -573,13 +566,168 @@ void code_gen(CodeGen *g) { #endif } -void code_gen_optimize(CodeGen *g) { - LLVMZigOptimizeModule(g->target_machine, g->module); - LLVMDumpModule(g->module); +static void define_primitive_types(CodeGen *g) { + { + TypeTableEntry *entry = allocate(1); + entry->type_ref = LLVMInt8Type(); + buf_init_from_str(&entry->name, "u8"); + entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 8, 8, + LLVMZigEncoding_DW_ATE_unsigned()); + g->type_table.put(&entry->name, entry); + g->builtin_types.entry_u8 = entry; + } + { + TypeTableEntry *entry = allocate(1); + entry->type_ref = LLVMInt32Type(); + buf_init_from_str(&entry->name, "i32"); + entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 32, 32, + LLVMZigEncoding_DW_ATE_signed()); + g->type_table.put(&entry->name, entry); + g->builtin_types.entry_i32 = entry; + } + { + TypeTableEntry *entry = allocate(1); + entry->type_ref = LLVMVoidType(); + buf_init_from_str(&entry->name, "void"); + entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 0, 0, + LLVMZigEncoding_DW_ATE_unsigned()); + g->type_table.put(&entry->name, entry); + g->builtin_types.entry_void = entry; + + // invalid types are void + g->builtin_types.entry_invalid = entry; + } + { + TypeTableEntry *entry = allocate(1); + entry->type_ref = LLVMVoidType(); + buf_init_from_str(&entry->name, "unreachable"); + entry->di_type = g->builtin_types.entry_invalid->di_type; + g->type_table.put(&entry->name, entry); + g->builtin_types.entry_unreachable = entry; + } } -ZigList *codegen_error_messages(CodeGen *g) { - return &g->errors; + + +static void init(CodeGen *g, Buf *source_path) { + LLVMInitializeAllTargets(); + LLVMInitializeAllTargetMCs(); + LLVMInitializeAllAsmPrinters(); + LLVMInitializeAllAsmParsers(); + LLVMInitializeNativeTarget(); + + g->is_native_target = true; + char *native_triple = LLVMGetDefaultTargetTriple(); + + LLVMTargetRef target_ref; + char *err_msg = nullptr; + if (LLVMGetTargetFromTriple(native_triple, &target_ref, &err_msg)) { + zig_panic("unable to get target from triple: %s", err_msg); + } + + char *native_cpu = LLVMZigGetHostCPUName(); + char *native_features = LLVMZigGetNativeFeatures(); + + LLVMCodeGenOptLevel opt_level = (g->build_type == CodeGenBuildTypeDebug) ? + LLVMCodeGenLevelNone : LLVMCodeGenLevelAggressive; + + LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC; + + g->target_machine = LLVMCreateTargetMachine(target_ref, native_triple, + native_cpu, native_features, opt_level, reloc_mode, LLVMCodeModelDefault); + + g->target_data_ref = LLVMGetTargetMachineData(g->target_machine); + + + g->module = LLVMModuleCreateWithName("ZigModule"); + + g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref); + + g->builder = LLVMCreateBuilder(); + g->dbuilder = LLVMZigCreateDIBuilder(g->module, true); + + + define_primitive_types(g); + + Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING); + bool is_optimized = g->build_type == CodeGenBuildTypeRelease; + const char *flags = ""; + unsigned runtime_version = 0; + g->compile_unit = LLVMZigCreateCompileUnit(g->dbuilder, LLVMZigLang_DW_LANG_C99(), + buf_ptr(source_path), buf_ptr(g->root_source_dir), + buf_ptr(producer), is_optimized, flags, runtime_version, + "", 0, !g->strip_debug_symbols); + + +} + +void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) { + if (!g->initialized) { + g->initialized = true; + init(g, source_path); + } + + Buf full_path = BUF_INIT; + os_path_join(g->root_source_dir, source_path, &full_path); + + Buf dirname = BUF_INIT; + Buf basename = BUF_INIT; + os_path_split(&full_path, &dirname, &basename); + + if (g->verbose) { + fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(source_path)); + fprintf(stderr, "----------------\n"); + fprintf(stderr, "%s\n", buf_ptr(source_code)); + + fprintf(stderr, "\nTokens:\n"); + fprintf(stderr, "---------\n"); + } + + ZigList *tokens = tokenize(source_code); + + if (g->verbose) { + print_tokens(source_code, tokens); + + fprintf(stderr, "\nAST:\n"); + fprintf(stderr, "------\n"); + } + + ImportTableEntry *import_entry = allocate(1); + import_entry->root = ast_parse(source_code, tokens); + assert(import_entry->root); + if (g->verbose) { + ast_print(import_entry->root, 0); + + fprintf(stderr, "\nSemantic Analysis:\n"); + fprintf(stderr, "--------------------\n"); + } + + import_entry->path = source_path; + import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&basename), buf_ptr(&dirname)); + g->import_table.put(source_path, import_entry); + + semantic_analyze(g, import_entry); + + if (g->errors.length == 0) { + if (g->verbose) { + fprintf(stderr, "OK\n"); + } + } else { + for (int i = 0; i < g->errors.length; i += 1) { + ErrorMsg *err = &g->errors.at(i); + fprintf(stderr, "Error: Line %d, column %d: %s\n", + err->line_start + 1, err->column_start + 1, + buf_ptr(err->msg)); + } + exit(1); + } + + if (g->verbose) { + fprintf(stderr, "\nCode Generation:\n"); + fprintf(stderr, "------------------\n"); + } + + do_code_gen(g); } static Buf *to_c_type(CodeGen *g, AstNode *type_node) { @@ -601,15 +749,15 @@ static Buf *to_c_type(CodeGen *g, AstNode *type_node) { } static void generate_h_file(CodeGen *g) { - Buf *h_file_out_path = buf_sprintf("%s.h", buf_ptr(g->out_name)); + Buf *h_file_out_path = buf_sprintf("%s.h", buf_ptr(g->root_out_name)); FILE *out_h = fopen(buf_ptr(h_file_out_path), "wb"); if (!out_h) zig_panic("unable to open %s: %s", buf_ptr(h_file_out_path), strerror(errno)); - Buf *export_macro = buf_sprintf("%s_EXPORT", buf_ptr(g->out_name)); + Buf *export_macro = buf_sprintf("%s_EXPORT", buf_ptr(g->root_out_name)); buf_upcase(export_macro); - Buf *extern_c_macro = buf_sprintf("%s_EXTERN_C", buf_ptr(g->out_name)); + Buf *extern_c_macro = buf_sprintf("%s_EXTERN_C", buf_ptr(g->root_out_name)); buf_upcase(extern_c_macro); Buf h_buf = BUF_INIT; @@ -644,7 +792,8 @@ static void generate_h_file(CodeGen *g) { } } - Buf *ifdef_dance_name = buf_sprintf("%s_%s_H", buf_ptr(g->out_name), buf_ptr(g->out_name)); + Buf *ifdef_dance_name = buf_sprintf("%s_%s_H", + buf_ptr(g->root_out_name), buf_ptr(g->root_out_name)); buf_upcase(ifdef_dance_name); fprintf(out_h, "#ifndef %s\n", buf_ptr(ifdef_dance_name)); @@ -677,9 +826,27 @@ static void generate_h_file(CodeGen *g) { zig_panic("unable to close h file: %s", strerror(errno)); } -void code_gen_link(CodeGen *g, const char *out_file) { +void codegen_link(CodeGen *g, const char *out_file) { + bool is_optimized = (g->build_type == CodeGenBuildTypeRelease); + if (is_optimized) { + if (g->verbose) { + fprintf(stderr, "\nOptimization:\n"); + fprintf(stderr, "---------------\n"); + } + + LLVMZigOptimizeModule(g->target_machine, g->module); + + if (g->verbose) { + LLVMDumpModule(g->module); + } + } + if (g->verbose) { + fprintf(stderr, "\nLink:\n"); + fprintf(stderr, "-------\n"); + } + if (!out_file) { - out_file = buf_ptr(g->out_name); + out_file = buf_ptr(g->root_out_name); } Buf out_file_o = BUF_INIT; @@ -728,8 +895,8 @@ void code_gen_link(CodeGen *g, const char *out_file) { if (g->out_type == OutTypeLib) { Buf *out_lib_so = buf_sprintf("lib%s.so.%d.%d.%d", - buf_ptr(g->out_name), g->version_major, g->version_minor, g->version_patch); - Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->out_name), g->version_major); + buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch); + Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->root_out_name), g->version_major); args.append("-shared"); args.append("-soname"); args.append(buf_ptr(soname)); @@ -756,4 +923,8 @@ void code_gen_link(CodeGen *g, const char *out_file) { if (g->out_type == OutTypeLib) { generate_h_file(g); } + + if (g->verbose) { + fprintf(stderr, "OK\n"); + } } diff --git a/src/codegen.hpp b/src/codegen.hpp index 7795a3d3d9..403931b834 100644 --- a/src/codegen.hpp +++ b/src/codegen.hpp @@ -29,7 +29,7 @@ struct ErrorMsg { }; -CodeGen *create_codegen(AstNode *root, Buf *in_file); +CodeGen *codegen_create(Buf *root_source_dir); enum CodeGenBuildType { CodeGenBuildTypeDebug, @@ -38,15 +38,12 @@ enum CodeGenBuildType { void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type); void codegen_set_is_static(CodeGen *codegen, bool is_static); void codegen_set_strip(CodeGen *codegen, bool strip); +void codegen_set_verbose(CodeGen *codegen, bool verbose); void codegen_set_out_type(CodeGen *codegen, OutType out_type); void codegen_set_out_name(CodeGen *codegen, Buf *out_name); -void code_gen_optimize(CodeGen *g); +void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code); -void code_gen(CodeGen *g); - -void code_gen_link(CodeGen *g, const char *out_file); - -ZigList *codegen_error_messages(CodeGen *g); +void codegen_link(CodeGen *g, const char *out_file); #endif diff --git a/src/error.cpp b/src/error.cpp index e7dab68147..7c3064c143 100644 --- a/src/error.cpp +++ b/src/error.cpp @@ -5,6 +5,7 @@ const char *err_str(int err) { case ErrorNone: return "(no error)"; case ErrorNoMem: return "out of memory"; case ErrorInvalidFormat: return "invalid format"; + case ErrorSemanticAnalyzeFail: return "semantic analyze failed"; } return "(invalid error)"; } diff --git a/src/error.hpp b/src/error.hpp index 3a975f2177..7da2cf8322 100644 --- a/src/error.hpp +++ b/src/error.hpp @@ -12,6 +12,7 @@ enum Error { ErrorNone, ErrorNoMem, ErrorInvalidFormat, + ErrorSemanticAnalyzeFail, }; const char *err_str(int err); diff --git a/src/main.cpp b/src/main.cpp index a39bb8feb5..b88d6ecd6b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,25 +6,11 @@ */ #include "config.h" -#include "util.hpp" -#include "list.hpp" #include "buffer.hpp" -#include "parser.hpp" -#include "tokenizer.hpp" -#include "error.hpp" #include "codegen.hpp" -#include "analyze.hpp" +#include "os.hpp" #include -#include -#include -#include -#include -#include -#include -#include -#include -#include static int usage(const char *arg0) { fprintf(stderr, "Usage: %s [command] [options] target\n" @@ -38,6 +24,7 @@ static int usage(const char *arg0) { " --export [exe|lib|obj] override output type\n" " --name [name] override output name\n" " --output [file] override destination path\n" + " --verbose turn on compiler debug output\n" , arg0); return EXIT_FAILURE; } @@ -47,98 +34,47 @@ static int version(void) { return EXIT_SUCCESS; } -static Buf *fetch_file(FILE *f) { - int fd = fileno(f); - struct stat st; - if (fstat(fd, &st)) - zig_panic("unable to stat file: %s", strerror(errno)); - off_t big_size = st.st_size; - if (big_size > INT_MAX) - zig_panic("file too big"); - int size = (int)big_size; +struct Build { + const char *in_file; + const char *out_file; + bool release; + bool strip; + bool is_static; + OutType out_type; + const char *out_name; + bool verbose; +}; - Buf *buf = buf_alloc_fixed(size); - size_t amt_read = fread(buf_ptr(buf), 1, buf_len(buf), f); - if (amt_read != (size_t)buf_len(buf)) - zig_panic("error reading: %s", strerror(errno)); - - return buf; -} - -static int build(const char *arg0, const char *in_file, const char *out_file, bool release, - bool strip, bool is_static, OutType out_type, char *out_name) -{ - static char cur_dir[1024]; - - if (!in_file) +static int build(const char *arg0, Build *b) { + if (!b->in_file) return usage(arg0); - FILE *in_f; - if (strcmp(in_file, "-") == 0) { - in_f = stdin; - char *result = getcwd(cur_dir, sizeof(cur_dir)); - if (!result) - zig_panic("unable to get current working directory: %s", strerror(errno)); + Buf in_file_buf = BUF_INIT; + buf_init_from_str(&in_file_buf, b->in_file); + + Buf root_source_dir = BUF_INIT; + Buf root_source_code = BUF_INIT; + Buf root_source_name = BUF_INIT; + if (buf_eql_str(&in_file_buf, "-")) { + os_get_cwd(&root_source_dir); + os_fetch_file(stdin, &root_source_code); + buf_init_from_str(&root_source_name, ""); } else { - in_f = fopen(in_file, "rb"); - if (!in_f) - zig_panic("unable to open %s for reading: %s\n", in_file, strerror(errno)); + os_path_split(&in_file_buf, &root_source_dir, &root_source_name); + os_fetch_file_path(buf_create_from_str(b->in_file), &root_source_code); } - fprintf(stderr, "Original source:\n"); - fprintf(stderr, "----------------\n"); - Buf *in_data = fetch_file(in_f); - fprintf(stderr, "%s\n", buf_ptr(in_data)); - - fprintf(stderr, "\nTokens:\n"); - fprintf(stderr, "---------\n"); - ZigList *tokens = tokenize(in_data); - print_tokens(in_data, tokens); - - fprintf(stderr, "\nAST:\n"); - fprintf(stderr, "------\n"); - AstNode *root = ast_parse(in_data, tokens); - assert(root); - ast_print(root, 0); - - fprintf(stderr, "\nSemantic Analysis:\n"); - fprintf(stderr, "--------------------\n"); - CodeGen *codegen = create_codegen(root, buf_create_from_str(in_file)); - codegen_set_build_type(codegen, release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug); - codegen_set_strip(codegen, strip); - codegen_set_is_static(codegen, is_static); - if (out_type != OutTypeUnknown) - codegen_set_out_type(codegen, out_type); - if (out_name) - codegen_set_out_name(codegen, buf_create_from_str(out_name)); - semantic_analyze(codegen); - ZigList *errors = codegen_error_messages(codegen); - if (errors->length == 0) { - fprintf(stderr, "OK\n"); - } else { - for (int i = 0; i < errors->length; i += 1) { - ErrorMsg *err = &errors->at(i); - fprintf(stderr, "Error: Line %d, column %d: %s\n", - err->line_start + 1, err->column_start + 1, - buf_ptr(err->msg)); - } - return 1; - } - - fprintf(stderr, "\nCode Generation:\n"); - fprintf(stderr, "------------------\n"); - code_gen(codegen); - - if (release) { - fprintf(stderr, "\nOptimization:\n"); - fprintf(stderr, "---------------\n"); - code_gen_optimize(codegen); - } - - fprintf(stderr, "\nLink:\n"); - fprintf(stderr, "-------\n"); - code_gen_link(codegen, out_file); - fprintf(stderr, "OK\n"); + CodeGen *g = codegen_create(&root_source_dir); + codegen_set_build_type(g, b->release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug); + codegen_set_strip(g, b->strip); + codegen_set_is_static(g, b->is_static); + if (b->out_type != OutTypeUnknown) + codegen_set_out_type(g, b->out_type); + if (b->out_name) + codegen_set_out_name(g, buf_create_from_str(b->out_name)); + codegen_set_verbose(g, b->verbose); + codegen_add_code(g, &root_source_name, &root_source_code); + codegen_link(g, b->out_file); return 0; } @@ -151,43 +87,39 @@ enum Cmd { int main(int argc, char **argv) { char *arg0 = argv[0]; - char *in_file = NULL; - char *out_file = NULL; - bool release = false; - bool strip = false; - bool is_static = false; - - OutType out_type = OutTypeUnknown; - char *out_name = NULL; + Build b = {0}; Cmd cmd = CmdNone; + for (int i = 1; i < argc; i += 1) { char *arg = argv[i]; if (arg[0] == '-' && arg[1] == '-') { if (strcmp(arg, "--release") == 0) { - release = true; + b.release = true; } else if (strcmp(arg, "--strip") == 0) { - strip = true; + b.strip = true; } else if (strcmp(arg, "--static") == 0) { - is_static = true; + b.is_static = true; + } else if (strcmp(arg, "--verbose") == 0) { + b.verbose = true; } else if (i + 1 >= argc) { return usage(arg0); } else { i += 1; if (strcmp(arg, "--output") == 0) { - out_file = argv[i]; + b.out_file = argv[i]; } else if (strcmp(arg, "--export") == 0) { if (strcmp(argv[i], "exe") == 0) { - out_type = OutTypeExe; + b.out_type = OutTypeExe; } else if (strcmp(argv[i], "lib") == 0) { - out_type = OutTypeLib; + b.out_type = OutTypeLib; } else if (strcmp(argv[i], "obj") == 0) { - out_type = OutTypeObj; + b.out_type = OutTypeObj; } else { return usage(arg0); } } else if (strcmp(arg, "--name") == 0) { - out_name = argv[i]; + b.out_name = argv[i]; } else { return usage(arg0); } @@ -206,8 +138,8 @@ int main(int argc, char **argv) { case CmdNone: zig_unreachable(); case CmdBuild: - if (!in_file) { - in_file = arg; + if (!b.in_file) { + b.in_file = arg; } else { return usage(arg0); } @@ -222,7 +154,7 @@ int main(int argc, char **argv) { case CmdNone: return usage(arg0); case CmdBuild: - return build(arg0, in_file, out_file, release, strip, is_static, out_type, out_name); + return build(arg0, &b); case CmdVersion: return version(); } diff --git a/src/os.cpp b/src/os.cpp index bab72de2b9..61dd1c01ee 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -13,8 +13,8 @@ #include #include #include -#include #include +#include void os_spawn_process(const char *exe, ZigList &args, bool detached) { pid_t pid = fork(); @@ -37,7 +37,7 @@ void os_spawn_process(const char *exe, ZigList &args, bool detache zig_panic("execvp failed: %s", strerror(errno)); } -static void read_all_fd(int fd, Buf *out_buf) { +static void read_all_fd_stream(int fd, Buf *out_buf) { static const ssize_t buf_size = 0x2000; buf_resize(out_buf, buf_size); ssize_t actual_buf_len = 0; @@ -72,6 +72,12 @@ void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) { buf_init_from_buf(out_basename, full_path); } +void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) { + buf_init_from_buf(out_full_path, dirname); + buf_append_char(out_full_path, '/'); + buf_append_buf(out_full_path, basename); +} + void os_exec_process(const char *exe, ZigList &args, int *return_code, Buf *out_stderr, Buf *out_stdout) { @@ -117,8 +123,8 @@ void os_exec_process(const char *exe, ZigList &args, waitpid(pid, return_code, 0); - read_all_fd(stdout_pipe[0], out_stdout); - read_all_fd(stderr_pipe[0], out_stderr); + read_all_fd_stream(stdout_pipe[0], out_stdout); + read_all_fd_stream(stderr_pipe[0], out_stderr); } } @@ -133,3 +139,44 @@ void os_write_file(Buf *full_path, Buf *contents) { if (close(fd) == -1) zig_panic("close failed"); } + +int os_fetch_file(FILE *f, Buf *out_contents) { + int fd = fileno(f); + struct stat st; + if (fstat(fd, &st)) + zig_panic("unable to stat file: %s", strerror(errno)); + off_t big_size = st.st_size; + if (big_size > INT_MAX) + zig_panic("file too big"); + int size = (int)big_size; + + buf_resize(out_contents, size); + ssize_t ret = read(fd, buf_ptr(out_contents), size); + + if (ret != size) + zig_panic("unable to read file: %s", strerror(errno)); + + return 0; +} + +int os_fetch_file_path(Buf *full_path, Buf *out_contents) { + FILE *f = fopen(buf_ptr(full_path), "rb"); + if (!f) + zig_panic("unable to open %s: %s\n", buf_ptr(full_path), strerror(errno)); + int result = os_fetch_file(f, out_contents); + fclose(f); + return result; +} + +int os_get_cwd(Buf *out_cwd) { + int err = ERANGE; + buf_resize(out_cwd, 512); + while (err == ERANGE) { + buf_resize(out_cwd, buf_len(out_cwd) * 2); + err = getcwd(buf_ptr(out_cwd), buf_len(out_cwd)) ? 0 : errno; + } + if (err) + zig_panic("unable to get cwd: %s", strerror(err)); + + return 0; +} diff --git a/src/os.hpp b/src/os.hpp index a17c2b56f1..8bb5d8ea4f 100644 --- a/src/os.hpp +++ b/src/os.hpp @@ -11,13 +11,22 @@ #include "list.hpp" #include "buffer.hpp" +#include + void os_spawn_process(const char *exe, ZigList &args, bool detached); void os_exec_process(const char *exe, ZigList &args, int *return_code, Buf *out_stderr, Buf *out_stdout); void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename); +void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path); void os_write_file(Buf *full_path, Buf *contents); +int os_fetch_file(FILE *file, Buf *out_contents); +int os_fetch_file_path(Buf *full_path, Buf *out_contents); + +int os_get_cwd(Buf *out_cwd); + + #endif diff --git a/src/parser.cpp b/src/parser.cpp index 10f43d26d4..613c559235 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -100,6 +100,8 @@ const char *node_type_str(NodeType node_type) { return "Symbol"; case NodeTypePrefixOpExpr: return "PrefixOpExpr"; + case NodeTypeUse: + return "Use"; } zig_unreachable(); } @@ -241,6 +243,9 @@ void ast_print(AstNode *node, int indent) { fprintf(stderr, "PrimaryExpr Symbol %s\n", buf_ptr(&node->data.symbol)); break; + case NodeTypeUse: + fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.use.path)); + break; } } @@ -1231,7 +1236,36 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b } /* -TopLevelDecl : FnDef | ExternBlock | RootExportDecl +Use : many(Directive) token(Use) token(String) token(Semicolon) +*/ +static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory) { + assert(mandatory == false); + + Token *use_kw = &pc->tokens->at(*token_index); + if (use_kw->id != TokenIdKeywordUse) + return nullptr; + *token_index += 1; + + Token *use_name = &pc->tokens->at(*token_index); + *token_index += 1; + ast_expect_token(pc, use_name, TokenIdStringLiteral); + + Token *semicolon = &pc->tokens->at(*token_index); + *token_index += 1; + ast_expect_token(pc, semicolon, TokenIdSemicolon); + + AstNode *node = ast_create_node(NodeTypeUse, use_kw); + + parse_string_literal(pc, use_name, &node->data.use.path); + + node->data.use.directives = pc->directive_list; + pc->directive_list = nullptr; + + return node; +} + +/* +TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use */ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList *top_level_decls) { for (;;) { @@ -1258,6 +1292,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis continue; } + AstNode *use_node = ast_parse_use(pc, token_index, false); + if (use_node) { + top_level_decls->append(use_node); + continue; + } + if (pc->directive_list->length > 0) { ast_error(directive_token, "invalid directive"); } diff --git a/src/parser.hpp b/src/parser.hpp index 6d99dfbc4c..cc7b3dd0b6 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -35,6 +35,7 @@ enum NodeType { NodeTypeSymbol, NodeTypePrefixOpExpr, NodeTypeFnCallExpr, + NodeTypeUse, }; struct AstNodeRoot { @@ -158,6 +159,11 @@ struct AstNodePrefixOpExpr { AstNode *primary_expr; }; +struct AstNodeUse { + Buf path; + ZigList *directives; +}; + struct AstNode { enum NodeType type; AstNode *parent; @@ -180,6 +186,7 @@ struct AstNode { AstNodeCastExpr cast_expr; AstNodePrefixOpExpr prefix_op_expr; AstNodeFnCallExpr fn_call_expr; + AstNodeUse use; Buf number; Buf string; Buf symbol; diff --git a/src/semantic_info.hpp b/src/semantic_info.hpp index 13a05b1207..dc87c12930 100644 --- a/src/semantic_info.hpp +++ b/src/semantic_info.hpp @@ -12,15 +12,6 @@ #include "hash_map.hpp" #include "zig_llvm.hpp" -struct FnTableEntry { - LLVMValueRef fn_value; - AstNode *proto_node; - AstNode *fn_def_node; - bool is_extern; - bool internal_linkage; - unsigned calling_convention; -}; - struct TypeTableEntry { LLVMTypeRef type_ref; LLVMZigDIType *di_type; @@ -33,17 +24,35 @@ struct TypeTableEntry { TypeTableEntry *pointer_mut_parent; }; +struct ImportTableEntry { + AstNode *root; + Buf *path; // relative to root_source_dir + LLVMZigDIFile *di_file; +}; + +struct FnTableEntry { + LLVMValueRef fn_value; + AstNode *proto_node; + AstNode *fn_def_node; + bool is_extern; + bool internal_linkage; + unsigned calling_convention; + ImportTableEntry *import_entry; +}; + struct CodeGen { LLVMModuleRef module; - AstNode *root; ZigList errors; LLVMBuilderRef builder; LLVMZigDIBuilder *dbuilder; LLVMZigDICompileUnit *compile_unit; + + // reminder: hash tables must be initialized before use HashMap fn_table; HashMap str_table; HashMap type_table; HashMap link_table; + HashMap import_table; struct { TypeTableEntry *entry_u8; @@ -60,12 +69,10 @@ struct CodeGen { CodeGenBuildType build_type; LLVMTargetMachineRef target_machine; bool is_native_target; - Buf in_file; - Buf in_dir; + Buf *root_source_dir; + Buf *root_out_name; ZigList block_scopes; - LLVMZigDIFile *di_file; ZigList fn_defs; - Buf *out_name; OutType out_type; FnTableEntry *cur_fn; bool c_stdint_used; @@ -73,6 +80,8 @@ struct CodeGen { int version_major; int version_minor; int version_patch; + bool verbose; + bool initialized; }; struct TypeNode { diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index 3e8a201f52..94f3966f0f 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -180,6 +180,8 @@ static void end_token(Tokenize *t) { t->cur_tok->id = TokenIdKeywordExport; } else if (mem_eql_str(token_mem, token_len, "as")) { t->cur_tok->id = TokenIdKeywordAs; + } else if (mem_eql_str(token_mem, token_len, "use")) { + t->cur_tok->id = TokenIdKeywordUse; } t->cur_tok = nullptr; @@ -562,6 +564,7 @@ static const char * token_name(Token *token) { case TokenIdKeywordPub: return "Pub"; case TokenIdKeywordExport: return "Export"; case TokenIdKeywordAs: return "As"; + case TokenIdKeywordUse: return "Use"; case TokenIdLParen: return "LParen"; case TokenIdRParen: return "RParen"; case TokenIdComma: return "Comma"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index 2c9ad61957..94cbb15d43 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -22,6 +22,7 @@ enum TokenId { TokenIdKeywordPub, TokenIdKeywordExport, TokenIdKeywordAs, + TokenIdKeywordUse, TokenIdLParen, TokenIdRParen, TokenIdComma, diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 6e6818ed62..b54f0bd4c8 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -47,6 +47,7 @@ static void add_simple_case(const char *case_name, const char *source, const cha test_case->compiler_args.append(tmp_exe_path); test_case->compiler_args.append("--release"); test_case->compiler_args.append("--strip"); + test_case->compiler_args.append("--verbose"); test_cases.append(test_case); } @@ -70,6 +71,7 @@ static void add_compile_fail_case(const char *case_name, const char *source, int test_case->compiler_args.append(tmp_exe_path); test_case->compiler_args.append("--release"); test_case->compiler_args.append("--strip"); + test_case->compiler_args.append("--verbose"); test_cases.append(test_case);