diff --git a/CMakeLists.txt b/CMakeLists.txt index 44e7c43170448641ee91572dc4e934733f9edd19..e8c78213ec3b1fe853986daafebf31bf4456fcdb 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/os.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" ) set(TEST_SOURCES diff --git a/README.md b/README.md index 8e4bc96d611ed839a6987cb63fcd90fc935165bb..63110101567871d7b3175bee2ee1992bf99d78c6 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 ab51dfc996fe391cf81e0e121ff6216ea6bba02d..1527cb8049da8b62a5624301e0f55fdf669fd145 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.zig deleted file mode 100644 index d9efc46e969008767147805bd700bbd21ed750cd..0000000000000000000000000000000000000000 --- a/example/hello.zig +++ /dev/null @@ -1,12 +0,0 @@ -export executable "hello"; - -#link("c") -extern { - fn puts(s: *mut u8) -> i32; - fn exit(code: i32) -> unreachable; -} - -export fn _start() -> unreachable { - puts("Hello, world!"); - exit(0); -} diff --git a/example/hello_world/hello.zig b/example/hello_world/hello.zig new file mode 100644 index 0000000000000000000000000000000000000000..d9efc46e969008767147805bd700bbd21ed750cd --- /dev/null +++ b/example/hello_world/hello.zig @@ -0,0 +1,12 @@ +export executable "hello"; + +#link("c") +extern { + fn puts(s: *mut u8) -> i32; + fn exit(code: i32) -> unreachable; +} + +export fn _start() -> unreachable { + puts("Hello, world!"); + exit(0); +} diff --git a/example/mathtest.zig b/example/mathtest.zig deleted file mode 100644 index 35ec90152327f0139c033d2433d9dcd2d6970f6d..0000000000000000000000000000000000000000 --- a/example/mathtest.zig +++ /dev/null @@ -1,6 +0,0 @@ -#version("2.0.0") -export library "mathtest"; - -export fn add(a: i32, b: i32) -> i32 { - return a + b; -} diff --git a/example/multiple_files/foo.zig b/example/multiple_files/foo.zig new file mode 100644 index 0000000000000000000000000000000000000000..aacc49a55633f39cb53ea48b3fb8e538d83c2a6f --- /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 0000000000000000000000000000000000000000..7d1a5bebd95c24dda4646b1a67c07ae22af53acb --- /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 0000000000000000000000000000000000000000..993d4234c2370f11d88f11528ecdced963891097 --- /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/shared_library/mathtest.zig b/example/shared_library/mathtest.zig new file mode 100644 index 0000000000000000000000000000000000000000..35ec90152327f0139c033d2433d9dcd2d6970f6d --- /dev/null +++ b/example/shared_library/mathtest.zig @@ -0,0 +1,6 @@ +#version("2.0.0") +export library "mathtest"; + +export fn add(a: i32, b: i32) -> i32 { + return a + b; +} diff --git a/example/shared_library/test.c b/example/shared_library/test.c new file mode 100644 index 0000000000000000000000000000000000000000..4fff250f08b012051ef3e6df2db7941efe6d8487 --- /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 8dae356e8184cd7277fa9e0015d107eda1ddb0ed..131bc22e5252703e1b49b3f09ca076a8ff58a751 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 0dca23194d95d80d3c7a8731d0ff945493d6e5b6..374fcad7482dae2824e233888a41104e296d50c3 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 c5e90cf75a4d663774a7451189ffb5e018a2d162..b854f343f03ab304cef54320394246601921a9c0 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 7795a3d3d9c1cfb29b8588fe0ad25ddbd2a87d68..403931b834b430c1b0811e2d594c8b17053588f0 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 e7dab6814717035dfdf8a6cb77c8a5137565c30c..7c3064c1436d587bd830efdad2e0f331e9a769ca 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 3a975f2177f477d5db90e6c0c1e9a566e23fbc55..7da2cf832211c5d7b7152a61e9c0f3840727951b 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 a39bb8feb5142ce89a419e90d5f846de3edae2dc..b88d6ecd6b9b7dd70a54f1898f568e06a566343f 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; - - 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) +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; +}; + +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)); - } else { - in_f = fopen(in_file, "rb"); - if (!in_f) - zig_panic("unable to open %s for reading: %s\n", in_file, strerror(errno)); - } - - 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); + Buf in_file_buf = BUF_INIT; + buf_init_from_str(&in_file_buf, b->in_file); - 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"); + 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 { - 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); + 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, "\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 bab72de2b95da66dde96b10b51ee681be499258f..61dd1c01ee615e4937169e18a0eb4bc34b547d6c 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 a17c2b56f1fc8eeb1357d12c4acb8ba28d0ef60e..8bb5d8ea4f46c446b7dd5737a7aa771c80ac2431 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 10f43d26d4487064dcb99df6ba95aba0e21ed8c1..613c559235f1fe9f22723385e10c4018f231e81e 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 6d99dfbc4ce98c18d5dfaf582a676810b6f53b50..cc7b3dd0b6910c105a79d665141f37275b8af6d5 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 13a05b12075aed1b645d42e36732c4032417b076..dc87c12930dbb80c811ccd4a412eac5506a8e7a8 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 3e8a201f522b5271bda6f539c48fc9cc0ee66fb8..94f3966f0f25f6cb5d66c6d1dedbb2f2fbcaff04 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 2c9ad619571df5ccfbc3788082a332182c0bf9cd..94cbb15d4399ad49480f991e7b21e2e32e3276d2 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 6e6818ed62dc1f62532f89da4972cfdc9bf4d0fa..b54f0bd4c80be0a96fd5f31a51abad5f468eb6c7 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);