authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-30 02:11:31-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-11-30 02:12:20-07:00
log8f0f318c393b815d547ea00741d7b1ebf99eaffe
treef5a80e8fb327f4da94a40cb3ae179dbf2c3ddf9a
parentac0c5a3707c4a79c27e60242e44231cc05964f0f

add directive to specify root export version


8 files changed, 128 insertions(+), 75 deletions(-)

README.md+3-6
...@@ -42,9 +42,6 @@ make...@@ -42,9 +42,6 @@ make
4242
43## Roadmap43## Roadmap
4444
45 * ability to specify version
46 * cli ability to override library export locations
47 * add test for building library
48 * variables and parameters45 * variables and parameters
49 * Export .so library46 * Export .so library
50 * Multiple files47 * Multiple files
...@@ -81,11 +78,11 @@ zig | C equivalent | Description...@@ -81,11 +78,11 @@ zig | C equivalent | Description
81### Grammar78### Grammar
8279
83```80```
84Root : RootExportDecl many(TopLevelDecl) token(EOF)81Root : many(TopLevelDecl) token(EOF)
8582
86RootExportDecl : token(Export) token(Symbol) token(String) token(Semicolon)83TopLevelDecl : FnDef | ExternBlock | RootExportDecl
8784
88TopLevelDecl : FnDef | ExternBlock85RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon)
8986
90ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnDecl) token(RBrace)87ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnDecl) token(RBrace)
9188
example/mathtest.zig+1
...@@ -1,3 +1,4 @@...@@ -1,3 +1,4 @@
1#version("2.0.0")
1export library "mathtest";2export library "mathtest";
23
3export fn add(a: i32, b: i32) -> i32 {4export fn add(a: i32, b: i32) -> i32 {
src/codegen.cpp+76-37
...@@ -10,6 +10,7 @@...@@ -10,6 +10,7 @@
10#include "zig_llvm.hpp"10#include "zig_llvm.hpp"
11#include "os.hpp"11#include "os.hpp"
12#include "config.h"12#include "config.h"
13#include "error.hpp"
1314
14#include <stdio.h>15#include <stdio.h>
1516
...@@ -79,6 +80,10 @@ struct CodeGen {...@@ -79,6 +80,10 @@ struct CodeGen {
79 OutType out_type;80 OutType out_type;
80 FnTableEntry *cur_fn;81 FnTableEntry *cur_fn;
81 bool c_stdint_used;82 bool c_stdint_used;
83 AstNode *root_export_decl;
84 int version_major;
85 int version_minor;
86 int version_patch;
82};87};
8388
84struct TypeNode {89struct TypeNode {
...@@ -169,6 +174,30 @@ static bool type_is_unreachable(AstNode *type_node) {...@@ -169,6 +174,30 @@ static bool type_is_unreachable(AstNode *type_node) {
169 return type_node->codegen_node->data.type_node.entry->id == TypeIdUnreachable;174 return type_node->codegen_node->data.type_node.entry->id == TypeIdUnreachable;
170}175}
171176
177
178static int parse_version_string(Buf *buf, int *major, int *minor, int *patch) {
179 char *dot1 = strstr(buf_ptr(buf), ".");
180 if (!dot1)
181 return ErrorInvalidFormat;
182 char *dot2 = strstr(dot1 + 1, ".");
183 if (!dot2)
184 return ErrorInvalidFormat;
185
186 *major = (int)strtol(buf_ptr(buf), nullptr, 10);
187 *minor = (int)strtol(dot1 + 1, nullptr, 10);
188 *patch = (int)strtol(dot2 + 1, nullptr, 10);
189
190 return ErrorNone;
191}
192
193static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node) {
194 int err;
195 if ((err = parse_version_string(version_buf, &g->version_major, &g->version_minor, &g->version_patch))) {
196 add_node_error(g, node,
197 buf_sprintf("invalid version string"));
198 }
199}
200
172static void find_declarations(CodeGen *g, AstNode *node);201static void find_declarations(CodeGen *g, AstNode *node);
173202
174static void resolve_type_and_recurse(CodeGen *g, AstNode *node) {203static void resolve_type_and_recurse(CodeGen *g, AstNode *node) {
...@@ -303,13 +332,25 @@ static void find_declarations(CodeGen *g, AstNode *node) {...@@ -303,13 +332,25 @@ static void find_declarations(CodeGen *g, AstNode *node) {
303 case NodeTypeDirective:332 case NodeTypeDirective:
304 // we handled directives in the parent function333 // we handled directives in the parent function
305 break;334 break;
335 case NodeTypeRootExportDecl:
336 for (int i = 0; i < node->data.root_export_decl.directives->length; i += 1) {
337 AstNode *directive_node = node->data.root_export_decl.directives->at(i);
338 Buf *name = &directive_node->data.directive.name;
339 Buf *param = &directive_node->data.directive.param;
340 if (buf_eql_str(name, "version")) {
341 set_root_export_version(g, param, directive_node);
342 } else {
343 add_node_error(g, directive_node,
344 buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
345 }
346 }
347 break;
306 case NodeTypeFnDecl:348 case NodeTypeFnDecl:
307 case NodeTypeReturnExpr:349 case NodeTypeReturnExpr:
308 case NodeTypeRoot:350 case NodeTypeRoot:
309 case NodeTypeBlock:351 case NodeTypeBlock:
310 case NodeTypeBinOpExpr:352 case NodeTypeBinOpExpr:
311 case NodeTypeFnCallExpr:353 case NodeTypeFnCallExpr:
312 case NodeTypeRootExportDecl:
313 case NodeTypeNumberLiteral:354 case NodeTypeNumberLiteral:
314 case NodeTypeStringLiteral:355 case NodeTypeStringLiteral:
315 case NodeTypeUnreachable:356 case NodeTypeUnreachable:
...@@ -385,36 +426,6 @@ static void analyze_node(CodeGen *g, AstNode *node) {...@@ -385,36 +426,6 @@ static void analyze_node(CodeGen *g, AstNode *node) {
385 switch (node->type) {426 switch (node->type) {
386 case NodeTypeRoot:427 case NodeTypeRoot:
387 {428 {
388 AstNode *root_export_decl_node = node->data.root.root_export_decl;
389 if (root_export_decl_node) {
390 assert(root_export_decl_node->type == NodeTypeRootExportDecl);
391 if (!g->out_name)
392 g->out_name = &root_export_decl_node->data.root_export_decl.name;
393
394 Buf *out_type = &root_export_decl_node->data.root_export_decl.type;
395 OutType export_out_type;
396 if (buf_eql_str(out_type, "executable")) {
397 export_out_type = OutTypeExe;
398 } else if (buf_eql_str(out_type, "library")) {
399 export_out_type = OutTypeLib;
400 } else if (buf_eql_str(out_type, "object")) {
401 export_out_type = OutTypeObj;
402 } else {
403 add_node_error(g, root_export_decl_node,
404 buf_sprintf("invalid export type: '%s'", buf_ptr(out_type)));
405 }
406 if (g->out_type == OutTypeUnknown)
407 g->out_type = export_out_type;
408 } else {
409 if (!g->out_name) {
410 add_node_error(g, node,
411 buf_sprintf("missing export declaration and output name not provided"));
412 } else if (g->out_type == OutTypeUnknown) {
413 add_node_error(g, node,
414 buf_sprintf("missing export declaration and export type not provided"));
415 }
416 }
417
418 // Iterate once over the top level declarations to build the function table429 // Iterate once over the top level declarations to build the function table
419 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {430 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
420 AstNode *child = node->data.root.top_level_decls.at(i);431 AstNode *child = node->data.root.top_level_decls.at(i);
...@@ -424,10 +435,40 @@ static void analyze_node(CodeGen *g, AstNode *node) {...@@ -424,10 +435,40 @@ static void analyze_node(CodeGen *g, AstNode *node) {
424 AstNode *child = node->data.root.top_level_decls.at(i);435 AstNode *child = node->data.root.top_level_decls.at(i);
425 analyze_node(g, child);436 analyze_node(g, child);
426 }437 }
438 if (!g->out_name) {
439 add_node_error(g, node,
440 buf_sprintf("missing export declaration and output name not provided"));
441 } else if (g->out_type == OutTypeUnknown) {
442 add_node_error(g, node,
443 buf_sprintf("missing export declaration and export type not provided"));
444 }
427 break;445 break;
428 }446 }
429 case NodeTypeRootExportDecl:447 case NodeTypeRootExportDecl:
430 // handled in parent448 if (g->root_export_decl) {
449 add_node_error(g, node,
450 buf_sprintf("only one root export declaration allowed"));
451 } else {
452 g->root_export_decl = node;
453
454 if (!g->out_name)
455 g->out_name = &node->data.root_export_decl.name;
456
457 Buf *out_type = &node->data.root_export_decl.type;
458 OutType export_out_type;
459 if (buf_eql_str(out_type, "executable")) {
460 export_out_type = OutTypeExe;
461 } else if (buf_eql_str(out_type, "library")) {
462 export_out_type = OutTypeLib;
463 } else if (buf_eql_str(out_type, "object")) {
464 export_out_type = OutTypeObj;
465 } else {
466 add_node_error(g, node,
467 buf_sprintf("invalid export type: '%s'", buf_ptr(out_type)));
468 }
469 if (g->out_type == OutTypeUnknown)
470 g->out_type = export_out_type;
471 }
431 break;472 break;
432 case NodeTypeExternBlock:473 case NodeTypeExternBlock:
433 for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) {474 for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) {
...@@ -1401,11 +1442,9 @@ void code_gen_link(CodeGen *g, const char *out_file) {...@@ -1401,11 +1442,9 @@ void code_gen_link(CodeGen *g, const char *out_file) {
1401 }1442 }
14021443
1403 if (g->out_type == OutTypeLib) {1444 if (g->out_type == OutTypeLib) {
1404 int major = 1;1445 Buf *out_lib_so = buf_sprintf("lib%s.so.%d.%d.%d",
1405 int minor = 0;1446 buf_ptr(g->out_name), g->version_major, g->version_minor, g->version_patch);
1406 int patch = 0;1447 Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->out_name), g->version_major);
1407 Buf *out_lib_so = buf_sprintf("lib%s.so.%d.%d.%d", buf_ptr(g->out_name), major, minor, patch);
1408 Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->out_name), major);
1409 args.append("-shared");1448 args.append("-shared");
1410 args.append("-soname");1449 args.append("-soname");
1411 args.append(buf_ptr(soname));1450 args.append(buf_ptr(soname));
src/error.cpp+1
...@@ -2,6 +2,7 @@...@@ -2,6 +2,7 @@
22
3const char *err_str(int err) {3const char *err_str(int err) {
4 switch ((enum Error)err) {4 switch ((enum Error)err) {
5 case ErrorNone: return "(no error)";
5 case ErrorNoMem: return "out of memory";6 case ErrorNoMem: return "out of memory";
6 case ErrorInvalidFormat: return "invalid format";7 case ErrorInvalidFormat: return "invalid format";
7 }8 }
src/error.hpp+1
...@@ -9,6 +9,7 @@...@@ -9,6 +9,7 @@
9#define ERROR_HPP9#define ERROR_HPP
1010
11enum Error {11enum Error {
12 ErrorNone,
12 ErrorNoMem,13 ErrorNoMem,
13 ErrorInvalidFormat,14 ErrorInvalidFormat,
14};15};
src/parser.cpp+45-30
...@@ -1195,6 +1195,44 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool...@@ -1195,6 +1195,44 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool
1195 zig_unreachable();1195 zig_unreachable();
1196}1196}
11971197
1198/*
1199RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon)
1200*/
1201static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, bool mandatory) {
1202 assert(mandatory == false);
1203
1204 Token *export_kw = &pc->tokens->at(*token_index);
1205 if (export_kw->id != TokenIdKeywordExport)
1206 return nullptr;
1207
1208 Token *export_type = &pc->tokens->at(*token_index + 1);
1209 if (export_type->id != TokenIdSymbol)
1210 return nullptr;
1211
1212 *token_index += 2;
1213
1214 AstNode *node = ast_create_node(NodeTypeRootExportDecl, export_kw);
1215 node->data.root_export_decl.directives = pc->directive_list;
1216 pc->directive_list = nullptr;
1217
1218 ast_buf_from_token(pc, export_type, &node->data.root_export_decl.type);
1219
1220 Token *export_name = &pc->tokens->at(*token_index);
1221 *token_index += 1;
1222 ast_expect_token(pc, export_name, TokenIdStringLiteral);
1223
1224 parse_string_literal(pc, export_name, &node->data.root_export_decl.name);
1225
1226 Token *semicolon = &pc->tokens->at(*token_index);
1227 *token_index += 1;
1228 ast_expect_token(pc, semicolon, TokenIdSemicolon);
1229
1230 return node;
1231}
1232
1233/*
1234TopLevelDecl : FnDef | ExternBlock | RootExportDecl
1235*/
1198static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {1236static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
1199 for (;;) {1237 for (;;) {
1200 Token *directive_token = &pc->tokens->at(*token_index);1238 Token *directive_token = &pc->tokens->at(*token_index);
...@@ -1202,6 +1240,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis...@@ -1202,6 +1240,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
1202 pc->directive_list = allocate<ZigList<AstNode*>>(1);1240 pc->directive_list = allocate<ZigList<AstNode*>>(1);
1203 ast_parse_directives(pc, token_index, pc->directive_list);1241 ast_parse_directives(pc, token_index, pc->directive_list);
12041242
1243 AstNode *root_export_decl_node = ast_parse_root_export_decl(pc, token_index, false);
1244 if (root_export_decl_node) {
1245 top_level_decls->append(root_export_decl_node);
1246 continue;
1247 }
1248
1205 AstNode *fn_decl_node = ast_parse_fn_def(pc, token_index, false);1249 AstNode *fn_decl_node = ast_parse_fn_def(pc, token_index, false);
1206 if (fn_decl_node) {1250 if (fn_decl_node) {
1207 top_level_decls->append(fn_decl_node);1251 top_level_decls->append(fn_decl_node);
...@@ -1224,41 +1268,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis...@@ -1224,41 +1268,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
1224 zig_unreachable();1268 zig_unreachable();
1225}1269}
12261270
1227static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index) {
1228 Token *export_kw = &pc->tokens->at(*token_index);
1229 if (export_kw->id != TokenIdKeywordExport)
1230 return nullptr;
1231 *token_index += 1;
1232
1233 AstNode *node = ast_create_node(NodeTypeRootExportDecl, export_kw);
1234
1235 Token *export_type = &pc->tokens->at(*token_index);
1236 *token_index += 1;
1237 ast_expect_token(pc, export_type, TokenIdSymbol);
1238
1239 ast_buf_from_token(pc, export_type, &node->data.root_export_decl.type);
1240
1241 Token *export_name = &pc->tokens->at(*token_index);
1242 *token_index += 1;
1243 ast_expect_token(pc, export_name, TokenIdStringLiteral);
1244
1245 parse_string_literal(pc, export_name, &node->data.root_export_decl.name);
1246
1247 Token *semicolon = &pc->tokens->at(*token_index);
1248 *token_index += 1;
1249 ast_expect_token(pc, semicolon, TokenIdSemicolon);
1250
1251 return node;
1252}
1253
1254/*1271/*
1255Root : RootExportDecl many(TopLevelDecl) token(EOF)1272Root : many(TopLevelDecl) token(EOF)
1256 */1273 */
1257static AstNode *ast_parse_root(ParseContext *pc, int *token_index) {1274static AstNode *ast_parse_root(ParseContext *pc, int *token_index) {
1258 AstNode *node = ast_create_node(NodeTypeRoot, &pc->tokens->at(*token_index));1275 AstNode *node = ast_create_node(NodeTypeRoot, &pc->tokens->at(*token_index));
12591276
1260 node->data.root.root_export_decl = ast_parse_root_export_decl(pc, token_index);
1261
1262 ast_parse_top_level_decls(pc, token_index, &node->data.root.top_level_decls);1277 ast_parse_top_level_decls(pc, token_index, &node->data.root.top_level_decls);
12631278
1264 if (*token_index != pc->tokens->length - 1) {1279 if (*token_index != pc->tokens->length - 1) {
src/parser.hpp+1-1
...@@ -38,7 +38,6 @@ enum NodeType {...@@ -38,7 +38,6 @@ enum NodeType {
38};38};
3939
40struct AstNodeRoot {40struct AstNodeRoot {
41 AstNode *root_export_decl;
42 ZigList<AstNode *> top_level_decls;41 ZigList<AstNode *> top_level_decls;
43};42};
4443
...@@ -138,6 +137,7 @@ struct AstNodeDirective {...@@ -138,6 +137,7 @@ struct AstNodeDirective {
138struct AstNodeRootExportDecl {137struct AstNodeRootExportDecl {
139 Buf type;138 Buf type;
140 Buf name;139 Buf name;
140 ZigList<AstNode *> *directives;
141};141};
142142
143struct AstNodeCastExpr {143struct AstNodeCastExpr {
src/tokenizer.cpp-1
...@@ -608,4 +608,3 @@ void print_tokens(Buf *buf, ZigList<Token> *tokens) {...@@ -608,4 +608,3 @@ void print_tokens(Buf *buf, ZigList<Token> *tokens) {
608 fprintf(stderr, "\n");608 fprintf(stderr, "\n");
609 }609 }
610}610}
611