Commit 8f0f318c39
Changed files (8)
example/mathtest.zig
@@ -1,3 +1,4 @@
+#version("2.0.0")
export library "mathtest";
export fn add(a: i32, b: i32) -> i32 {
src/codegen.cpp
@@ -10,6 +10,7 @@
#include "zig_llvm.hpp"
#include "os.hpp"
#include "config.h"
+#include "error.hpp"
#include <stdio.h>
@@ -79,6 +80,10 @@ struct CodeGen {
OutType out_type;
FnTableEntry *cur_fn;
bool c_stdint_used;
+ AstNode *root_export_decl;
+ int version_major;
+ int version_minor;
+ int version_patch;
};
struct TypeNode {
@@ -169,6 +174,30 @@ static bool type_is_unreachable(AstNode *type_node) {
return type_node->codegen_node->data.type_node.entry->id == TypeIdUnreachable;
}
+
+static int parse_version_string(Buf *buf, int *major, int *minor, int *patch) {
+ char *dot1 = strstr(buf_ptr(buf), ".");
+ if (!dot1)
+ return ErrorInvalidFormat;
+ char *dot2 = strstr(dot1 + 1, ".");
+ if (!dot2)
+ return ErrorInvalidFormat;
+
+ *major = (int)strtol(buf_ptr(buf), nullptr, 10);
+ *minor = (int)strtol(dot1 + 1, nullptr, 10);
+ *patch = (int)strtol(dot2 + 1, nullptr, 10);
+
+ return ErrorNone;
+}
+
+static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node) {
+ int err;
+ if ((err = parse_version_string(version_buf, &g->version_major, &g->version_minor, &g->version_patch))) {
+ add_node_error(g, node,
+ buf_sprintf("invalid version string"));
+ }
+}
+
static void find_declarations(CodeGen *g, AstNode *node);
static void resolve_type_and_recurse(CodeGen *g, AstNode *node) {
@@ -303,13 +332,25 @@ static void find_declarations(CodeGen *g, AstNode *node) {
case NodeTypeDirective:
// we handled directives in the parent function
break;
+ case NodeTypeRootExportDecl:
+ for (int i = 0; i < node->data.root_export_decl.directives->length; i += 1) {
+ AstNode *directive_node = node->data.root_export_decl.directives->at(i);
+ Buf *name = &directive_node->data.directive.name;
+ Buf *param = &directive_node->data.directive.param;
+ if (buf_eql_str(name, "version")) {
+ set_root_export_version(g, param, directive_node);
+ } else {
+ add_node_error(g, directive_node,
+ buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
+ }
+ }
+ break;
case NodeTypeFnDecl:
case NodeTypeReturnExpr:
case NodeTypeRoot:
case NodeTypeBlock:
case NodeTypeBinOpExpr:
case NodeTypeFnCallExpr:
- case NodeTypeRootExportDecl:
case NodeTypeNumberLiteral:
case NodeTypeStringLiteral:
case NodeTypeUnreachable:
@@ -385,36 +426,6 @@ static void analyze_node(CodeGen *g, AstNode *node) {
switch (node->type) {
case NodeTypeRoot:
{
- AstNode *root_export_decl_node = node->data.root.root_export_decl;
- if (root_export_decl_node) {
- assert(root_export_decl_node->type == NodeTypeRootExportDecl);
- if (!g->out_name)
- g->out_name = &root_export_decl_node->data.root_export_decl.name;
-
- Buf *out_type = &root_export_decl_node->data.root_export_decl.type;
- OutType export_out_type;
- if (buf_eql_str(out_type, "executable")) {
- export_out_type = OutTypeExe;
- } else if (buf_eql_str(out_type, "library")) {
- export_out_type = OutTypeLib;
- } else if (buf_eql_str(out_type, "object")) {
- export_out_type = OutTypeObj;
- } else {
- add_node_error(g, root_export_decl_node,
- buf_sprintf("invalid export type: '%s'", buf_ptr(out_type)));
- }
- if (g->out_type == OutTypeUnknown)
- g->out_type = export_out_type;
- } else {
- if (!g->out_name) {
- add_node_error(g, node,
- buf_sprintf("missing export declaration and output name not provided"));
- } else if (g->out_type == OutTypeUnknown) {
- add_node_error(g, node,
- buf_sprintf("missing export declaration and export type not provided"));
- }
- }
-
// Iterate once over the top level declarations to build the function table
for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
AstNode *child = node->data.root.top_level_decls.at(i);
@@ -424,10 +435,40 @@ static void analyze_node(CodeGen *g, AstNode *node) {
AstNode *child = node->data.root.top_level_decls.at(i);
analyze_node(g, child);
}
+ if (!g->out_name) {
+ add_node_error(g, node,
+ buf_sprintf("missing export declaration and output name not provided"));
+ } else if (g->out_type == OutTypeUnknown) {
+ add_node_error(g, node,
+ buf_sprintf("missing export declaration and export type not provided"));
+ }
break;
}
case NodeTypeRootExportDecl:
- // handled in parent
+ if (g->root_export_decl) {
+ add_node_error(g, node,
+ buf_sprintf("only one root export declaration allowed"));
+ } else {
+ g->root_export_decl = node;
+
+ if (!g->out_name)
+ g->out_name = &node->data.root_export_decl.name;
+
+ Buf *out_type = &node->data.root_export_decl.type;
+ OutType export_out_type;
+ if (buf_eql_str(out_type, "executable")) {
+ export_out_type = OutTypeExe;
+ } else if (buf_eql_str(out_type, "library")) {
+ export_out_type = OutTypeLib;
+ } else if (buf_eql_str(out_type, "object")) {
+ export_out_type = OutTypeObj;
+ } else {
+ add_node_error(g, node,
+ buf_sprintf("invalid export type: '%s'", buf_ptr(out_type)));
+ }
+ if (g->out_type == OutTypeUnknown)
+ g->out_type = export_out_type;
+ }
break;
case NodeTypeExternBlock:
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) {
}
if (g->out_type == OutTypeLib) {
- int major = 1;
- int minor = 0;
- int patch = 0;
- Buf *out_lib_so = buf_sprintf("lib%s.so.%d.%d.%d", buf_ptr(g->out_name), major, minor, patch);
- Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->out_name), major);
+ 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);
args.append("-shared");
args.append("-soname");
args.append(buf_ptr(soname));
src/error.cpp
@@ -2,6 +2,7 @@
const char *err_str(int err) {
switch ((enum Error)err) {
+ case ErrorNone: return "(no error)";
case ErrorNoMem: return "out of memory";
case ErrorInvalidFormat: return "invalid format";
}
src/error.hpp
@@ -9,6 +9,7 @@
#define ERROR_HPP
enum Error {
+ ErrorNone,
ErrorNoMem,
ErrorInvalidFormat,
};
src/parser.cpp
@@ -1195,6 +1195,44 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool
zig_unreachable();
}
+/*
+RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon)
+*/
+static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, bool mandatory) {
+ assert(mandatory == false);
+
+ Token *export_kw = &pc->tokens->at(*token_index);
+ if (export_kw->id != TokenIdKeywordExport)
+ return nullptr;
+
+ Token *export_type = &pc->tokens->at(*token_index + 1);
+ if (export_type->id != TokenIdSymbol)
+ return nullptr;
+
+ *token_index += 2;
+
+ AstNode *node = ast_create_node(NodeTypeRootExportDecl, export_kw);
+ node->data.root_export_decl.directives = pc->directive_list;
+ pc->directive_list = nullptr;
+
+ ast_buf_from_token(pc, export_type, &node->data.root_export_decl.type);
+
+ Token *export_name = &pc->tokens->at(*token_index);
+ *token_index += 1;
+ ast_expect_token(pc, export_name, TokenIdStringLiteral);
+
+ parse_string_literal(pc, export_name, &node->data.root_export_decl.name);
+
+ Token *semicolon = &pc->tokens->at(*token_index);
+ *token_index += 1;
+ ast_expect_token(pc, semicolon, TokenIdSemicolon);
+
+ return node;
+}
+
+/*
+TopLevelDecl : FnDef | ExternBlock | RootExportDecl
+*/
static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
for (;;) {
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
pc->directive_list = allocate<ZigList<AstNode*>>(1);
ast_parse_directives(pc, token_index, pc->directive_list);
+ AstNode *root_export_decl_node = ast_parse_root_export_decl(pc, token_index, false);
+ if (root_export_decl_node) {
+ top_level_decls->append(root_export_decl_node);
+ continue;
+ }
+
AstNode *fn_decl_node = ast_parse_fn_def(pc, token_index, false);
if (fn_decl_node) {
top_level_decls->append(fn_decl_node);
@@ -1224,41 +1268,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
zig_unreachable();
}
-static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index) {
- Token *export_kw = &pc->tokens->at(*token_index);
- if (export_kw->id != TokenIdKeywordExport)
- return nullptr;
- *token_index += 1;
-
- AstNode *node = ast_create_node(NodeTypeRootExportDecl, export_kw);
-
- Token *export_type = &pc->tokens->at(*token_index);
- *token_index += 1;
- ast_expect_token(pc, export_type, TokenIdSymbol);
-
- ast_buf_from_token(pc, export_type, &node->data.root_export_decl.type);
-
- Token *export_name = &pc->tokens->at(*token_index);
- *token_index += 1;
- ast_expect_token(pc, export_name, TokenIdStringLiteral);
-
- parse_string_literal(pc, export_name, &node->data.root_export_decl.name);
-
- Token *semicolon = &pc->tokens->at(*token_index);
- *token_index += 1;
- ast_expect_token(pc, semicolon, TokenIdSemicolon);
-
- return node;
-}
-
/*
-Root : RootExportDecl many(TopLevelDecl) token(EOF)
+Root : many(TopLevelDecl) token(EOF)
*/
static AstNode *ast_parse_root(ParseContext *pc, int *token_index) {
AstNode *node = ast_create_node(NodeTypeRoot, &pc->tokens->at(*token_index));
- node->data.root.root_export_decl = ast_parse_root_export_decl(pc, token_index);
-
ast_parse_top_level_decls(pc, token_index, &node->data.root.top_level_decls);
if (*token_index != pc->tokens->length - 1) {
src/parser.hpp
@@ -38,7 +38,6 @@ enum NodeType {
};
struct AstNodeRoot {
- AstNode *root_export_decl;
ZigList<AstNode *> top_level_decls;
};
@@ -138,6 +137,7 @@ struct AstNodeDirective {
struct AstNodeRootExportDecl {
Buf type;
Buf name;
+ ZigList<AstNode *> *directives;
};
struct AstNodeCastExpr {
src/tokenizer.cpp
@@ -608,4 +608,3 @@ void print_tokens(Buf *buf, ZigList<Token> *tokens) {
fprintf(stderr, "\n");
}
}
-
README.md
@@ -42,9 +42,6 @@ make
## Roadmap
- * ability to specify version
- * cli ability to override library export locations
- * add test for building library
* variables and parameters
* Export .so library
* Multiple files
@@ -81,11 +78,11 @@ zig | C equivalent | Description
### Grammar
```
-Root : RootExportDecl many(TopLevelDecl) token(EOF)
+Root : many(TopLevelDecl) token(EOF)
-RootExportDecl : token(Export) token(Symbol) token(String) token(Semicolon)
+TopLevelDecl : FnDef | ExternBlock | RootExportDecl
-TopLevelDecl : FnDef | ExternBlock
+RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon)
ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnDecl) token(RBrace)