| author | |
| committer | |
| log | cb4773ce29fbac856811f69a3fb5b17b7e83d44d |
| tree | 5c87a210beae92c243dcd7818865447b35d44be5 |
| parent | 4cc95174a77f7cbb42b371bb892c55a8349bc7fa |
10 files changed, 206 insertions(+), 30 deletions(-)
README.md+6-2| ... | @@ -32,7 +32,9 @@ readable, safe, optimal, and concise code to solve any computing problem. | ... | @@ -32,7 +32,9 @@ readable, safe, optimal, and concise code to solve any computing problem. |
| 32 | 32 | ||
| 33 | ## Roadmap | 33 | ## Roadmap |
| 34 | 34 | ||
| 35 | * Simple .so library | 35 | * Math expression |
| 36 | * Export .so library | ||
| 37 | * Export .o file | ||
| 36 | * Multiple files | 38 | * Multiple files |
| 37 | * inline assembly and syscalls | 39 | * inline assembly and syscalls |
| 38 | * running code at compile time | 40 | * running code at compile time |
| ... | @@ -66,7 +68,9 @@ zig | C equivalent | Description | ... | @@ -66,7 +68,9 @@ zig | C equivalent | Description |
| 66 | ### Grammar | 68 | ### Grammar |
| 67 | 69 | ||
| 68 | ``` | 70 | ``` |
| 69 | Root : many(TopLevelDecl) token(EOF) | 71 | Root : RootExportDecl many(TopLevelDecl) token(EOF) |
| 72 | |||
| 73 | RootExportDecl : token(Export) token(Symbol) token(String) token(Semicolon) | ||
| 70 | 74 | ||
| 71 | TopLevelDecl : FnDef | ExternBlock | 75 | TopLevelDecl : FnDef | ExternBlock |
| 72 | 76 |
doc/vim/syntax/zig.vim+15| ... | @@ -10,7 +10,22 @@ endif | ... | @@ -10,7 +10,22 @@ endif |
| 10 | syn keyword zigKeyword fn return mut const extern unreachable export pub | 10 | syn keyword zigKeyword fn return mut const extern unreachable export pub |
| 11 | syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void | 11 | syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void |
| 12 | 12 | ||
| 13 | syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell | ||
| 14 | syn region zigCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=zigTodo,@Spell | ||
| 15 | syn region zigCommentBlock matchgroup=zigCommentBlock start="/\*\%(!\|\*[*/]\@!\)\@!" end="\*/" contains=zigTodo,zigCommentBlockNest,@Spell | ||
| 16 | syn region zigCommentBlockDoc matchgroup=zigCommentBlockDoc start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=zigTodo,zigCommentBlockDocNest,@Spell | ||
| 17 | syn region zigCommentBlockNest matchgroup=zigCommentBlock start="/\*" end="\*/" contains=zigTodo,zigCommentBlockNest,@Spell contained transparent | ||
| 18 | syn region zigCommentBlockDocNest matchgroup=zigCommentBlockDoc start="/\*" end="\*/" contains=zigTodo,zigCommentBlockDocNest,@Spell contained transparent | ||
| 19 | |||
| 20 | syn keyword zigTodo contained TODO XXX | ||
| 21 | |||
| 13 | let b:current_syntax = "zig" | 22 | let b:current_syntax = "zig" |
| 14 | 23 | ||
| 15 | hi def link zigKeyword Keyword | 24 | hi def link zigKeyword Keyword |
| 16 | hi def link zigType Type | 25 | hi def link zigType Type |
| 26 | hi def link zigCommentLine Comment | ||
| 27 | hi def link zigCommentLineDoc SpecialComment | ||
| 28 | hi def link zigCommentBlock zigCommentLine | ||
| 29 | hi def link zigCommentBlockDoc zigCommentLineDoc | ||
| 30 | hi def link zigTodo Todo | ||
| 31 |
example/hello.zig+2| ... | @@ -1,3 +1,5 @@ | ... | @@ -1,3 +1,5 @@ |
| 1 | export executable "hello"; | ||
| 2 | |||
| 1 | #link("c") | 3 | #link("c") |
| 2 | extern { | 4 | extern { |
| 3 | fn puts(s: *mut u8) -> i32; | 5 | fn puts(s: *mut u8) -> i32; |
example/math.zig created+6| ... | @@ -0,0 +1,6 @@ | ||
| 1 | export library "math"; | ||
| 2 | |||
| 3 | export fn add(a: i32, b: i32) -> i32 { | ||
| 4 | return a + b; | ||
| 5 | } | ||
| 6 | |||
src/codegen.cpp+70-8| ... | @@ -75,6 +75,8 @@ struct CodeGen { | ... | @@ -75,6 +75,8 @@ struct CodeGen { |
| 75 | ZigList<llvm::DIScope *> block_scopes; | 75 | ZigList<llvm::DIScope *> block_scopes; |
| 76 | llvm::DIFile *di_file; | 76 | llvm::DIFile *di_file; |
| 77 | ZigList<FnTableEntry *> fn_defs; | 77 | ZigList<FnTableEntry *> fn_defs; |
| 78 | Buf *out_name; | ||
| 79 | OutType out_type; | ||
| 78 | }; | 80 | }; |
| 79 | 81 | ||
| 80 | struct TypeNode { | 82 | struct TypeNode { |
| ... | @@ -103,6 +105,8 @@ CodeGen *create_codegen(AstNode *root, Buf *in_full_path) { | ... | @@ -103,6 +105,8 @@ CodeGen *create_codegen(AstNode *root, Buf *in_full_path) { |
| 103 | g->is_static = false; | 105 | g->is_static = false; |
| 104 | g->build_type = CodeGenBuildTypeDebug; | 106 | g->build_type = CodeGenBuildTypeDebug; |
| 105 | g->strip_debug_symbols = false; | 107 | g->strip_debug_symbols = false; |
| 108 | g->out_name = nullptr; | ||
| 109 | g->out_type = OutTypeUnknown; | ||
| 106 | 110 | ||
| 107 | os_path_split(in_full_path, &g->in_dir, &g->in_file); | 111 | os_path_split(in_full_path, &g->in_dir, &g->in_file); |
| 108 | return g; | 112 | return g; |
| ... | @@ -120,6 +124,14 @@ void codegen_set_strip(CodeGen *g, bool strip) { | ... | @@ -120,6 +124,14 @@ void codegen_set_strip(CodeGen *g, bool strip) { |
| 120 | g->strip_debug_symbols = strip; | 124 | g->strip_debug_symbols = strip; |
| 121 | } | 125 | } |
| 122 | 126 | ||
| 127 | void codegen_set_out_type(CodeGen *g, OutType out_type) { | ||
| 128 | g->out_type = out_type; | ||
| 129 | } | ||
| 130 | |||
| 131 | void codegen_set_out_name(CodeGen *g, Buf *out_name) { | ||
| 132 | g->out_name = out_name; | ||
| 133 | } | ||
| 134 | |||
| 123 | static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) { | 135 | static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) { |
| 124 | g->errors.add_one(); | 136 | g->errors.add_one(); |
| 125 | ErrorMsg *last_msg = &g->errors.last(); | 137 | ErrorMsg *last_msg = &g->errors.last(); |
| ... | @@ -294,6 +306,7 @@ static void find_declarations(CodeGen *g, AstNode *node) { | ... | @@ -294,6 +306,7 @@ static void find_declarations(CodeGen *g, AstNode *node) { |
| 294 | case NodeTypeBlock: | 306 | case NodeTypeBlock: |
| 295 | case NodeTypeExpression: | 307 | case NodeTypeExpression: |
| 296 | case NodeTypeFnCall: | 308 | case NodeTypeFnCall: |
| 309 | case NodeTypeRootExportDecl: | ||
| 297 | zig_unreachable(); | 310 | zig_unreachable(); |
| 298 | } | 311 | } |
| 299 | } | 312 | } |
| ... | @@ -355,15 +368,50 @@ static void check_fn_def_control_flow(CodeGen *g, AstNode *node) { | ... | @@ -355,15 +368,50 @@ static void check_fn_def_control_flow(CodeGen *g, AstNode *node) { |
| 355 | static void analyze_node(CodeGen *g, AstNode *node) { | 368 | static void analyze_node(CodeGen *g, AstNode *node) { |
| 356 | switch (node->type) { | 369 | switch (node->type) { |
| 357 | case NodeTypeRoot: | 370 | case NodeTypeRoot: |
| 358 | // Iterate once over the top level declarations to build the function table | 371 | { |
| 359 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { | 372 | AstNode *root_export_decl_node = node->data.root.root_export_decl; |
| 360 | AstNode *child = node->data.root.top_level_decls.at(i); | 373 | if (root_export_decl_node) { |
| 361 | find_declarations(g, child); | 374 | assert(root_export_decl_node->type == NodeTypeRootExportDecl); |
| 362 | } | 375 | if (!g->out_name) |
| 363 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { | 376 | g->out_name = &root_export_decl_node->data.root_export_decl.name; |
| 364 | AstNode *child = node->data.root.top_level_decls.at(i); | 377 | |
| 365 | analyze_node(g, child); | 378 | Buf *out_type = &root_export_decl_node->data.root_export_decl.type; |
| 379 | OutType export_out_type; | ||
| 380 | if (buf_eql_str(out_type, "executable")) { | ||
| 381 | export_out_type = OutTypeExe; | ||
| 382 | } else if (buf_eql_str(out_type, "library")) { | ||
| 383 | export_out_type = OutTypeLib; | ||
| 384 | } else if (buf_eql_str(out_type, "object")) { | ||
| 385 | export_out_type = OutTypeObj; | ||
| 386 | } else { | ||
| 387 | add_node_error(g, root_export_decl_node, | ||
| 388 | buf_sprintf("invalid export type: '%s'", buf_ptr(out_type))); | ||
| 389 | } | ||
| 390 | if (g->out_type == OutTypeUnknown) | ||
| 391 | g->out_type = export_out_type; | ||
| 392 | } else { | ||
| 393 | if (!g->out_name) { | ||
| 394 | add_node_error(g, node, | ||
| 395 | buf_sprintf("missing export declaration and output name not provided")); | ||
| 396 | } else if (g->out_type == OutTypeUnknown) { | ||
| 397 | add_node_error(g, node, | ||
| 398 | buf_sprintf("missing export declaration and export type not provided")); | ||
| 399 | } | ||
| 400 | } | ||
| 401 | |||
| 402 | // Iterate once over the top level declarations to build the function table | ||
| 403 | for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) { | ||
| 404 | AstNode *child = node->data.root.top_level_decls.at(i); | ||
| 405 | find_declarations(g, child); | ||
| 406 | } | ||
| 407 | 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); | ||
| 409 | analyze_node(g, child); | ||
| 410 | } | ||
| 411 | break; | ||
| 366 | } | 412 | } |
| 413 | case NodeTypeRootExportDecl: | ||
| 414 | // handled in parent | ||
| 367 | break; | 415 | break; |
| 368 | case NodeTypeExternBlock: | 416 | case NodeTypeExternBlock: |
| 369 | for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) { | 417 | for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) { |
| ... | @@ -674,6 +722,7 @@ static void gen_block(CodeGen *g, AstNode *block_node, bool add_implicit_return) | ... | @@ -674,6 +722,7 @@ static void gen_block(CodeGen *g, AstNode *block_node, bool add_implicit_return) |
| 674 | case NodeTypeFnCall: | 722 | case NodeTypeFnCall: |
| 675 | case NodeTypeExternBlock: | 723 | case NodeTypeExternBlock: |
| 676 | case NodeTypeDirective: | 724 | case NodeTypeDirective: |
| 725 | case NodeTypeRootExportDecl: | ||
| 677 | zig_unreachable(); | 726 | zig_unreachable(); |
| 678 | } | 727 | } |
| 679 | } | 728 | } |
| ... | @@ -929,6 +978,15 @@ static Buf *get_dynamic_linker(CodeGen *g) { | ... | @@ -929,6 +978,15 @@ static Buf *get_dynamic_linker(CodeGen *g) { |
| 929 | } | 978 | } |
| 930 | } | 979 | } |
| 931 | 980 | ||
| 981 | /* | ||
| 982 | |||
| 983 | # static link into libfoo.a | ||
| 984 | ar cq libfoo.a foo1.o foo2.o | ||
| 985 | |||
| 986 | # dynamic link into libfoo.so | ||
| 987 | gcc -fPIC -g -Werror -pedantic -shared -Wl,-soname,libsoundio.so.1 -o libsoundio.so.1.0.3 foo1.o foo2.o -ljack -lpulse -lasound -lpthread | ||
| 988 | |||
| 989 | */ | ||
| 932 | void code_gen_link(CodeGen *g, const char *out_file) { | 990 | void code_gen_link(CodeGen *g, const char *out_file) { |
| 933 | LLVMPassRegistryRef registry = LLVMGetGlobalPassRegistry(); | 991 | LLVMPassRegistryRef registry = LLVMGetGlobalPassRegistry(); |
| 934 | LLVMInitializeCore(registry); | 992 | LLVMInitializeCore(registry); |
| ... | @@ -937,6 +995,10 @@ void code_gen_link(CodeGen *g, const char *out_file) { | ... | @@ -937,6 +995,10 @@ void code_gen_link(CodeGen *g, const char *out_file) { |
| 937 | LLVMZigInitializeLowerIntrinsicsPass(registry); | 995 | LLVMZigInitializeLowerIntrinsicsPass(registry); |
| 938 | LLVMZigInitializeUnreachableBlockElimPass(registry); | 996 | LLVMZigInitializeUnreachableBlockElimPass(registry); |
| 939 | 997 | ||
| 998 | if (!out_file) { | ||
| 999 | out_file = buf_ptr(g->out_name); | ||
| 1000 | } | ||
| 1001 | |||
| 940 | Buf out_file_o = BUF_INIT; | 1002 | Buf out_file_o = BUF_INIT; |
| 941 | buf_init_from_str(&out_file_o, out_file); | 1003 | buf_init_from_str(&out_file_o, out_file); |
| 942 | buf_append_str(&out_file_o, ".o"); | 1004 | buf_append_str(&out_file_o, ".o"); |
src/codegen.hpp+10| ... | @@ -12,6 +12,14 @@ | ... | @@ -12,6 +12,14 @@ |
| 12 | 12 | ||
| 13 | struct CodeGen; | 13 | struct CodeGen; |
| 14 | 14 | ||
| 15 | enum OutType { | ||
| 16 | OutTypeUnknown, | ||
| 17 | OutTypeExe, | ||
| 18 | OutTypeLib, | ||
| 19 | OutTypeObj, | ||
| 20 | }; | ||
| 21 | |||
| 22 | |||
| 15 | struct ErrorMsg { | 23 | struct ErrorMsg { |
| 16 | int line_start; | 24 | int line_start; |
| 17 | int column_start; | 25 | int column_start; |
| ... | @@ -30,6 +38,8 @@ enum CodeGenBuildType { | ... | @@ -30,6 +38,8 @@ enum CodeGenBuildType { |
| 30 | void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type); | 38 | void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type); |
| 31 | void codegen_set_is_static(CodeGen *codegen, bool is_static); | 39 | void codegen_set_is_static(CodeGen *codegen, bool is_static); |
| 32 | void codegen_set_strip(CodeGen *codegen, bool strip); | 40 | void codegen_set_strip(CodeGen *codegen, bool strip); |
| 41 | void codegen_set_out_type(CodeGen *codegen, OutType out_type); | ||
| 42 | void codegen_set_out_name(CodeGen *codegen, Buf *out_name); | ||
| 33 | 43 | ||
| 34 | void semantic_analyze(CodeGen *g); | 44 | void semantic_analyze(CodeGen *g); |
| 35 | 45 |
src/main.cpp+45-20| ... | @@ -28,18 +28,24 @@ | ... | @@ -28,18 +28,24 @@ |
| 28 | static int usage(const char *arg0) { | 28 | static int usage(const char *arg0) { |
| 29 | fprintf(stderr, "Usage: %s [command] [options] target\n" | 29 | fprintf(stderr, "Usage: %s [command] [options] target\n" |
| 30 | "Commands:\n" | 30 | "Commands:\n" |
| 31 | " build create an executable from target\n" | 31 | " build create executable, object, or library from target\n" |
| 32 | "Options:\n" | 32 | " version print version number and exit\n" |
| 33 | " --output output file\n" | 33 | "Optional Options:\n" |
| 34 | " --version print version number and exit\n" | 34 | " --release build with optimizations on and debug protection off\n" |
| 35 | " -Ipath add path to header include path\n" | 35 | " --static output will be statically linked\n" |
| 36 | " --release build with optimizations on\n" | 36 | " --strip exclude debug symbols\n" |
| 37 | " --strip exclude debug symbols\n" | 37 | " --export [exe|lib|obj] override output type\n" |
| 38 | " --static build a static executable\n" | 38 | " --name [name] override output name\n" |
| 39 | " --output [file] override destination path\n" | ||
| 39 | , arg0); | 40 | , arg0); |
| 40 | return EXIT_FAILURE; | 41 | return EXIT_FAILURE; |
| 41 | } | 42 | } |
| 42 | 43 | ||
| 44 | static int version(void) { | ||
| 45 | printf("%s\n", ZIG_VERSION_STRING); | ||
| 46 | return EXIT_SUCCESS; | ||
| 47 | } | ||
| 48 | |||
| 43 | static Buf *fetch_file(FILE *f) { | 49 | static Buf *fetch_file(FILE *f) { |
| 44 | int fd = fileno(f); | 50 | int fd = fileno(f); |
| 45 | struct stat st; | 51 | struct stat st; |
| ... | @@ -58,12 +64,12 @@ static Buf *fetch_file(FILE *f) { | ... | @@ -58,12 +64,12 @@ static Buf *fetch_file(FILE *f) { |
| 58 | return buf; | 64 | return buf; |
| 59 | } | 65 | } |
| 60 | 66 | ||
| 61 | static int build(const char *arg0, const char *in_file, const char *out_file, | 67 | static int build(const char *arg0, const char *in_file, const char *out_file, bool release, |
| 62 | ZigList<char *> *include_paths, bool release, bool strip, bool is_static) | 68 | bool strip, bool is_static, OutType out_type, char *out_name) |
| 63 | { | 69 | { |
| 64 | static char cur_dir[1024]; | 70 | static char cur_dir[1024]; |
| 65 | 71 | ||
| 66 | if (!in_file || !out_file) | 72 | if (!in_file) |
| 67 | return usage(arg0); | 73 | return usage(arg0); |
| 68 | 74 | ||
| 69 | FILE *in_f; | 75 | FILE *in_f; |
| ... | @@ -100,6 +106,10 @@ static int build(const char *arg0, const char *in_file, const char *out_file, | ... | @@ -100,6 +106,10 @@ static int build(const char *arg0, const char *in_file, const char *out_file, |
| 100 | codegen_set_build_type(codegen, release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug); | 106 | codegen_set_build_type(codegen, release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug); |
| 101 | codegen_set_strip(codegen, strip); | 107 | codegen_set_strip(codegen, strip); |
| 102 | codegen_set_is_static(codegen, is_static); | 108 | codegen_set_is_static(codegen, is_static); |
| 109 | if (out_type != OutTypeUnknown) | ||
| 110 | codegen_set_out_type(codegen, out_type); | ||
| 111 | if (out_name) | ||
| 112 | codegen_set_out_name(codegen, buf_create_from_str(out_name)); | ||
| 103 | semantic_analyze(codegen); | 113 | semantic_analyze(codegen); |
| 104 | ZigList<ErrorMsg> *errors = codegen_error_messages(codegen); | 114 | ZigList<ErrorMsg> *errors = codegen_error_messages(codegen); |
| 105 | if (errors->length == 0) { | 115 | if (errors->length == 0) { |
| ... | @@ -135,25 +145,25 @@ static int build(const char *arg0, const char *in_file, const char *out_file, | ... | @@ -135,25 +145,25 @@ static int build(const char *arg0, const char *in_file, const char *out_file, |
| 135 | enum Cmd { | 145 | enum Cmd { |
| 136 | CmdNone, | 146 | CmdNone, |
| 137 | CmdBuild, | 147 | CmdBuild, |
| 148 | CmdVersion, | ||
| 138 | }; | 149 | }; |
| 139 | 150 | ||
| 140 | int main(int argc, char **argv) { | 151 | int main(int argc, char **argv) { |
| 141 | char *arg0 = argv[0]; | 152 | char *arg0 = argv[0]; |
| 142 | char *in_file = NULL; | 153 | char *in_file = NULL; |
| 143 | char *out_file = NULL; | 154 | char *out_file = NULL; |
| 144 | ZigList<char *> include_paths = {0}; | ||
| 145 | bool release = false; | 155 | bool release = false; |
| 146 | bool strip = false; | 156 | bool strip = false; |
| 147 | bool is_static = false; | 157 | bool is_static = false; |
| 148 | 158 | ||
| 159 | OutType out_type = OutTypeUnknown; | ||
| 160 | char *out_name = NULL; | ||
| 161 | |||
| 149 | Cmd cmd = CmdNone; | 162 | Cmd cmd = CmdNone; |
| 150 | for (int i = 1; i < argc; i += 1) { | 163 | for (int i = 1; i < argc; i += 1) { |
| 151 | char *arg = argv[i]; | 164 | char *arg = argv[i]; |
| 152 | if (arg[0] == '-' && arg[1] == '-') { | 165 | if (arg[0] == '-' && arg[1] == '-') { |
| 153 | if (strcmp(arg, "--version") == 0) { | 166 | if (strcmp(arg, "--release") == 0) { |
| 154 | printf("%s\n", ZIG_VERSION_STRING); | ||
| 155 | return EXIT_SUCCESS; | ||
| 156 | } else if (strcmp(arg, "--release") == 0) { | ||
| 157 | release = true; | 167 | release = true; |
| 158 | } else if (strcmp(arg, "--strip") == 0) { | 168 | } else if (strcmp(arg, "--strip") == 0) { |
| 159 | strip = true; | 169 | strip = true; |
| ... | @@ -165,15 +175,27 @@ int main(int argc, char **argv) { | ... | @@ -165,15 +175,27 @@ int main(int argc, char **argv) { |
| 165 | i += 1; | 175 | i += 1; |
| 166 | if (strcmp(arg, "--output") == 0) { | 176 | if (strcmp(arg, "--output") == 0) { |
| 167 | out_file = argv[i]; | 177 | out_file = argv[i]; |
| 178 | } else if (strcmp(arg, "--export") == 0) { | ||
| 179 | if (strcmp(argv[i], "exe") == 0) { | ||
| 180 | out_type = OutTypeExe; | ||
| 181 | } else if (strcmp(argv[i], "lib") == 0) { | ||
| 182 | out_type = OutTypeLib; | ||
| 183 | } else if (strcmp(argv[i], "obj") == 0) { | ||
| 184 | out_type = OutTypeObj; | ||
| 185 | } else { | ||
| 186 | return usage(arg0); | ||
| 187 | } | ||
| 188 | } else if (strcmp(arg, "--name") == 0) { | ||
| 189 | out_name = argv[i]; | ||
| 168 | } else { | 190 | } else { |
| 169 | return usage(arg0); | 191 | return usage(arg0); |
| 170 | } | 192 | } |
| 171 | } | 193 | } |
| 172 | } else if (arg[0] == '-' && arg[1] == 'I') { | ||
| 173 | include_paths.append(arg + 2); | ||
| 174 | } else if (cmd == CmdNone) { | 194 | } else if (cmd == CmdNone) { |
| 175 | if (strcmp(arg, "build") == 0) { | 195 | if (strcmp(arg, "build") == 0) { |
| 176 | cmd = CmdBuild; | 196 | cmd = CmdBuild; |
| 197 | } else if (strcmp(arg, "version") == 0) { | ||
| 198 | cmd = CmdVersion; | ||
| 177 | } else { | 199 | } else { |
| 178 | fprintf(stderr, "Unrecognized command: %s\n", arg); | 200 | fprintf(stderr, "Unrecognized command: %s\n", arg); |
| 179 | return usage(arg0); | 201 | return usage(arg0); |
| ... | @@ -189,6 +211,8 @@ int main(int argc, char **argv) { | ... | @@ -189,6 +211,8 @@ int main(int argc, char **argv) { |
| 189 | return usage(arg0); | 211 | return usage(arg0); |
| 190 | } | 212 | } |
| 191 | break; | 213 | break; |
| 214 | case CmdVersion: | ||
| 215 | return usage(arg0); | ||
| 192 | } | 216 | } |
| 193 | } | 217 | } |
| 194 | } | 218 | } |
| ... | @@ -197,9 +221,10 @@ int main(int argc, char **argv) { | ... | @@ -197,9 +221,10 @@ int main(int argc, char **argv) { |
| 197 | case CmdNone: | 221 | case CmdNone: |
| 198 | return usage(arg0); | 222 | return usage(arg0); |
| 199 | case CmdBuild: | 223 | case CmdBuild: |
| 200 | return build(arg0, in_file, out_file, &include_paths, release, strip, is_static); | 224 | return build(arg0, in_file, out_file, release, strip, is_static, out_type, out_name); |
| 225 | case CmdVersion: | ||
| 226 | return version(); | ||
| 201 | } | 227 | } |
| 202 | 228 | ||
| 203 | zig_unreachable(); | 229 | zig_unreachable(); |
| 204 | } | 230 | } |
| 205 |
src/parser.cpp+40| ... | @@ -29,6 +29,8 @@ const char *node_type_str(NodeType node_type) { | ... | @@ -29,6 +29,8 @@ const char *node_type_str(NodeType node_type) { |
| 29 | switch (node_type) { | 29 | switch (node_type) { |
| 30 | case NodeTypeRoot: | 30 | case NodeTypeRoot: |
| 31 | return "Root"; | 31 | return "Root"; |
| 32 | case NodeTypeRootExportDecl: | ||
| 33 | return "RootExportDecl"; | ||
| 32 | case NodeTypeFnDef: | 34 | case NodeTypeFnDef: |
| 33 | return "FnDef"; | 35 | return "FnDef"; |
| 34 | case NodeTypeFnDecl: | 36 | case NodeTypeFnDecl: |
| ... | @@ -68,6 +70,11 @@ void ast_print(AstNode *node, int indent) { | ... | @@ -68,6 +70,11 @@ void ast_print(AstNode *node, int indent) { |
| 68 | ast_print(child, indent + 2); | 70 | ast_print(child, indent + 2); |
| 69 | } | 71 | } |
| 70 | break; | 72 | break; |
| 73 | case NodeTypeRootExportDecl: | ||
| 74 | fprintf(stderr, "%s %s '%s'\n", node_type_str(node->type), | ||
| 75 | buf_ptr(&node->data.root_export_decl.type), | ||
| 76 | buf_ptr(&node->data.root_export_decl.name)); | ||
| 77 | break; | ||
| 71 | case NodeTypeFnDef: | 78 | case NodeTypeFnDef: |
| 72 | { | 79 | { |
| 73 | fprintf(stderr, "%s\n", node_type_str(node->type)); | 80 | fprintf(stderr, "%s\n", node_type_str(node->type)); |
| ... | @@ -714,6 +721,36 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis | ... | @@ -714,6 +721,36 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis |
| 714 | zig_unreachable(); | 721 | zig_unreachable(); |
| 715 | } | 722 | } |
| 716 | 723 | ||
| 724 | static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index) { | ||
| 725 | Token *export_kw = &pc->tokens->at(*token_index); | ||
| 726 | if (export_kw->id != TokenIdKeywordExport) | ||
| 727 | return nullptr; | ||
| 728 | *token_index += 1; | ||
| 729 | |||
| 730 | AstNode *node = ast_create_node(NodeTypeRootExportDecl, export_kw); | ||
| 731 | |||
| 732 | Token *export_type = &pc->tokens->at(*token_index); | ||
| 733 | *token_index += 1; | ||
| 734 | ast_expect_token(pc, export_type, TokenIdSymbol); | ||
| 735 | |||
| 736 | ast_buf_from_token(pc, export_type, &node->data.root_export_decl.type); | ||
| 737 | |||
| 738 | Token *export_name = &pc->tokens->at(*token_index); | ||
| 739 | *token_index += 1; | ||
| 740 | ast_expect_token(pc, export_name, TokenIdStringLiteral); | ||
| 741 | |||
| 742 | parse_string_literal(pc, export_name, &node->data.root_export_decl.name); | ||
| 743 | |||
| 744 | Token *semicolon = &pc->tokens->at(*token_index); | ||
| 745 | *token_index += 1; | ||
| 746 | ast_expect_token(pc, semicolon, TokenIdSemicolon); | ||
| 747 | |||
| 748 | return node; | ||
| 749 | } | ||
| 750 | |||
| 751 | /* | ||
| 752 | Root : RootExportDecl many(TopLevelDecl) token(EOF) | ||
| 753 | */ | ||
| 717 | AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) { | 754 | AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) { |
| 718 | ParseContext pc = {0}; | 755 | ParseContext pc = {0}; |
| 719 | pc.buf = buf; | 756 | pc.buf = buf; |
| ... | @@ -721,6 +758,9 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) { | ... | @@ -721,6 +758,9 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) { |
| 721 | pc.tokens = tokens; | 758 | pc.tokens = tokens; |
| 722 | 759 | ||
| 723 | int token_index = 0; | 760 | int token_index = 0; |
| 761 | |||
| 762 | pc.root->data.root.root_export_decl = ast_parse_root_export_decl(&pc, &token_index); | ||
| 763 | |||
| 724 | ast_parse_top_level_decls(&pc, &token_index, &pc.root->data.root.top_level_decls); | 764 | ast_parse_top_level_decls(&pc, &token_index, &pc.root->data.root.top_level_decls); |
| 725 | 765 | ||
| 726 | if (token_index != tokens->length - 1) { | 766 | if (token_index != tokens->length - 1) { |
src/parser.hpp+8| ... | @@ -17,6 +17,7 @@ struct CodeGenNode; | ... | @@ -17,6 +17,7 @@ struct CodeGenNode; |
| 17 | 17 | ||
| 18 | enum NodeType { | 18 | enum NodeType { |
| 19 | NodeTypeRoot, | 19 | NodeTypeRoot, |
| 20 | NodeTypeRootExportDecl, | ||
| 20 | NodeTypeFnProto, | 21 | NodeTypeFnProto, |
| 21 | NodeTypeFnDef, | 22 | NodeTypeFnDef, |
| 22 | NodeTypeFnDecl, | 23 | NodeTypeFnDecl, |
| ... | @@ -31,6 +32,7 @@ enum NodeType { | ... | @@ -31,6 +32,7 @@ enum NodeType { |
| 31 | }; | 32 | }; |
| 32 | 33 | ||
| 33 | struct AstNodeRoot { | 34 | struct AstNodeRoot { |
| 35 | AstNode *root_export_decl; | ||
| 34 | ZigList<AstNode *> top_level_decls; | 36 | ZigList<AstNode *> top_level_decls; |
| 35 | }; | 37 | }; |
| 36 | 38 | ||
| ... | @@ -113,6 +115,11 @@ struct AstNodeDirective { | ... | @@ -113,6 +115,11 @@ struct AstNodeDirective { |
| 113 | Buf param; | 115 | Buf param; |
| 114 | }; | 116 | }; |
| 115 | 117 | ||
| 118 | struct AstNodeRootExportDecl { | ||
| 119 | Buf type; | ||
| 120 | Buf name; | ||
| 121 | }; | ||
| 122 | |||
| 116 | struct AstNode { | 123 | struct AstNode { |
| 117 | enum NodeType type; | 124 | enum NodeType type; |
| 118 | AstNode *parent; | 125 | AstNode *parent; |
| ... | @@ -121,6 +128,7 @@ struct AstNode { | ... | @@ -121,6 +128,7 @@ struct AstNode { |
| 121 | CodeGenNode *codegen_node; | 128 | CodeGenNode *codegen_node; |
| 122 | union { | 129 | union { |
| 123 | AstNodeRoot root; | 130 | AstNodeRoot root; |
| 131 | AstNodeRootExportDecl root_export_decl; | ||
| 124 | AstNodeFnDef fn_def; | 132 | AstNodeFnDef fn_def; |
| 125 | AstNodeFnDecl fn_decl; | 133 | AstNodeFnDecl fn_decl; |
| 126 | AstNodeFnProto fn_proto; | 134 | AstNodeFnProto fn_proto; |
test/run_tests.cpp+4| ... | @@ -39,6 +39,10 @@ static void add_simple_case(const char *case_name, const char *source, const cha | ... | @@ -39,6 +39,10 @@ static void add_simple_case(const char *case_name, const char *source, const cha |
| 39 | 39 | ||
| 40 | test_case->compiler_args.append("build"); | 40 | test_case->compiler_args.append("build"); |
| 41 | test_case->compiler_args.append(tmp_source_path); | 41 | test_case->compiler_args.append(tmp_source_path); |
| 42 | test_case->compiler_args.append("--export"); | ||
| 43 | test_case->compiler_args.append("exe"); | ||
| 44 | test_case->compiler_args.append("--name"); | ||
| 45 | test_case->compiler_args.append("test"); | ||
| 42 | test_case->compiler_args.append("--output"); | 46 | test_case->compiler_args.append("--output"); |
| 43 | test_case->compiler_args.append(tmp_exe_path); | 47 | test_case->compiler_args.append(tmp_exe_path); |
| 44 | test_case->compiler_args.append("--release"); | 48 | test_case->compiler_args.append("--release"); |