Commit cb4773ce29
Changed files (10)
doc
vim
syntax
test
doc/vim/syntax/zig.vim
@@ -10,7 +10,22 @@ endif
syn keyword zigKeyword fn return mut const extern unreachable export pub
syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void
+syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell
+syn region zigCommentLineDoc start="//\%(//\@!\|!\)" end="$" contains=zigTodo,@Spell
+syn region zigCommentBlock matchgroup=zigCommentBlock start="/\*\%(!\|\*[*/]\@!\)\@!" end="\*/" contains=zigTodo,zigCommentBlockNest,@Spell
+syn region zigCommentBlockDoc matchgroup=zigCommentBlockDoc start="/\*\%(!\|\*[*/]\@!\)" end="\*/" contains=zigTodo,zigCommentBlockDocNest,@Spell
+syn region zigCommentBlockNest matchgroup=zigCommentBlock start="/\*" end="\*/" contains=zigTodo,zigCommentBlockNest,@Spell contained transparent
+syn region zigCommentBlockDocNest matchgroup=zigCommentBlockDoc start="/\*" end="\*/" contains=zigTodo,zigCommentBlockDocNest,@Spell contained transparent
+
+syn keyword zigTodo contained TODO XXX
+
let b:current_syntax = "zig"
hi def link zigKeyword Keyword
hi def link zigType Type
+hi def link zigCommentLine Comment
+hi def link zigCommentLineDoc SpecialComment
+hi def link zigCommentBlock zigCommentLine
+hi def link zigCommentBlockDoc zigCommentLineDoc
+hi def link zigTodo Todo
+
example/hello.zig
@@ -1,3 +1,5 @@
+export executable "hello";
+
#link("c")
extern {
fn puts(s: *mut u8) -> i32;
example/math.zig
@@ -0,0 +1,6 @@
+export library "math";
+
+export fn add(a: i32, b: i32) -> i32 {
+ return a + b;
+}
+
src/codegen.cpp
@@ -75,6 +75,8 @@ struct CodeGen {
ZigList<llvm::DIScope *> block_scopes;
llvm::DIFile *di_file;
ZigList<FnTableEntry *> fn_defs;
+ Buf *out_name;
+ OutType out_type;
};
struct TypeNode {
@@ -103,6 +105,8 @@ CodeGen *create_codegen(AstNode *root, Buf *in_full_path) {
g->is_static = false;
g->build_type = CodeGenBuildTypeDebug;
g->strip_debug_symbols = false;
+ g->out_name = nullptr;
+ g->out_type = OutTypeUnknown;
os_path_split(in_full_path, &g->in_dir, &g->in_file);
return g;
@@ -120,6 +124,14 @@ void codegen_set_strip(CodeGen *g, bool strip) {
g->strip_debug_symbols = strip;
}
+void codegen_set_out_type(CodeGen *g, OutType out_type) {
+ g->out_type = out_type;
+}
+
+void codegen_set_out_name(CodeGen *g, Buf *out_name) {
+ g->out_name = out_name;
+}
+
static void add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
g->errors.add_one();
ErrorMsg *last_msg = &g->errors.last();
@@ -294,6 +306,7 @@ static void find_declarations(CodeGen *g, AstNode *node) {
case NodeTypeBlock:
case NodeTypeExpression:
case NodeTypeFnCall:
+ case NodeTypeRootExportDecl:
zig_unreachable();
}
}
@@ -355,15 +368,50 @@ static void check_fn_def_control_flow(CodeGen *g, AstNode *node) {
static void analyze_node(CodeGen *g, AstNode *node) {
switch (node->type) {
case NodeTypeRoot:
- // 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);
- find_declarations(g, child);
- }
- for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
- AstNode *child = node->data.root.top_level_decls.at(i);
- analyze_node(g, child);
+ {
+ 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);
+ find_declarations(g, child);
+ }
+ for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
+ AstNode *child = node->data.root.top_level_decls.at(i);
+ analyze_node(g, child);
+ }
+ break;
}
+ case NodeTypeRootExportDecl:
+ // handled in parent
break;
case NodeTypeExternBlock:
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)
case NodeTypeFnCall:
case NodeTypeExternBlock:
case NodeTypeDirective:
+ case NodeTypeRootExportDecl:
zig_unreachable();
}
}
@@ -929,6 +978,15 @@ static Buf *get_dynamic_linker(CodeGen *g) {
}
}
+/*
+
+# static link into libfoo.a
+ar cq libfoo.a foo1.o foo2.o
+
+# dynamic link into libfoo.so
+gcc -fPIC -g -Werror -pedantic -shared -Wl,-soname,libsoundio.so.1 -o libsoundio.so.1.0.3 foo1.o foo2.o -ljack -lpulse -lasound -lpthread
+
+*/
void code_gen_link(CodeGen *g, const char *out_file) {
LLVMPassRegistryRef registry = LLVMGetGlobalPassRegistry();
LLVMInitializeCore(registry);
@@ -937,6 +995,10 @@ void code_gen_link(CodeGen *g, const char *out_file) {
LLVMZigInitializeLowerIntrinsicsPass(registry);
LLVMZigInitializeUnreachableBlockElimPass(registry);
+ if (!out_file) {
+ out_file = buf_ptr(g->out_name);
+ }
+
Buf out_file_o = BUF_INIT;
buf_init_from_str(&out_file_o, out_file);
buf_append_str(&out_file_o, ".o");
src/codegen.hpp
@@ -12,6 +12,14 @@
struct CodeGen;
+enum OutType {
+ OutTypeUnknown,
+ OutTypeExe,
+ OutTypeLib,
+ OutTypeObj,
+};
+
+
struct ErrorMsg {
int line_start;
int column_start;
@@ -30,6 +38,8 @@ enum CodeGenBuildType {
void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type);
void codegen_set_is_static(CodeGen *codegen, bool is_static);
void codegen_set_strip(CodeGen *codegen, bool strip);
+void codegen_set_out_type(CodeGen *codegen, OutType out_type);
+void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
void semantic_analyze(CodeGen *g);
src/main.cpp
@@ -28,18 +28,24 @@
static int usage(const char *arg0) {
fprintf(stderr, "Usage: %s [command] [options] target\n"
"Commands:\n"
- " build create an executable from target\n"
- "Options:\n"
- " --output output file\n"
- " --version print version number and exit\n"
- " -Ipath add path to header include path\n"
- " --release build with optimizations on\n"
- " --strip exclude debug symbols\n"
- " --static build a static executable\n"
+ " build create executable, object, or library from target\n"
+ " version print version number and exit\n"
+ "Optional Options:\n"
+ " --release build with optimizations on and debug protection off\n"
+ " --static output will be statically linked\n"
+ " --strip exclude debug symbols\n"
+ " --export [exe|lib|obj] override output type\n"
+ " --name [name] override output name\n"
+ " --output [file] override destination path\n"
, arg0);
return EXIT_FAILURE;
}
+static int version(void) {
+ printf("%s\n", ZIG_VERSION_STRING);
+ return EXIT_SUCCESS;
+}
+
static Buf *fetch_file(FILE *f) {
int fd = fileno(f);
struct stat st;
@@ -58,12 +64,12 @@ static Buf *fetch_file(FILE *f) {
return buf;
}
-static int build(const char *arg0, const char *in_file, const char *out_file,
- ZigList<char *> *include_paths, bool release, bool strip, bool is_static)
+static int build(const char *arg0, const char *in_file, const char *out_file, bool release,
+ bool strip, bool is_static, OutType out_type, char *out_name)
{
static char cur_dir[1024];
- if (!in_file || !out_file)
+ if (!in_file)
return usage(arg0);
FILE *in_f;
@@ -100,6 +106,10 @@ static int build(const char *arg0, const char *in_file, const char *out_file,
codegen_set_build_type(codegen, release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug);
codegen_set_strip(codegen, strip);
codegen_set_is_static(codegen, is_static);
+ if (out_type != OutTypeUnknown)
+ codegen_set_out_type(codegen, out_type);
+ if (out_name)
+ codegen_set_out_name(codegen, buf_create_from_str(out_name));
semantic_analyze(codegen);
ZigList<ErrorMsg> *errors = codegen_error_messages(codegen);
if (errors->length == 0) {
@@ -135,25 +145,25 @@ static int build(const char *arg0, const char *in_file, const char *out_file,
enum Cmd {
CmdNone,
CmdBuild,
+ CmdVersion,
};
int main(int argc, char **argv) {
char *arg0 = argv[0];
char *in_file = NULL;
char *out_file = NULL;
- ZigList<char *> include_paths = {0};
bool release = false;
bool strip = false;
bool is_static = false;
+ OutType out_type = OutTypeUnknown;
+ char *out_name = NULL;
+
Cmd cmd = CmdNone;
for (int i = 1; i < argc; i += 1) {
char *arg = argv[i];
if (arg[0] == '-' && arg[1] == '-') {
- if (strcmp(arg, "--version") == 0) {
- printf("%s\n", ZIG_VERSION_STRING);
- return EXIT_SUCCESS;
- } else if (strcmp(arg, "--release") == 0) {
+ if (strcmp(arg, "--release") == 0) {
release = true;
} else if (strcmp(arg, "--strip") == 0) {
strip = true;
@@ -165,15 +175,27 @@ int main(int argc, char **argv) {
i += 1;
if (strcmp(arg, "--output") == 0) {
out_file = argv[i];
+ } else if (strcmp(arg, "--export") == 0) {
+ if (strcmp(argv[i], "exe") == 0) {
+ out_type = OutTypeExe;
+ } else if (strcmp(argv[i], "lib") == 0) {
+ out_type = OutTypeLib;
+ } else if (strcmp(argv[i], "obj") == 0) {
+ out_type = OutTypeObj;
+ } else {
+ return usage(arg0);
+ }
+ } else if (strcmp(arg, "--name") == 0) {
+ out_name = argv[i];
} else {
return usage(arg0);
}
}
- } else if (arg[0] == '-' && arg[1] == 'I') {
- include_paths.append(arg + 2);
} else if (cmd == CmdNone) {
if (strcmp(arg, "build") == 0) {
cmd = CmdBuild;
+ } else if (strcmp(arg, "version") == 0) {
+ cmd = CmdVersion;
} else {
fprintf(stderr, "Unrecognized command: %s\n", arg);
return usage(arg0);
@@ -189,6 +211,8 @@ int main(int argc, char **argv) {
return usage(arg0);
}
break;
+ case CmdVersion:
+ return usage(arg0);
}
}
}
@@ -197,9 +221,10 @@ int main(int argc, char **argv) {
case CmdNone:
return usage(arg0);
case CmdBuild:
- return build(arg0, in_file, out_file, &include_paths, release, strip, is_static);
+ return build(arg0, in_file, out_file, release, strip, is_static, out_type, out_name);
+ case CmdVersion:
+ return version();
}
zig_unreachable();
}
-
src/parser.cpp
@@ -29,6 +29,8 @@ const char *node_type_str(NodeType node_type) {
switch (node_type) {
case NodeTypeRoot:
return "Root";
+ case NodeTypeRootExportDecl:
+ return "RootExportDecl";
case NodeTypeFnDef:
return "FnDef";
case NodeTypeFnDecl:
@@ -68,6 +70,11 @@ void ast_print(AstNode *node, int indent) {
ast_print(child, indent + 2);
}
break;
+ case NodeTypeRootExportDecl:
+ fprintf(stderr, "%s %s '%s'\n", node_type_str(node->type),
+ buf_ptr(&node->data.root_export_decl.type),
+ buf_ptr(&node->data.root_export_decl.name));
+ break;
case NodeTypeFnDef:
{
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
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)
+ */
AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) {
ParseContext pc = {0};
pc.buf = buf;
@@ -721,6 +758,9 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens) {
pc.tokens = tokens;
int token_index = 0;
+
+ pc.root->data.root.root_export_decl = ast_parse_root_export_decl(&pc, &token_index);
+
ast_parse_top_level_decls(&pc, &token_index, &pc.root->data.root.top_level_decls);
if (token_index != tokens->length - 1) {
src/parser.hpp
@@ -17,6 +17,7 @@ struct CodeGenNode;
enum NodeType {
NodeTypeRoot,
+ NodeTypeRootExportDecl,
NodeTypeFnProto,
NodeTypeFnDef,
NodeTypeFnDecl,
@@ -31,6 +32,7 @@ enum NodeType {
};
struct AstNodeRoot {
+ AstNode *root_export_decl;
ZigList<AstNode *> top_level_decls;
};
@@ -113,6 +115,11 @@ struct AstNodeDirective {
Buf param;
};
+struct AstNodeRootExportDecl {
+ Buf type;
+ Buf name;
+};
+
struct AstNode {
enum NodeType type;
AstNode *parent;
@@ -121,6 +128,7 @@ struct AstNode {
CodeGenNode *codegen_node;
union {
AstNodeRoot root;
+ AstNodeRootExportDecl root_export_decl;
AstNodeFnDef fn_def;
AstNodeFnDecl fn_decl;
AstNodeFnProto fn_proto;
test/run_tests.cpp
@@ -39,6 +39,10 @@ static void add_simple_case(const char *case_name, const char *source, const cha
test_case->compiler_args.append("build");
test_case->compiler_args.append(tmp_source_path);
+ test_case->compiler_args.append("--export");
+ test_case->compiler_args.append("exe");
+ test_case->compiler_args.append("--name");
+ test_case->compiler_args.append("test");
test_case->compiler_args.append("--output");
test_case->compiler_args.append(tmp_exe_path);
test_case->compiler_args.append("--release");
README.md
@@ -32,7 +32,9 @@ readable, safe, optimal, and concise code to solve any computing problem.
## Roadmap
- * Simple .so library
+ * Math expression
+ * Export .so library
+ * Export .o file
* Multiple files
* inline assembly and syscalls
* running code at compile time
@@ -66,7 +68,9 @@ zig | C equivalent | Description
### Grammar
```
-Root : many(TopLevelDecl) token(EOF)
+Root : RootExportDecl many(TopLevelDecl) token(EOF)
+
+RootExportDecl : token(Export) token(Symbol) token(String) token(Semicolon)
TopLevelDecl : FnDef | ExternBlock