authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-27 21:24:11-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-27 21:24:47-07:00
logcb4773ce29fbac856811f69a3fb5b17b7e83d44d
tree5c87a210beae92c243dcd7818865447b35d44be5
parent4cc95174a77f7cbb42b371bb892c55a8349bc7fa

add root export declaration which is overridable by command line options


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.
3232
3333## Roadmap
3434
35 * Simple .so library
35 * Math expression
36 * Export .so library
37 * Export .o file
3638 * Multiple files
3739 * inline assembly and syscalls
3840 * running code at compile time
......@@ -66,7 +68,9 @@ zig | C equivalent | Description
6668### Grammar
6769
6870```
69Root : many(TopLevelDecl) token(EOF)
71Root : RootExportDecl many(TopLevelDecl) token(EOF)
72
73RootExportDecl : token(Export) token(Symbol) token(String) token(Semicolon)
7074
7175TopLevelDecl : FnDef | ExternBlock
7276
doc/vim/syntax/zig.vim+15
......@@ -10,7 +10,22 @@ endif
1010syn keyword zigKeyword fn return mut const extern unreachable export pub
1111syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void
1212
13syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell
14syn region zigCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=zigTodo,@Spell
15syn region zigCommentBlock matchgroup=zigCommentBlock start="/\*\%(!\|\*[*/]\@!\)\@!" end="\*/" contains=zigTodo,zigCommentBlockNest,@Spell
16syn region zigCommentBlockDoc matchgroup=zigCommentBlockDoc start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=zigTodo,zigCommentBlockDocNest,@Spell
17syn region zigCommentBlockNest matchgroup=zigCommentBlock start="/\*" end="\*/" contains=zigTodo,zigCommentBlockNest,@Spell contained transparent
18syn region zigCommentBlockDocNest matchgroup=zigCommentBlockDoc start="/\*" end="\*/" contains=zigTodo,zigCommentBlockDocNest,@Spell contained transparent
19
20syn keyword zigTodo contained TODO XXX
21
1322let b:current_syntax = "zig"
1423
1524hi def link zigKeyword Keyword
1625hi def link zigType Type
26hi def link zigCommentLine Comment
27hi def link zigCommentLineDoc SpecialComment
28hi def link zigCommentBlock zigCommentLine
29hi def link zigCommentBlockDoc zigCommentLineDoc
30hi def link zigTodo Todo
31
example/hello.zig+2
......@@ -1,3 +1,5 @@
1export executable "hello";
2
13#link("c")
24extern {
35 fn puts(s: *mut u8) -> i32;
example/math.zig created+6
......@@ -0,0 +1,6 @@
1export library "math";
2
3export fn add(a: i32, b: i32) -> i32 {
4 return a + b;
5}
6
src/codegen.cpp+70-8
......@@ -75,6 +75,8 @@ struct CodeGen {
7575 ZigList<llvm::DIScope *> block_scopes;
7676 llvm::DIFile *di_file;
7777 ZigList<FnTableEntry *> fn_defs;
78 Buf *out_name;
79 OutType out_type;
7880};
7981
8082struct TypeNode {
......@@ -103,6 +105,8 @@ CodeGen *create_codegen(AstNode *root, Buf *in_full_path) {
103105 g->is_static = false;
104106 g->build_type = CodeGenBuildTypeDebug;
105107 g->strip_debug_symbols = false;
108 g->out_name = nullptr;
109 g->out_type = OutTypeUnknown;
106110
107111 os_path_split(in_full_path, &g->in_dir, &g->in_file);
108112 return g;
......@@ -120,6 +124,14 @@ void codegen_set_strip(CodeGen *g, bool strip) {
120124 g->strip_debug_symbols = strip;
121125}
122126
127void codegen_set_out_type(CodeGen *g, OutType out_type) {
128 g->out_type = out_type;
129}
130
131void codegen_set_out_name(CodeGen *g, Buf *out_name) {
132 g->out_name = out_name;
133}
134
123135static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
124136 g->errors.add_one();
125137 ErrorMsg *last_msg = &g->errors.last();
......@@ -294,6 +306,7 @@ static void find_declarations(CodeGen *g, AstNode *node) {
294306 case NodeTypeBlock:
295307 case NodeTypeExpression:
296308 case NodeTypeFnCall:
309 case NodeTypeRootExportDecl:
297310 zig_unreachable();
298311 }
299312}
......@@ -355,15 +368,50 @@ static void check_fn_def_control_flow(CodeGen *g, AstNode *node) {
355368static void analyze_node(CodeGen *g, AstNode *node) {
356369 switch (node->type) {
357370 case NodeTypeRoot:
358 // Iterate once over the top level declarations to build the function table
359 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
360 AstNode *child = node->data.root.top_level_decls.at(i);
361 find_declarations(g, child);
362 }
363 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
364 AstNode *child = node->data.root.top_level_decls.at(i);
365 analyze_node(g, child);
371 {
372 AstNode *root_export_decl_node = node->data.root.root_export_decl;
373 if (root_export_decl_node) {
374 assert(root_export_decl_node->type == NodeTypeRootExportDecl);
375 if (!g->out_name)
376 g->out_name = &root_export_decl_node->data.root_export_decl.name;
377
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;
366412 }
413 case NodeTypeRootExportDecl:
414 // handled in parent
367415 break;
368416 case NodeTypeExternBlock:
369417 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)
674722 case NodeTypeFnCall:
675723 case NodeTypeExternBlock:
676724 case NodeTypeDirective:
725 case NodeTypeRootExportDecl:
677726 zig_unreachable();
678727 }
679728 }
......@@ -929,6 +978,15 @@ static Buf *get_dynamic_linker(CodeGen *g) {
929978 }
930979}
931980
981/*
982
983# static link into libfoo.a
984ar cq libfoo.a foo1.o foo2.o
985
986# dynamic link into libfoo.so
987gcc -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*/
932990void code_gen_link(CodeGen *g, const char *out_file) {
933991 LLVMPassRegistryRef registry = LLVMGetGlobalPassRegistry();
934992 LLVMInitializeCore(registry);
......@@ -937,6 +995,10 @@ void code_gen_link(CodeGen *g, const char *out_file) {
937995 LLVMZigInitializeLowerIntrinsicsPass(registry);
938996 LLVMZigInitializeUnreachableBlockElimPass(registry);
939997
998 if (!out_file) {
999 out_file = buf_ptr(g->out_name);
1000 }
1001
9401002 Buf out_file_o = BUF_INIT;
9411003 buf_init_from_str(&out_file_o, out_file);
9421004 buf_append_str(&out_file_o, ".o");
src/codegen.hpp+10
......@@ -12,6 +12,14 @@
1212
1313struct CodeGen;
1414
15enum OutType {
16 OutTypeUnknown,
17 OutTypeExe,
18 OutTypeLib,
19 OutTypeObj,
20};
21
22
1523struct ErrorMsg {
1624 int line_start;
1725 int column_start;
......@@ -30,6 +38,8 @@ enum CodeGenBuildType {
3038void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type);
3139void codegen_set_is_static(CodeGen *codegen, bool is_static);
3240void codegen_set_strip(CodeGen *codegen, bool strip);
41void codegen_set_out_type(CodeGen *codegen, OutType out_type);
42void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
3343
3444void semantic_analyze(CodeGen *g);
3545
src/main.cpp+45-20
......@@ -28,18 +28,24 @@
2828static int usage(const char *arg0) {
2929 fprintf(stderr, "Usage: %s [command] [options] target\n"
3030 "Commands:\n"
31 " build create an executable from target\n"
32 "Options:\n"
33 " --output output file\n"
34 " --version print version number and exit\n"
35 " -Ipath add path to header include path\n"
36 " --release build with optimizations on\n"
37 " --strip exclude debug symbols\n"
38 " --static build a static executable\n"
31 " build create executable, object, or library from target\n"
32 " version print version number and exit\n"
33 "Optional Options:\n"
34 " --release build with optimizations on and debug protection off\n"
35 " --static output will be statically linked\n"
36 " --strip exclude debug symbols\n"
37 " --export [exe|lib|obj] override output type\n"
38 " --name [name] override output name\n"
39 " --output [file] override destination path\n"
3940 , arg0);
4041 return EXIT_FAILURE;
4142}
4243
44static int version(void) {
45 printf("%s\n", ZIG_VERSION_STRING);
46 return EXIT_SUCCESS;
47}
48
4349static Buf *fetch_file(FILE *f) {
4450 int fd = fileno(f);
4551 struct stat st;
......@@ -58,12 +64,12 @@ static Buf *fetch_file(FILE *f) {
5864 return buf;
5965}
6066
61static int build(const char *arg0, const char *in_file, const char *out_file,
62 ZigList<char *> *include_paths, bool release, bool strip, bool is_static)
67static int build(const char *arg0, const char *in_file, const char *out_file, bool release,
68 bool strip, bool is_static, OutType out_type, char *out_name)
6369{
6470 static char cur_dir[1024];
6571
66 if (!in_file || !out_file)
72 if (!in_file)
6773 return usage(arg0);
6874
6975 FILE *in_f;
......@@ -100,6 +106,10 @@ static int build(const char *arg0, const char *in_file, const char *out_file,
100106 codegen_set_build_type(codegen, release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug);
101107 codegen_set_strip(codegen, strip);
102108 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));
103113 semantic_analyze(codegen);
104114 ZigList<ErrorMsg> *errors = codegen_error_messages(codegen);
105115 if (errors->length == 0) {
......@@ -135,25 +145,25 @@ static int build(const char *arg0, const char *in_file, const char *out_file,
135145enum Cmd {
136146 CmdNone,
137147 CmdBuild,
148 CmdVersion,
138149};
139150
140151int main(int argc, char **argv) {
141152 char *arg0 = argv[0];
142153 char *in_file = NULL;
143154 char *out_file = NULL;
144 ZigList<char *> include_paths = {0};
145155 bool release = false;
146156 bool strip = false;
147157 bool is_static = false;
148158
159 OutType out_type = OutTypeUnknown;
160 char *out_name = NULL;
161
149162 Cmd cmd = CmdNone;
150163 for (int i = 1; i < argc; i += 1) {
151164 char *arg = argv[i];
152165 if (arg[0] == '-' && arg[1] == '-') {
153 if (strcmp(arg, "--version") == 0) {
154 printf("%s\n", ZIG_VERSION_STRING);
155 return EXIT_SUCCESS;
156 } else if (strcmp(arg, "--release") == 0) {
166 if (strcmp(arg, "--release") == 0) {
157167 release = true;
158168 } else if (strcmp(arg, "--strip") == 0) {
159169 strip = true;
......@@ -165,15 +175,27 @@ int main(int argc, char **argv) {
165175 i += 1;
166176 if (strcmp(arg, "--output") == 0) {
167177 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];
168190 } else {
169191 return usage(arg0);
170192 }
171193 }
172 } else if (arg[0] == '-' && arg[1] == 'I') {
173 include_paths.append(arg + 2);
174194 } else if (cmd == CmdNone) {
175195 if (strcmp(arg, "build") == 0) {
176196 cmd = CmdBuild;
197 } else if (strcmp(arg, "version") == 0) {
198 cmd = CmdVersion;
177199 } else {
178200 fprintf(stderr, "Unrecognized command: %s\n", arg);
179201 return usage(arg0);
......@@ -189,6 +211,8 @@ int main(int argc, char **argv) {
189211 return usage(arg0);
190212 }
191213 break;
214 case CmdVersion:
215 return usage(arg0);
192216 }
193217 }
194218 }
......@@ -197,9 +221,10 @@ int main(int argc, char **argv) {
197221 case CmdNone:
198222 return usage(arg0);
199223 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();
201227 }
202228
203229 zig_unreachable();
204230}
205
src/parser.cpp+40
......@@ -29,6 +29,8 @@ const char *node_type_str(NodeType node_type) {
2929 switch (node_type) {
3030 case NodeTypeRoot:
3131 return "Root";
32 case NodeTypeRootExportDecl:
33 return "RootExportDecl";
3234 case NodeTypeFnDef:
3335 return "FnDef";
3436 case NodeTypeFnDecl:
......@@ -68,6 +70,11 @@ void ast_print(AstNode *node, int indent) {
6870 ast_print(child, indent + 2);
6971 }
7072 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;
7178 case NodeTypeFnDef:
7279 {
7380 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
714721 zig_unreachable();
715722}
716723
724static 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/*
752Root : RootExportDecl many(TopLevelDecl) token(EOF)
753 */
717754AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) {
718755 ParseContext pc = {0};
719756 pc.buf = buf;
......@@ -721,6 +758,9 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) {
721758 pc.tokens = tokens;
722759
723760 int token_index = 0;
761
762 pc.root->data.root.root_export_decl = ast_parse_root_export_decl(&pc, &token_index);
763
724764 ast_parse_top_level_decls(&pc, &token_index, &pc.root->data.root.top_level_decls);
725765
726766 if (token_index != tokens->length - 1) {
src/parser.hpp+8
......@@ -17,6 +17,7 @@ struct CodeGenNode;
1717
1818enum NodeType {
1919 NodeTypeRoot,
20 NodeTypeRootExportDecl,
2021 NodeTypeFnProto,
2122 NodeTypeFnDef,
2223 NodeTypeFnDecl,
......@@ -31,6 +32,7 @@ enum NodeType {
3132};
3233
3334struct AstNodeRoot {
35 AstNode *root_export_decl;
3436 ZigList<AstNode *> top_level_decls;
3537};
3638
......@@ -113,6 +115,11 @@ struct AstNodeDirective {
113115 Buf param;
114116};
115117
118struct AstNodeRootExportDecl {
119 Buf type;
120 Buf name;
121};
122
116123struct AstNode {
117124 enum NodeType type;
118125 AstNode *parent;
......@@ -121,6 +128,7 @@ struct AstNode {
121128 CodeGenNode *codegen_node;
122129 union {
123130 AstNodeRoot root;
131 AstNodeRootExportDecl root_export_decl;
124132 AstNodeFnDef fn_def;
125133 AstNodeFnDecl fn_decl;
126134 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
3939
4040 test_case->compiler_args.append("build");
4141 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");
4246 test_case->compiler_args.append("--output");
4347 test_case->compiler_args.append(tmp_exe_path);
4448 test_case->compiler_args.append("--release");