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
4242
4343## Roadmap
4444
45 * ability to specify version
46 * cli ability to override library export locations
47 * add test for building library
4845 * variables and parameters
4946 * Export .so library
5047 * Multiple files
......@@ -81,11 +78,11 @@ zig | C equivalent | Description
8178### Grammar
8279
8380```
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 | ExternBlock
85RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon)
8986
9087ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnDecl) token(RBrace)
9188
example/mathtest.zig+1
......@@ -1,3 +1,4 @@
1#version("2.0.0")
12export library "mathtest";
23
34export fn add(a: i32, b: i32) -> i32 {
src/codegen.cpp+76-37
......@@ -10,6 +10,7 @@
1010#include "zig_llvm.hpp"
1111#include "os.hpp"
1212#include "config.h"
13#include "error.hpp"
1314
1415#include <stdio.h>
1516
......@@ -79,6 +80,10 @@ struct CodeGen {
7980 OutType out_type;
8081 FnTableEntry *cur_fn;
8182 bool c_stdint_used;
83 AstNode *root_export_decl;
84 int version_major;
85 int version_minor;
86 int version_patch;
8287};
8388
8489struct TypeNode {
......@@ -169,6 +174,30 @@ static bool type_is_unreachable(AstNode *type_node) {
169174 return type_node->codegen_node->data.type_node.entry->id == TypeIdUnreachable;
170175}
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
172201static void find_declarations(CodeGen *g, AstNode *node);
173202
174203static void resolve_type_and_recurse(CodeGen *g, AstNode *node) {
......@@ -303,13 +332,25 @@ static void find_declarations(CodeGen *g, AstNode *node) {
303332 case NodeTypeDirective:
304333 // we handled directives in the parent function
305334 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;
306348 case NodeTypeFnDecl:
307349 case NodeTypeReturnExpr:
308350 case NodeTypeRoot:
309351 case NodeTypeBlock:
310352 case NodeTypeBinOpExpr:
311353 case NodeTypeFnCallExpr:
312 case NodeTypeRootExportDecl:
313354 case NodeTypeNumberLiteral:
314355 case NodeTypeStringLiteral:
315356 case NodeTypeUnreachable:
......@@ -385,36 +426,6 @@ static void analyze_node(CodeGen *g, AstNode *node) {
385426 switch (node->type) {
386427 case NodeTypeRoot:
387428 {
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
418429 // Iterate once over the top level declarations to build the function table
419430 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
420431 AstNode *child = node->data.root.top_level_decls.at(i);
......@@ -424,10 +435,40 @@ static void analyze_node(CodeGen *g, AstNode *node) {
424435 AstNode *child = node->data.root.top_level_decls.at(i);
425436 analyze_node(g, child);
426437 }
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 }
427445 break;
428446 }
429447 case NodeTypeRootExportDecl:
430 // handled in parent
448 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 }
431472 break;
432473 case NodeTypeExternBlock:
433474 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) {
14011442 }
14021443
14031444 if (g->out_type == OutTypeLib) {
1404 int major = 1;
1405 int minor = 0;
1406 int patch = 0;
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);
1445 Buf *out_lib_so = buf_sprintf("lib%s.so.%d.%d.%d",
1446 buf_ptr(g->out_name), g->version_major, g->version_minor, g->version_patch);
1447 Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->out_name), g->version_major);
14091448 args.append("-shared");
14101449 args.append("-soname");
14111450 args.append(buf_ptr(soname));
src/error.cpp+1
......@@ -2,6 +2,7 @@
22
33const char *err_str(int err) {
44 switch ((enum Error)err) {
5 case ErrorNone: return "(no error)";
56 case ErrorNoMem: return "out of memory";
67 case ErrorInvalidFormat: return "invalid format";
78 }
src/error.hpp+1
......@@ -9,6 +9,7 @@
99#define ERROR_HPP
1010
1111enum Error {
12 ErrorNone,
1213 ErrorNoMem,
1314 ErrorInvalidFormat,
1415};
src/parser.cpp+45-30
......@@ -1195,6 +1195,44 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool
11951195 zig_unreachable();
11961196}
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*/
11981236static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
11991237 for (;;) {
12001238 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
12021240 pc->directive_list = allocate<ZigList<AstNode*>>(1);
12031241 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
12051249 AstNode *fn_decl_node = ast_parse_fn_def(pc, token_index, false);
12061250 if (fn_decl_node) {
12071251 top_level_decls->append(fn_decl_node);
......@@ -1224,41 +1268,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
12241268 zig_unreachable();
12251269}
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
12541271/*
1255Root : RootExportDecl many(TopLevelDecl) token(EOF)
1272Root : many(TopLevelDecl) token(EOF)
12561273 */
12571274static AstNode *ast_parse_root(ParseContext *pc, int *token_index) {
12581275 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
12621277 ast_parse_top_level_decls(pc, token_index, &node->data.root.top_level_decls);
12631278
12641279 if (*token_index != pc->tokens->length - 1) {
src/parser.hpp+1-1
......@@ -38,7 +38,6 @@ enum NodeType {
3838};
3939
4040struct AstNodeRoot {
41 AstNode *root_export_decl;
4241 ZigList<AstNode *> top_level_decls;
4342};
4443
......@@ -138,6 +137,7 @@ struct AstNodeDirective {
138137struct AstNodeRootExportDecl {
139138 Buf type;
140139 Buf name;
140 ZigList<AstNode *> *directives;
141141};
142142
143143struct AstNodeCastExpr {
src/tokenizer.cpp-1
......@@ -608,4 +608,3 @@ void print_tokens(Buf *buf, ZigList<Token> *tokens) {
608608 fprintf(stderr, "\n");
609609 }
610610}
611