mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
add directive to specify root export version
This commit is contained in:
parent
ac0c5a3707
commit
8f0f318c39
@ -42,9 +42,6 @@ make
|
|||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
* ability to specify version
|
|
||||||
* cli ability to override library export locations
|
|
||||||
* add test for building library
|
|
||||||
* variables and parameters
|
* variables and parameters
|
||||||
* Export .so library
|
* Export .so library
|
||||||
* Multiple files
|
* Multiple files
|
||||||
@ -81,11 +78,11 @@ zig | C equivalent | Description
|
|||||||
### Grammar
|
### 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)
|
ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnDecl) token(RBrace)
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
#version("2.0.0")
|
||||||
export library "mathtest";
|
export library "mathtest";
|
||||||
|
|
||||||
export fn add(a: i32, b: i32) -> i32 {
|
export fn add(a: i32, b: i32) -> i32 {
|
||||||
|
|||||||
113
src/codegen.cpp
113
src/codegen.cpp
@ -10,6 +10,7 @@
|
|||||||
#include "zig_llvm.hpp"
|
#include "zig_llvm.hpp"
|
||||||
#include "os.hpp"
|
#include "os.hpp"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "error.hpp"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
@ -79,6 +80,10 @@ struct CodeGen {
|
|||||||
OutType out_type;
|
OutType out_type;
|
||||||
FnTableEntry *cur_fn;
|
FnTableEntry *cur_fn;
|
||||||
bool c_stdint_used;
|
bool c_stdint_used;
|
||||||
|
AstNode *root_export_decl;
|
||||||
|
int version_major;
|
||||||
|
int version_minor;
|
||||||
|
int version_patch;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TypeNode {
|
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;
|
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 find_declarations(CodeGen *g, AstNode *node);
|
||||||
|
|
||||||
static void resolve_type_and_recurse(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:
|
case NodeTypeDirective:
|
||||||
// we handled directives in the parent function
|
// we handled directives in the parent function
|
||||||
break;
|
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 NodeTypeFnDecl:
|
||||||
case NodeTypeReturnExpr:
|
case NodeTypeReturnExpr:
|
||||||
case NodeTypeRoot:
|
case NodeTypeRoot:
|
||||||
case NodeTypeBlock:
|
case NodeTypeBlock:
|
||||||
case NodeTypeBinOpExpr:
|
case NodeTypeBinOpExpr:
|
||||||
case NodeTypeFnCallExpr:
|
case NodeTypeFnCallExpr:
|
||||||
case NodeTypeRootExportDecl:
|
|
||||||
case NodeTypeNumberLiteral:
|
case NodeTypeNumberLiteral:
|
||||||
case NodeTypeStringLiteral:
|
case NodeTypeStringLiteral:
|
||||||
case NodeTypeUnreachable:
|
case NodeTypeUnreachable:
|
||||||
@ -385,36 +426,6 @@ static void analyze_node(CodeGen *g, AstNode *node) {
|
|||||||
switch (node->type) {
|
switch (node->type) {
|
||||||
case NodeTypeRoot:
|
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
|
// 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) {
|
for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
|
||||||
AstNode *child = node->data.root.top_level_decls.at(i);
|
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);
|
AstNode *child = node->data.root.top_level_decls.at(i);
|
||||||
analyze_node(g, child);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case NodeTypeRootExportDecl:
|
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;
|
break;
|
||||||
case NodeTypeExternBlock:
|
case NodeTypeExternBlock:
|
||||||
for (int fn_decl_i = 0; fn_decl_i < node->data.extern_block.fn_decls.length; fn_decl_i += 1) {
|
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) {
|
if (g->out_type == OutTypeLib) {
|
||||||
int major = 1;
|
Buf *out_lib_so = buf_sprintf("lib%s.so.%d.%d.%d",
|
||||||
int minor = 0;
|
buf_ptr(g->out_name), g->version_major, g->version_minor, g->version_patch);
|
||||||
int patch = 0;
|
Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->out_name), g->version_major);
|
||||||
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);
|
|
||||||
args.append("-shared");
|
args.append("-shared");
|
||||||
args.append("-soname");
|
args.append("-soname");
|
||||||
args.append(buf_ptr(soname));
|
args.append(buf_ptr(soname));
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const char *err_str(int err) {
|
const char *err_str(int err) {
|
||||||
switch ((enum Error)err) {
|
switch ((enum Error)err) {
|
||||||
|
case ErrorNone: return "(no error)";
|
||||||
case ErrorNoMem: return "out of memory";
|
case ErrorNoMem: return "out of memory";
|
||||||
case ErrorInvalidFormat: return "invalid format";
|
case ErrorInvalidFormat: return "invalid format";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#define ERROR_HPP
|
#define ERROR_HPP
|
||||||
|
|
||||||
enum Error {
|
enum Error {
|
||||||
|
ErrorNone,
|
||||||
ErrorNoMem,
|
ErrorNoMem,
|
||||||
ErrorInvalidFormat,
|
ErrorInvalidFormat,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1195,6 +1195,44 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool
|
|||||||
zig_unreachable();
|
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) {
|
static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
Token *directive_token = &pc->tokens->at(*token_index);
|
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);
|
pc->directive_list = allocate<ZigList<AstNode*>>(1);
|
||||||
ast_parse_directives(pc, token_index, pc->directive_list);
|
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);
|
AstNode *fn_decl_node = ast_parse_fn_def(pc, token_index, false);
|
||||||
if (fn_decl_node) {
|
if (fn_decl_node) {
|
||||||
top_level_decls->append(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();
|
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) {
|
static AstNode *ast_parse_root(ParseContext *pc, int *token_index) {
|
||||||
AstNode *node = ast_create_node(NodeTypeRoot, &pc->tokens->at(*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);
|
ast_parse_top_level_decls(pc, token_index, &node->data.root.top_level_decls);
|
||||||
|
|
||||||
if (*token_index != pc->tokens->length - 1) {
|
if (*token_index != pc->tokens->length - 1) {
|
||||||
|
|||||||
@ -38,7 +38,6 @@ enum NodeType {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeRoot {
|
struct AstNodeRoot {
|
||||||
AstNode *root_export_decl;
|
|
||||||
ZigList<AstNode *> top_level_decls;
|
ZigList<AstNode *> top_level_decls;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -138,6 +137,7 @@ struct AstNodeDirective {
|
|||||||
struct AstNodeRootExportDecl {
|
struct AstNodeRootExportDecl {
|
||||||
Buf type;
|
Buf type;
|
||||||
Buf name;
|
Buf name;
|
||||||
|
ZigList<AstNode *> *directives;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AstNodeCastExpr {
|
struct AstNodeCastExpr {
|
||||||
|
|||||||
@ -608,4 +608,3 @@ void print_tokens(Buf *buf, ZigList<Token> *tokens) {
|
|||||||
fprintf(stderr, "\n");
|
fprintf(stderr, "\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user