authorgravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2015-11-30 22:12:21-07:00
committergravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2015-11-30 22:12:21-07:00
log00f4c05784c05552e1e379b98c09161c936cfb31
tree5b2234cae585c5ac3a2cb23503908b0a6e2a27e3
parentabbc3957019c3a12dacd54869ff18b91c3f07699
parent55b8472374eede496b59396dbe253b05b16063e1

merge conflicts


26 files changed, 562 insertions(+), 306 deletions(-)

CMakeLists.txt+4-4
......@@ -22,16 +22,16 @@ include_directories(
2222)
2323
2424set(ZIG_SOURCES
25 "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp"
26 "${CMAKE_SOURCE_DIR}/src/parser.cpp"
2527 "${CMAKE_SOURCE_DIR}/src/analyze.cpp"
28 "${CMAKE_SOURCE_DIR}/src/codegen.cpp"
2629 "${CMAKE_SOURCE_DIR}/src/buffer.cpp"
2730 "${CMAKE_SOURCE_DIR}/src/error.cpp"
2831 "${CMAKE_SOURCE_DIR}/src/main.cpp"
29 "${CMAKE_SOURCE_DIR}/src/parser.cpp"
30 "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp"
32 "${CMAKE_SOURCE_DIR}/src/os.cpp"
3133 "${CMAKE_SOURCE_DIR}/src/util.cpp"
32 "${CMAKE_SOURCE_DIR}/src/codegen.cpp"
3334 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
34 "${CMAKE_SOURCE_DIR}/src/os.cpp"
3535)
3636
3737set(TEST_SOURCES
README.md+3-1
......@@ -79,7 +79,9 @@ zig | C equivalent | Description
7979```
8080Root : many(TopLevelDecl) token(EOF)
8181
82TopLevelDecl : FnDef | ExternBlock | RootExportDecl
82TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use
83
84Use : many(Directive) token(Use) token(String) token(Semicolon)
8385
8486RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon)
8587
doc/vim/syntax/zig.vim+15-2
......@@ -7,7 +7,7 @@ if exists("b:current_syntax")
77 finish
88endif
99
10syn keyword zigKeyword fn return mut const extern unreachable export pub as
10syn keyword zigKeyword fn return mut const extern unreachable export pub as use
1111syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void
1212
1313syn region zigCommentLine start="//" end="$" contains=zigTodo,@Spell
......@@ -19,6 +19,15 @@ syn region zigCommentBlockDocNest matchgroup=zigCommentBlockDoc start="/\*" end=
1919
2020syn keyword zigTodo contained TODO XXX
2121
22syn match zigEscapeError display contained /\\./
23syn match zigEscape display contained /\\\([nrt0\\'"]\|x\x\{2}\)/
24syn match zigEscapeUnicode display contained /\\\(u\x\{4}\|U\x\{8}\)/
25syn match zigEscapeUnicode display contained /\\u{\x\{1,6}}/
26syn match zigStringContinuation display contained /\\\n\s*/
27syn region zigString start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=zigEscape,zigEscapeError,zigStringContinuation
28syn region zigString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=zigEscape,zigEscapeUnicode,zigEscapeError,zigStringContinuation,@Spell
29syn region zigString start='b\?r\z(#*\)"' end='"\z1' contains=@Spell
30
2231let b:current_syntax = "zig"
2332
2433hi def link zigKeyword Keyword
......@@ -28,4 +37,8 @@ hi def link zigCommentLineDoc SpecialComment
2837hi def link zigCommentBlock zigCommentLine
2938hi def link zigCommentBlockDoc zigCommentLineDoc
3039hi def link zigTodo Todo
31
40hi def link zigStringContinuation Special
41hi def link zigString String
42hi def link zigEscape Special
43hi def link zigEscapeUnicode zigEscape
44hi def link zigEscapeError Error
example/hello.zig deleted-12
......@@ -1,12 +0,0 @@
1export executable "hello";
2
3#link("c")
4extern {
5 fn puts(s: *mut u8) -> i32;
6 fn exit(code: i32) -> unreachable;
7}
8
9export fn _start() -> unreachable {
10 puts("Hello, world!");
11 exit(0);
12}
example/hello_world/hello.zig created+12
......@@ -0,0 +1,12 @@
1export executable "hello";
2
3#link("c")
4extern {
5 fn puts(s: *mut u8) -> i32;
6 fn exit(code: i32) -> unreachable;
7}
8
9export fn _start() -> unreachable {
10 puts("Hello, world!");
11 exit(0);
12}
example/mathtest.zig deleted-6
......@@ -1,6 +0,0 @@
1#version("2.0.0")
2export library "mathtest";
3
4export fn add(a: i32, b: i32) -> i32 {
5 return a + b;
6}
example/multiple_files/foo.zig created+5
......@@ -0,0 +1,5 @@
1use "libc.zig";
2
3fn print_text() {
4 puts("it works!");
5}
example/multiple_files/libc.zig created+5
......@@ -0,0 +1,5 @@
1#link("c")
2extern {
3 fn puts(s: *mut u8) -> i32;
4 fn exit(code: i32) -> unreachable;
5}
example/multiple_files/main.zig created+9
......@@ -0,0 +1,9 @@
1export executable "test";
2
3use "libc.zig";
4use "foo.zig";
5
6fn _start() -> unreachable {
7 print_text();
8 exit(0);
9}
example/shared_library/mathtest.zig created+6
......@@ -0,0 +1,6 @@
1#version("2.0.0")
2export library "mathtest";
3
4export fn add(a: i32, b: i32) -> i32 {
5 return a + b;
6}
example/shared_library/test.c created+7
......@@ -0,0 +1,7 @@
1#include "mathtest.h"
2#include <stdio.h>
3
4int main(int argc, char **argv) {
5 printf("%d\n", add(42, 1137));
6 return 0;
7}
src/analyze.cpp+84-93
......@@ -119,7 +119,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node) {
119119 resolve_type(g, node->data.fn_proto.return_type);
120120}
121121
122static void preview_function_declarations(CodeGen *g, AstNode *node) {
122static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, AstNode *node) {
123123 switch (node->type) {
124124 case NodeTypeExternBlock:
125125 for (int i = 0; i < node->data.extern_block.directives->length; i += 1) {
......@@ -145,6 +145,7 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {
145145 fn_table_entry->proto_node = fn_proto;
146146 fn_table_entry->is_extern = true;
147147 fn_table_entry->calling_convention = LLVMCCallConv;
148 fn_table_entry->import_entry = import;
148149 g->fn_table.put(name, fn_table_entry);
149150 }
150151 break;
......@@ -162,6 +163,7 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {
162163 node->codegen_node->data.fn_def_node.skip = true;
163164 } else {
164165 FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
166 fn_table_entry->import_entry = import;
165167 fn_table_entry->proto_node = proto_node;
166168 fn_table_entry->fn_def_node = node;
167169 fn_table_entry->internal_linkage = proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport;
......@@ -196,8 +198,8 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {
196198 } else {
197199 g->root_export_decl = node;
198200
199 if (!g->out_name)
200 g->out_name = &node->data.root_export_decl.name;
201 if (!g->root_out_name)
202 g->root_out_name = &node->data.root_export_decl.name;
201203
202204 Buf *out_type = &node->data.root_export_decl.type;
203205 OutType export_out_type;
......@@ -215,6 +217,9 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {
215217 g->out_type = export_out_type;
216218 }
217219 break;
220 case NodeTypeUse:
221 zig_panic("TODO use");
222 break;
218223 case NodeTypeDirective:
219224 case NodeTypeParamDecl:
220225 case NodeTypeFnProto:
......@@ -379,6 +384,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, BlockContext *context, Ty
379384 case NodeTypeRootExportDecl:
380385 case NodeTypeExternBlock:
381386 case NodeTypeFnDef:
387 case NodeTypeUse:
382388 zig_unreachable();
383389 }
384390 zig_unreachable();
......@@ -437,6 +443,75 @@ static void check_fn_def_control_flow(CodeGen *g, AstNode *node) {
437443 }
438444}
439445
446static void analyze_expression(CodeGen *g, AstNode *node) {
447 switch (node->type) {
448 case NodeTypeBlock:
449 for (int i = 0; i < node->data.block.statements.length; i += 1) {
450 AstNode *child = node->data.block.statements.at(i);
451 analyze_expression(g, child);
452 }
453 break;
454 case NodeTypeReturnExpr:
455 if (node->data.return_expr.expr) {
456 analyze_expression(g, node->data.return_expr.expr);
457 }
458 break;
459 case NodeTypeBinOpExpr:
460 analyze_expression(g, node->data.bin_op_expr.op1);
461 analyze_expression(g, node->data.bin_op_expr.op2);
462 break;
463 case NodeTypeFnCallExpr:
464 {
465 Buf *name = hack_get_fn_call_name(g, node->data.fn_call_expr.fn_ref_expr);
466
467 auto entry = g->fn_table.maybe_get(name);
468 if (!entry) {
469 add_node_error(g, node,
470 buf_sprintf("undefined function: '%s'", buf_ptr(name)));
471 } else {
472 FnTableEntry *fn_table_entry = entry->value;
473 assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
474 int expected_param_count = fn_table_entry->proto_node->data.fn_proto.params.length;
475 int actual_param_count = node->data.fn_call_expr.params.length;
476 if (expected_param_count != actual_param_count) {
477 add_node_error(g, node,
478 buf_sprintf("wrong number of arguments. Expected %d, got %d.",
479 expected_param_count, actual_param_count));
480 }
481 }
482
483 for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
484 AstNode *child = node->data.fn_call_expr.params.at(i);
485 analyze_expression(g, child);
486 }
487 break;
488 }
489 case NodeTypeCastExpr:
490 zig_panic("TODO");
491 break;
492 case NodeTypePrefixOpExpr:
493 zig_panic("TODO");
494 break;
495 case NodeTypeNumberLiteral:
496 case NodeTypeStringLiteral:
497 case NodeTypeUnreachable:
498 case NodeTypeSymbol:
499 // nothing to do
500 break;
501 case NodeTypeDirective:
502 case NodeTypeFnDecl:
503 case NodeTypeFnProto:
504 case NodeTypeParamDecl:
505 case NodeTypeType:
506 case NodeTypeRoot:
507 case NodeTypeRootExportDecl:
508 case NodeTypeExternBlock:
509 case NodeTypeFnDef:
510 case NodeTypeUse:
511 zig_unreachable();
512 }
513}
514
440515static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
441516 switch (node->type) {
442517 case NodeTypeFnDef:
......@@ -470,9 +545,9 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
470545
471546 case NodeTypeRootExportDecl:
472547 case NodeTypeExternBlock:
548 case NodeTypeUse:
473549 // already looked at these in the preview pass
474550 break;
475
476551 case NodeTypeDirective:
477552 case NodeTypeParamDecl:
478553 case NodeTypeFnProto:
......@@ -493,13 +568,13 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
493568 }
494569}
495570
496static void analyze_root(CodeGen *g, AstNode *node) {
571static void analyze_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
497572 assert(node->type == NodeTypeRoot);
498573
499574 // find function declarations
500575 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
501576 AstNode *child = node->data.root.top_level_decls.at(i);
502 preview_function_declarations(g, child);
577 preview_function_declarations(g, import, child);
503578 }
504579
505580 for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
......@@ -507,7 +582,7 @@ static void analyze_root(CodeGen *g, AstNode *node) {
507582 analyze_top_level_declaration(g, child);
508583 }
509584
510 if (!g->out_name) {
585 if (!g->root_out_name) {
511586 add_node_error(g, node,
512587 buf_sprintf("missing export declaration and output name not provided"));
513588 } else if (g->out_type == OutTypeUnknown) {
......@@ -516,91 +591,7 @@ static void analyze_root(CodeGen *g, AstNode *node) {
516591 }
517592}
518593
519static void define_primitive_types(CodeGen *g) {
520 {
521 // if this type is anywhere in the AST, we should never hit codegen.
522 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
523 buf_init_from_str(&entry->name, "(invalid)");
524 g->builtin_types.entry_invalid = entry;
525 }
526 {
527 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
528 entry->type_ref = LLVMInt8Type();
529 buf_init_from_str(&entry->name, "u8");
530 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 8, 8,
531 LLVMZigEncoding_DW_ATE_unsigned());
532 g->type_table.put(&entry->name, entry);
533 g->builtin_types.entry_u8 = entry;
534 }
535 {
536 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
537 entry->type_ref = LLVMInt32Type();
538 buf_init_from_str(&entry->name, "i32");
539 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 32, 32,
540 LLVMZigEncoding_DW_ATE_signed());
541 g->type_table.put(&entry->name, entry);
542 g->builtin_types.entry_i32 = entry;
543 }
544 {
545 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
546 entry->type_ref = LLVMVoidType();
547 buf_init_from_str(&entry->name, "void");
548 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 0, 0,
549 LLVMZigEncoding_DW_ATE_unsigned());
550 g->type_table.put(&entry->name, entry);
551 g->builtin_types.entry_void = entry;
552 }
553 {
554 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
555 entry->type_ref = LLVMVoidType();
556 buf_init_from_str(&entry->name, "unreachable");
557 entry->di_type = g->builtin_types.entry_void->di_type;
558 g->type_table.put(&entry->name, entry);
559 g->builtin_types.entry_unreachable = entry;
560 }
561}
562
563
564void semantic_analyze(CodeGen *g) {
565 LLVMInitializeAllTargets();
566 LLVMInitializeAllTargetMCs();
567 LLVMInitializeAllAsmPrinters();
568 LLVMInitializeAllAsmParsers();
569 LLVMInitializeNativeTarget();
570
571 g->is_native_target = true;
572 char *native_triple = LLVMGetDefaultTargetTriple();
573
574 LLVMTargetRef target_ref;
575 char *err_msg = nullptr;
576 if (LLVMGetTargetFromTriple(native_triple, &target_ref, &err_msg)) {
577 zig_panic("unable to get target from triple: %s", err_msg);
578 }
579
580 char *native_cpu = LLVMZigGetHostCPUName();
581 char *native_features = LLVMZigGetNativeFeatures();
582
583 LLVMCodeGenOptLevel opt_level = (g->build_type == CodeGenBuildTypeDebug) ?
584 LLVMCodeGenLevelNone : LLVMCodeGenLevelAggressive;
585
586 LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC;
587
588 g->target_machine = LLVMCreateTargetMachine(target_ref, native_triple,
589 native_cpu, native_features, opt_level, reloc_mode, LLVMCodeModelDefault);
590
591 g->target_data_ref = LLVMGetTargetMachineData(g->target_machine);
592
593
594 g->module = LLVMModuleCreateWithName("ZigModule");
595
596 g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref);
597
598 g->builder = LLVMCreateBuilder();
599 g->dbuilder = LLVMZigCreateDIBuilder(g->module, true);
600
601
602 define_primitive_types(g);
603
604 analyze_root(g, g->root);
594void semantic_analyze(CodeGen *g, ImportTableEntry *import_table_entry) {
595 analyze_root(g, import_table_entry, import_table_entry->root);
605596}
606597
src/analyze.hpp+2-1
......@@ -9,7 +9,8 @@
99#define ZIG_ANALYZE_HPP
1010
1111struct CodeGen;
12struct ImportTableEntry;
1213
13void semantic_analyze(CodeGen *g);
14void semantic_analyze(CodeGen *g, ImportTableEntry *entry);
1415
1516#endif
src/codegen.cpp+216-42
......@@ -11,26 +11,21 @@
1111#include "os.hpp"
1212#include "config.h"
1313#include "error.hpp"
14
1514#include "semantic_info.hpp"
15#include "analyze.hpp"
1616
1717#include <stdio.h>
1818#include <errno.h>
1919
20CodeGen *create_codegen(AstNode *root, Buf *in_full_path) {
20CodeGen *codegen_create(Buf *root_source_dir) {
2121 CodeGen *g = allocate<CodeGen>(1);
22 g->root = root;
2322 g->fn_table.init(32);
2423 g->str_table.init(32);
2524 g->type_table.init(32);
2625 g->link_table.init(32);
27 g->is_static = false;
26 g->import_table.init(32);
2827 g->build_type = CodeGenBuildTypeDebug;
29 g->strip_debug_symbols = false;
30 g->out_name = nullptr;
31 g->out_type = OutTypeUnknown;
32
33 os_path_split(in_full_path, &g->in_dir, &g->in_file);
28 g->root_source_dir = root_source_dir;
3429 return g;
3530}
3631
......@@ -42,6 +37,10 @@ void codegen_set_is_static(CodeGen *g, bool is_static) {
4237 g->is_static = is_static;
4338}
4439
40void codegen_set_verbose(CodeGen *g, bool verbose) {
41 g->verbose = verbose;
42}
43
4544void codegen_set_strip(CodeGen *g, bool strip) {
4645 g->strip_debug_symbols = strip;
4746}
......@@ -51,7 +50,7 @@ void codegen_set_out_type(CodeGen *g, OutType out_type) {
5150}
5251
5352void codegen_set_out_name(CodeGen *g, Buf *out_name) {
54 g->out_name = out_name;
53 g->root_out_name = out_name;
5554}
5655
5756static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);
......@@ -425,16 +424,17 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
425424 case NodeTypeBlock:
426425 case NodeTypeExternBlock:
427426 case NodeTypeDirective:
427 case NodeTypeUse:
428428 zig_unreachable();
429429 }
430430 zig_unreachable();
431431}
432432
433static void gen_block(CodeGen *g, AstNode *block_node, bool add_implicit_return) {
433static void gen_block(CodeGen *g, ImportTableEntry *import, AstNode *block_node, bool add_implicit_return) {
434434 assert(block_node->type == NodeTypeBlock);
435435
436436 LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder, g->block_scopes.last(),
437 g->di_file, block_node->line + 1, block_node->column + 1);
437 import->di_file, block_node->line + 1, block_node->column + 1);
438438 g->block_scopes.append(LLVMZigLexicalBlockToScope(di_block));
439439
440440 add_debug_source_node(g, block_node);
......@@ -466,22 +466,11 @@ static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnPro
466466 return LLVMZigCreateSubroutineType(g->dbuilder, di_file, types, types_len, 0);
467467}
468468
469void code_gen(CodeGen *g) {
469static void do_code_gen(CodeGen *g) {
470470 assert(!g->errors.length);
471471
472 Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING);
473 bool is_optimized = g->build_type == CodeGenBuildTypeRelease;
474 const char *flags = "";
475 unsigned runtime_version = 0;
476 g->compile_unit = LLVMZigCreateCompileUnit(g->dbuilder, LLVMZigLang_DW_LANG_C99(),
477 buf_ptr(&g->in_file), buf_ptr(&g->in_dir),
478 buf_ptr(producer), is_optimized, flags, runtime_version,
479 "", 0, !g->strip_debug_symbols);
480
481472 g->block_scopes.append(LLVMZigCompileUnitToScope(g->compile_unit));
482473
483 g->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&g->in_file), buf_ptr(&g->in_dir));
484
485474
486475 // Generate function prototypes
487476 auto it = g->fn_table.entry_iterator();
......@@ -523,6 +512,7 @@ void code_gen(CodeGen *g) {
523512 // Generate function definitions.
524513 for (int i = 0; i < g->fn_defs.length; i += 1) {
525514 FnTableEntry *fn_table_entry = g->fn_defs.at(i);
515 ImportTableEntry *import = fn_table_entry->import_entry;
526516 AstNode *fn_def_node = fn_table_entry->fn_def_node;
527517 LLVMValueRef fn = fn_table_entry->fn_value;
528518 g->cur_fn = fn_table_entry;
......@@ -532,14 +522,15 @@ void code_gen(CodeGen *g) {
532522 AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
533523
534524 // Add debug info.
535 LLVMZigDIScope *fn_scope = LLVMZigFileToScope(g->di_file);
525 LLVMZigDIScope *fn_scope = LLVMZigFileToScope(import->di_file);
536526 unsigned line_number = fn_def_node->line + 1;
537527 unsigned scope_line = line_number;
538528 bool is_definition = true;
539529 unsigned flags = 0;
530 bool is_optimized = g->build_type == CodeGenBuildTypeRelease;
540531 LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder,
541 fn_scope, buf_ptr(&fn_proto->name), "", g->di_file, line_number,
542 create_di_function_type(g, fn_proto, g->di_file), fn_table_entry->internal_linkage,
532 fn_scope, buf_ptr(&fn_proto->name), "", import->di_file, line_number,
533 create_di_function_type(g, fn_proto, import->di_file), fn_table_entry->internal_linkage,
543534 is_definition, scope_line, flags, is_optimized, fn);
544535
545536 g->block_scopes.append(LLVMZigSubprogramToScope(subprogram));
......@@ -555,7 +546,7 @@ void code_gen(CodeGen *g) {
555546 LLVMGetParams(fn, codegen_fn_def->params);
556547
557548 bool add_implicit_return = codegen_fn_def->add_implicit_return;
558 gen_block(g, fn_def_node->data.fn_def.body, add_implicit_return);
549 gen_block(g, import, fn_def_node->data.fn_def.body, add_implicit_return);
559550
560551 g->block_scopes.pop();
561552 }
......@@ -563,7 +554,9 @@ void code_gen(CodeGen *g) {
563554
564555 LLVMZigDIBuilderFinalize(g->dbuilder);
565556
566 LLVMDumpModule(g->module);
557 if (g->verbose) {
558 LLVMDumpModule(g->module);
559 }
567560
568561 // in release mode, we're sooooo confident that we've generated correct ir,
569562 // that we skip the verify module step in order to get better performance.
......@@ -573,13 +566,171 @@ void code_gen(CodeGen *g) {
573566#endif
574567}
575568
576void code_gen_optimize(CodeGen *g) {
577 LLVMZigOptimizeModule(g->target_machine, g->module);
578 LLVMDumpModule(g->module);
569static void define_primitive_types(CodeGen *g) {
570 {
571 // if this type is anywhere in the AST, we should never hit codegen.
572 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
573 buf_init_from_str(&entry->name, "(invalid)");
574 g->builtin_types.entry_invalid = entry;
575 }
576 {
577 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
578 entry->type_ref = LLVMInt8Type();
579 buf_init_from_str(&entry->name, "u8");
580 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 8, 8,
581 LLVMZigEncoding_DW_ATE_unsigned());
582 g->type_table.put(&entry->name, entry);
583 g->builtin_types.entry_u8 = entry;
584 }
585 {
586 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
587 entry->type_ref = LLVMInt32Type();
588 buf_init_from_str(&entry->name, "i32");
589 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 32, 32,
590 LLVMZigEncoding_DW_ATE_signed());
591 g->type_table.put(&entry->name, entry);
592 g->builtin_types.entry_i32 = entry;
593 }
594 {
595 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
596 entry->type_ref = LLVMVoidType();
597 buf_init_from_str(&entry->name, "void");
598 entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 0, 0,
599 LLVMZigEncoding_DW_ATE_unsigned());
600 g->type_table.put(&entry->name, entry);
601 g->builtin_types.entry_void = entry;
602 }
603 {
604 TypeTableEntry *entry = allocate<TypeTableEntry>(1);
605 entry->type_ref = LLVMVoidType();
606 buf_init_from_str(&entry->name, "unreachable");
607 entry->di_type = g->builtin_types.entry_void->di_type;
608 g->type_table.put(&entry->name, entry);
609 g->builtin_types.entry_unreachable = entry;
610 }
579611}
580612
581ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g) {
582 return &g->errors;
613
614
615static void init(CodeGen *g, Buf *source_path) {
616 LLVMInitializeAllTargets();
617 LLVMInitializeAllTargetMCs();
618 LLVMInitializeAllAsmPrinters();
619 LLVMInitializeAllAsmParsers();
620 LLVMInitializeNativeTarget();
621
622 g->is_native_target = true;
623 char *native_triple = LLVMGetDefaultTargetTriple();
624
625 LLVMTargetRef target_ref;
626 char *err_msg = nullptr;
627 if (LLVMGetTargetFromTriple(native_triple, &target_ref, &err_msg)) {
628 zig_panic("unable to get target from triple: %s", err_msg);
629 }
630
631 char *native_cpu = LLVMZigGetHostCPUName();
632 char *native_features = LLVMZigGetNativeFeatures();
633
634 LLVMCodeGenOptLevel opt_level = (g->build_type == CodeGenBuildTypeDebug) ?
635 LLVMCodeGenLevelNone : LLVMCodeGenLevelAggressive;
636
637 LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC;
638
639 g->target_machine = LLVMCreateTargetMachine(target_ref, native_triple,
640 native_cpu, native_features, opt_level, reloc_mode, LLVMCodeModelDefault);
641
642 g->target_data_ref = LLVMGetTargetMachineData(g->target_machine);
643
644
645 g->module = LLVMModuleCreateWithName("ZigModule");
646
647 g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref);
648
649 g->builder = LLVMCreateBuilder();
650 g->dbuilder = LLVMZigCreateDIBuilder(g->module, true);
651
652
653 define_primitive_types(g);
654
655 Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING);
656 bool is_optimized = g->build_type == CodeGenBuildTypeRelease;
657 const char *flags = "";
658 unsigned runtime_version = 0;
659 g->compile_unit = LLVMZigCreateCompileUnit(g->dbuilder, LLVMZigLang_DW_LANG_C99(),
660 buf_ptr(source_path), buf_ptr(g->root_source_dir),
661 buf_ptr(producer), is_optimized, flags, runtime_version,
662 "", 0, !g->strip_debug_symbols);
663
664
665}
666
667void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
668 if (!g->initialized) {
669 g->initialized = true;
670 init(g, source_path);
671 }
672
673 Buf full_path = BUF_INIT;
674 os_path_join(g->root_source_dir, source_path, &full_path);
675
676 Buf dirname = BUF_INIT;
677 Buf basename = BUF_INIT;
678 os_path_split(&full_path, &dirname, &basename);
679
680 if (g->verbose) {
681 fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(source_path));
682 fprintf(stderr, "----------------\n");
683 fprintf(stderr, "%s\n", buf_ptr(source_code));
684
685 fprintf(stderr, "\nTokens:\n");
686 fprintf(stderr, "---------\n");
687 }
688
689 ZigList<Token> *tokens = tokenize(source_code);
690
691 if (g->verbose) {
692 print_tokens(source_code, tokens);
693
694 fprintf(stderr, "\nAST:\n");
695 fprintf(stderr, "------\n");
696 }
697
698 ImportTableEntry *import_entry = allocate<ImportTableEntry>(1);
699 import_entry->root = ast_parse(source_code, tokens);
700 assert(import_entry->root);
701 if (g->verbose) {
702 ast_print(import_entry->root, 0);
703
704 fprintf(stderr, "\nSemantic Analysis:\n");
705 fprintf(stderr, "--------------------\n");
706 }
707
708 import_entry->path = source_path;
709 import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&basename), buf_ptr(&dirname));
710 g->import_table.put(source_path, import_entry);
711
712 semantic_analyze(g, import_entry);
713
714 if (g->errors.length == 0) {
715 if (g->verbose) {
716 fprintf(stderr, "OK\n");
717 }
718 } else {
719 for (int i = 0; i < g->errors.length; i += 1) {
720 ErrorMsg *err = &g->errors.at(i);
721 fprintf(stderr, "Error: Line %d, column %d: %s\n",
722 err->line_start + 1, err->column_start + 1,
723 buf_ptr(err->msg));
724 }
725 exit(1);
726 }
727
728 if (g->verbose) {
729 fprintf(stderr, "\nCode Generation:\n");
730 fprintf(stderr, "------------------\n");
731 }
732
733 do_code_gen(g);
583734}
584735
585736static Buf *to_c_type(CodeGen *g, AstNode *type_node) {
......@@ -601,15 +752,15 @@ static Buf *to_c_type(CodeGen *g, AstNode *type_node) {
601752}
602753
603754static void generate_h_file(CodeGen *g) {
604 Buf *h_file_out_path = buf_sprintf("%s.h", buf_ptr(g->out_name));
755 Buf *h_file_out_path = buf_sprintf("%s.h", buf_ptr(g->root_out_name));
605756 FILE *out_h = fopen(buf_ptr(h_file_out_path), "wb");
606757 if (!out_h)
607758 zig_panic("unable to open %s: %s", buf_ptr(h_file_out_path), strerror(errno));
608759
609 Buf *export_macro = buf_sprintf("%s_EXPORT", buf_ptr(g->out_name));
760 Buf *export_macro = buf_sprintf("%s_EXPORT", buf_ptr(g->root_out_name));
610761 buf_upcase(export_macro);
611762
612 Buf *extern_c_macro = buf_sprintf("%s_EXTERN_C", buf_ptr(g->out_name));
763 Buf *extern_c_macro = buf_sprintf("%s_EXTERN_C", buf_ptr(g->root_out_name));
613764 buf_upcase(extern_c_macro);
614765
615766 Buf h_buf = BUF_INIT;
......@@ -644,7 +795,8 @@ static void generate_h_file(CodeGen *g) {
644795 }
645796 }
646797
647 Buf *ifdef_dance_name = buf_sprintf("%s_%s_H", buf_ptr(g->out_name), buf_ptr(g->out_name));
798 Buf *ifdef_dance_name = buf_sprintf("%s_%s_H",
799 buf_ptr(g->root_out_name), buf_ptr(g->root_out_name));
648800 buf_upcase(ifdef_dance_name);
649801
650802 fprintf(out_h, "#ifndef %s\n", buf_ptr(ifdef_dance_name));
......@@ -677,9 +829,27 @@ static void generate_h_file(CodeGen *g) {
677829 zig_panic("unable to close h file: %s", strerror(errno));
678830}
679831
680void code_gen_link(CodeGen *g, const char *out_file) {
832void codegen_link(CodeGen *g, const char *out_file) {
833 bool is_optimized = (g->build_type == CodeGenBuildTypeRelease);
834 if (is_optimized) {
835 if (g->verbose) {
836 fprintf(stderr, "\nOptimization:\n");
837 fprintf(stderr, "---------------\n");
838 }
839
840 LLVMZigOptimizeModule(g->target_machine, g->module);
841
842 if (g->verbose) {
843 LLVMDumpModule(g->module);
844 }
845 }
846 if (g->verbose) {
847 fprintf(stderr, "\nLink:\n");
848 fprintf(stderr, "-------\n");
849 }
850
681851 if (!out_file) {
682 out_file = buf_ptr(g->out_name);
852 out_file = buf_ptr(g->root_out_name);
683853 }
684854
685855 Buf out_file_o = BUF_INIT;
......@@ -728,8 +898,8 @@ void code_gen_link(CodeGen *g, const char *out_file) {
728898
729899 if (g->out_type == OutTypeLib) {
730900 Buf *out_lib_so = buf_sprintf("lib%s.so.%d.%d.%d",
731 buf_ptr(g->out_name), g->version_major, g->version_minor, g->version_patch);
732 Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->out_name), g->version_major);
901 buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
902 Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->root_out_name), g->version_major);
733903 args.append("-shared");
734904 args.append("-soname");
735905 args.append(buf_ptr(soname));
......@@ -756,4 +926,8 @@ void code_gen_link(CodeGen *g, const char *out_file) {
756926 if (g->out_type == OutTypeLib) {
757927 generate_h_file(g);
758928 }
929
930 if (g->verbose) {
931 fprintf(stderr, "OK\n");
932 }
759933}
src/codegen.hpp+4-7
......@@ -29,7 +29,7 @@ struct ErrorMsg {
2929};
3030
3131
32CodeGen *create_codegen(AstNode *root, Buf *in_file);
32CodeGen *codegen_create(Buf *root_source_dir);
3333
3434enum CodeGenBuildType {
3535 CodeGenBuildTypeDebug,
......@@ -38,15 +38,12 @@ enum CodeGenBuildType {
3838void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type);
3939void codegen_set_is_static(CodeGen *codegen, bool is_static);
4040void codegen_set_strip(CodeGen *codegen, bool strip);
41void codegen_set_verbose(CodeGen *codegen, bool verbose);
4142void codegen_set_out_type(CodeGen *codegen, OutType out_type);
4243void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
4344
44void code_gen_optimize(CodeGen *g);
45void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code);
4546
46void code_gen(CodeGen *g);
47
48void code_gen_link(CodeGen *g, const char *out_file);
49
50ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g);
47void codegen_link(CodeGen *g, const char *out_file);
5148
5249#endif
src/error.cpp+1
......@@ -5,6 +5,7 @@ const char *err_str(int err) {
55 case ErrorNone: return "(no error)";
66 case ErrorNoMem: return "out of memory";
77 case ErrorInvalidFormat: return "invalid format";
8 case ErrorSemanticAnalyzeFail: return "semantic analyze failed";
89 }
910 return "(invalid error)";
1011}
src/error.hpp+1
......@@ -12,6 +12,7 @@ enum Error {
1212 ErrorNone,
1313 ErrorNoMem,
1414 ErrorInvalidFormat,
15 ErrorSemanticAnalyzeFail,
1516};
1617
1718const char *err_str(int err);
src/main.cpp+51-119
......@@ -6,25 +6,11 @@
66 */
77
88#include "config.h"
9#include "util.hpp"
10#include "list.hpp"
119#include "buffer.hpp"
12#include "parser.hpp"
13#include "tokenizer.hpp"
14#include "error.hpp"
1510#include "codegen.hpp"
16#include "analyze.hpp"
11#include "os.hpp"
1712
1813#include <stdio.h>
19#include <string.h>
20#include <stdlib.h>
21#include <limits.h>
22#include <stdint.h>
23#include <errno.h>
24#include <sys/types.h>
25#include <sys/stat.h>
26#include <unistd.h>
27#include <inttypes.h>
2814
2915static int usage(const char *arg0) {
3016 fprintf(stderr, "Usage: %s [command] [options] target\n"
......@@ -38,6 +24,7 @@ static int usage(const char *arg0) {
3824 " --export [exe|lib|obj] override output type\n"
3925 " --name [name] override output name\n"
4026 " --output [file] override destination path\n"
27 " --verbose turn on compiler debug output\n"
4128 , arg0);
4229 return EXIT_FAILURE;
4330}
......@@ -47,98 +34,47 @@ static int version(void) {
4734 return EXIT_SUCCESS;
4835}
4936
50static Buf *fetch_file(FILE *f) {
51 int fd = fileno(f);
52 struct stat st;
53 if (fstat(fd, &st))
54 zig_panic("unable to stat file: %s", strerror(errno));
55 off_t big_size = st.st_size;
56 if (big_size > INT_MAX)
57 zig_panic("file too big");
58 int size = (int)big_size;
59
60 Buf *buf = buf_alloc_fixed(size);
61 size_t amt_read = fread(buf_ptr(buf), 1, buf_len(buf), f);
62 if (amt_read != (size_t)buf_len(buf))
63 zig_panic("error reading: %s", strerror(errno));
64
65 return buf;
66}
67
68static int build(const char *arg0, const char *in_file, const char *out_file, bool release,
69 bool strip, bool is_static, OutType out_type, char *out_name)
70{
71 static char cur_dir[1024];
37struct Build {
38 const char *in_file;
39 const char *out_file;
40 bool release;
41 bool strip;
42 bool is_static;
43 OutType out_type;
44 const char *out_name;
45 bool verbose;
46};
7247
73 if (!in_file)
48static int build(const char *arg0, Build *b) {
49 if (!b->in_file)
7450 return usage(arg0);
7551
76 FILE *in_f;
77 if (strcmp(in_file, "-") == 0) {
78 in_f = stdin;
79 char *result = getcwd(cur_dir, sizeof(cur_dir));
80 if (!result)
81 zig_panic("unable to get current working directory: %s", strerror(errno));
82 } else {
83 in_f = fopen(in_file, "rb");
84 if (!in_f)
85 zig_panic("unable to open %s for reading: %s\n", in_file, strerror(errno));
86 }
52 Buf in_file_buf = BUF_INIT;
53 buf_init_from_str(&in_file_buf, b->in_file);
8754
88 fprintf(stderr, "Original source:\n");
89 fprintf(stderr, "----------------\n");
90 Buf *in_data = fetch_file(in_f);
91 fprintf(stderr, "%s\n", buf_ptr(in_data));
92
93 fprintf(stderr, "\nTokens:\n");
94 fprintf(stderr, "---------\n");
95 ZigList<Token> *tokens = tokenize(in_data);
96 print_tokens(in_data, tokens);
97
98 fprintf(stderr, "\nAST:\n");
99 fprintf(stderr, "------\n");
100 AstNode *root = ast_parse(in_data, tokens);
101 assert(root);
102 ast_print(root, 0);
103
104 fprintf(stderr, "\nSemantic Analysis:\n");
105 fprintf(stderr, "--------------------\n");
106 CodeGen *codegen = create_codegen(root, buf_create_from_str(in_file));
107 codegen_set_build_type(codegen, release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug);
108 codegen_set_strip(codegen, strip);
109 codegen_set_is_static(codegen, is_static);
110 if (out_type != OutTypeUnknown)
111 codegen_set_out_type(codegen, out_type);
112 if (out_name)
113 codegen_set_out_name(codegen, buf_create_from_str(out_name));
114 semantic_analyze(codegen);
115 ZigList<ErrorMsg> *errors = codegen_error_messages(codegen);
116 if (errors->length == 0) {
117 fprintf(stderr, "OK\n");
55 Buf root_source_dir = BUF_INIT;
56 Buf root_source_code = BUF_INIT;
57 Buf root_source_name = BUF_INIT;
58 if (buf_eql_str(&in_file_buf, "-")) {
59 os_get_cwd(&root_source_dir);
60 os_fetch_file(stdin, &root_source_code);
61 buf_init_from_str(&root_source_name, "");
11862 } else {
119 for (int i = 0; i < errors->length; i += 1) {
120 ErrorMsg *err = &errors->at(i);
121 fprintf(stderr, "Error: Line %d, column %d: %s\n",
122 err->line_start + 1, err->column_start + 1,
123 buf_ptr(err->msg));
124 }
125 return 1;
63 os_path_split(&in_file_buf, &root_source_dir, &root_source_name);
64 os_fetch_file_path(buf_create_from_str(b->in_file), &root_source_code);
12665 }
12766
128 fprintf(stderr, "\nCode Generation:\n");
129 fprintf(stderr, "------------------\n");
130 code_gen(codegen);
131
132 if (release) {
133 fprintf(stderr, "\nOptimization:\n");
134 fprintf(stderr, "---------------\n");
135 code_gen_optimize(codegen);
136 }
137
138 fprintf(stderr, "\nLink:\n");
139 fprintf(stderr, "-------\n");
140 code_gen_link(codegen, out_file);
141 fprintf(stderr, "OK\n");
67 CodeGen *g = codegen_create(&root_source_dir);
68 codegen_set_build_type(g, b->release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug);
69 codegen_set_strip(g, b->strip);
70 codegen_set_is_static(g, b->is_static);
71 if (b->out_type != OutTypeUnknown)
72 codegen_set_out_type(g, b->out_type);
73 if (b->out_name)
74 codegen_set_out_name(g, buf_create_from_str(b->out_name));
75 codegen_set_verbose(g, b->verbose);
76 codegen_add_code(g, &root_source_name, &root_source_code);
77 codegen_link(g, b->out_file);
14278
14379 return 0;
14480}
......@@ -151,43 +87,39 @@ enum Cmd {
15187
15288int main(int argc, char **argv) {
15389 char *arg0 = argv[0];
154 char *in_file = NULL;
155 char *out_file = NULL;
156 bool release = false;
157 bool strip = false;
158 bool is_static = false;
159
160 OutType out_type = OutTypeUnknown;
161 char *out_name = NULL;
16290
91 Build b = {0};
16392 Cmd cmd = CmdNone;
93
16494 for (int i = 1; i < argc; i += 1) {
16595 char *arg = argv[i];
16696 if (arg[0] == '-' && arg[1] == '-') {
16797 if (strcmp(arg, "--release") == 0) {
168 release = true;
98 b.release = true;
16999 } else if (strcmp(arg, "--strip") == 0) {
170 strip = true;
100 b.strip = true;
171101 } else if (strcmp(arg, "--static") == 0) {
172 is_static = true;
102 b.is_static = true;
103 } else if (strcmp(arg, "--verbose") == 0) {
104 b.verbose = true;
173105 } else if (i + 1 >= argc) {
174106 return usage(arg0);
175107 } else {
176108 i += 1;
177109 if (strcmp(arg, "--output") == 0) {
178 out_file = argv[i];
110 b.out_file = argv[i];
179111 } else if (strcmp(arg, "--export") == 0) {
180112 if (strcmp(argv[i], "exe") == 0) {
181 out_type = OutTypeExe;
113 b.out_type = OutTypeExe;
182114 } else if (strcmp(argv[i], "lib") == 0) {
183 out_type = OutTypeLib;
115 b.out_type = OutTypeLib;
184116 } else if (strcmp(argv[i], "obj") == 0) {
185 out_type = OutTypeObj;
117 b.out_type = OutTypeObj;
186118 } else {
187119 return usage(arg0);
188120 }
189121 } else if (strcmp(arg, "--name") == 0) {
190 out_name = argv[i];
122 b.out_name = argv[i];
191123 } else {
192124 return usage(arg0);
193125 }
......@@ -206,8 +138,8 @@ int main(int argc, char **argv) {
206138 case CmdNone:
207139 zig_unreachable();
208140 case CmdBuild:
209 if (!in_file) {
210 in_file = arg;
141 if (!b.in_file) {
142 b.in_file = arg;
211143 } else {
212144 return usage(arg0);
213145 }
......@@ -222,7 +154,7 @@ int main(int argc, char **argv) {
222154 case CmdNone:
223155 return usage(arg0);
224156 case CmdBuild:
225 return build(arg0, in_file, out_file, release, strip, is_static, out_type, out_name);
157 return build(arg0, &b);
226158 case CmdVersion:
227159 return version();
228160 }
src/os.cpp+51-4
......@@ -13,8 +13,8 @@
1313#include <sys/types.h>
1414#include <sys/stat.h>
1515#include <sys/wait.h>
16#include <stdio.h>
1716#include <fcntl.h>
17#include <limits.h>
1818
1919void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached) {
2020 pid_t pid = fork();
......@@ -37,7 +37,7 @@ void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detache
3737 zig_panic("execvp failed: %s", strerror(errno));
3838}
3939
40static void read_all_fd(int fd, Buf *out_buf) {
40static void read_all_fd_stream(int fd, Buf *out_buf) {
4141 static const ssize_t buf_size = 0x2000;
4242 buf_resize(out_buf, buf_size);
4343 ssize_t actual_buf_len = 0;
......@@ -72,6 +72,12 @@ void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) {
7272 buf_init_from_buf(out_basename, full_path);
7373}
7474
75void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {
76 buf_init_from_buf(out_full_path, dirname);
77 buf_append_char(out_full_path, '/');
78 buf_append_buf(out_full_path, basename);
79}
80
7581void os_exec_process(const char *exe, ZigList<const char *> &args,
7682 int *return_code, Buf *out_stderr, Buf *out_stdout)
7783{
......@@ -117,8 +123,8 @@ void os_exec_process(const char *exe, ZigList<const char *> &args,
117123
118124 waitpid(pid, return_code, 0);
119125
120 read_all_fd(stdout_pipe[0], out_stdout);
121 read_all_fd(stderr_pipe[0], out_stderr);
126 read_all_fd_stream(stdout_pipe[0], out_stdout);
127 read_all_fd_stream(stderr_pipe[0], out_stderr);
122128
123129 }
124130}
......@@ -133,3 +139,44 @@ void os_write_file(Buf *full_path, Buf *contents) {
133139 if (close(fd) == -1)
134140 zig_panic("close failed");
135141}
142
143int os_fetch_file(FILE *f, Buf *out_contents) {
144 int fd = fileno(f);
145 struct stat st;
146 if (fstat(fd, &st))
147 zig_panic("unable to stat file: %s", strerror(errno));
148 off_t big_size = st.st_size;
149 if (big_size > INT_MAX)
150 zig_panic("file too big");
151 int size = (int)big_size;
152
153 buf_resize(out_contents, size);
154 ssize_t ret = read(fd, buf_ptr(out_contents), size);
155
156 if (ret != size)
157 zig_panic("unable to read file: %s", strerror(errno));
158
159 return 0;
160}
161
162int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
163 FILE *f = fopen(buf_ptr(full_path), "rb");
164 if (!f)
165 zig_panic("unable to open %s: %s\n", buf_ptr(full_path), strerror(errno));
166 int result = os_fetch_file(f, out_contents);
167 fclose(f);
168 return result;
169}
170
171int os_get_cwd(Buf *out_cwd) {
172 int err = ERANGE;
173 buf_resize(out_cwd, 512);
174 while (err == ERANGE) {
175 buf_resize(out_cwd, buf_len(out_cwd) * 2);
176 err = getcwd(buf_ptr(out_cwd), buf_len(out_cwd)) ? 0 : errno;
177 }
178 if (err)
179 zig_panic("unable to get cwd: %s", strerror(err));
180
181 return 0;
182}
src/os.hpp+9
......@@ -11,13 +11,22 @@
1111#include "list.hpp"
1212#include "buffer.hpp"
1313
14#include <stdio.h>
15
1416void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached);
1517void os_exec_process(const char *exe, ZigList<const char *> &args,
1618 int *return_code, Buf *out_stderr, Buf *out_stdout);
1719
1820void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
21void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);
1922
2023void os_write_file(Buf *full_path, Buf *contents);
2124
2225
26int os_fetch_file(FILE *file, Buf *out_contents);
27int os_fetch_file_path(Buf *full_path, Buf *out_contents);
28
29int os_get_cwd(Buf *out_cwd);
30
31
2332#endif
src/parser.cpp+41-1
......@@ -100,6 +100,8 @@ const char *node_type_str(NodeType node_type) {
100100 return "Symbol";
101101 case NodeTypePrefixOpExpr:
102102 return "PrefixOpExpr";
103 case NodeTypeUse:
104 return "Use";
103105 }
104106 zig_unreachable();
105107}
......@@ -241,6 +243,9 @@ void ast_print(AstNode *node, int indent) {
241243 fprintf(stderr, "PrimaryExpr Symbol %s\n",
242244 buf_ptr(&node->data.symbol));
243245 break;
246 case NodeTypeUse:
247 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.use.path));
248 break;
244249 }
245250}
246251
......@@ -1231,7 +1236,36 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b
12311236}
12321237
12331238/*
1234TopLevelDecl : FnDef | ExternBlock | RootExportDecl
1239Use : many(Directive) token(Use) token(String) token(Semicolon)
1240*/
1241static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory) {
1242 assert(mandatory == false);
1243
1244 Token *use_kw = &pc->tokens->at(*token_index);
1245 if (use_kw->id != TokenIdKeywordUse)
1246 return nullptr;
1247 *token_index += 1;
1248
1249 Token *use_name = &pc->tokens->at(*token_index);
1250 *token_index += 1;
1251 ast_expect_token(pc, use_name, TokenIdStringLiteral);
1252
1253 Token *semicolon = &pc->tokens->at(*token_index);
1254 *token_index += 1;
1255 ast_expect_token(pc, semicolon, TokenIdSemicolon);
1256
1257 AstNode *node = ast_create_node(NodeTypeUse, use_kw);
1258
1259 parse_string_literal(pc, use_name, &node->data.use.path);
1260
1261 node->data.use.directives = pc->directive_list;
1262 pc->directive_list = nullptr;
1263
1264 return node;
1265}
1266
1267/*
1268TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use
12351269*/
12361270static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
12371271 for (;;) {
......@@ -1258,6 +1292,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
12581292 continue;
12591293 }
12601294
1295 AstNode *use_node = ast_parse_use(pc, token_index, false);
1296 if (use_node) {
1297 top_level_decls->append(use_node);
1298 continue;
1299 }
1300
12611301 if (pc->directive_list->length > 0) {
12621302 ast_error(directive_token, "invalid directive");
12631303 }
src/parser.hpp+7
......@@ -35,6 +35,7 @@ enum NodeType {
3535 NodeTypeSymbol,
3636 NodeTypePrefixOpExpr,
3737 NodeTypeFnCallExpr,
38 NodeTypeUse,
3839};
3940
4041struct AstNodeRoot {
......@@ -158,6 +159,11 @@ struct AstNodePrefixOpExpr {
158159 AstNode *primary_expr;
159160};
160161
162struct AstNodeUse {
163 Buf path;
164 ZigList<AstNode *> *directives;
165};
166
161167struct AstNode {
162168 enum NodeType type;
163169 AstNode *parent;
......@@ -180,6 +186,7 @@ struct AstNode {
180186 AstNodeCastExpr cast_expr;
181187 AstNodePrefixOpExpr prefix_op_expr;
182188 AstNodeFnCallExpr fn_call_expr;
189 AstNodeUse use;
183190 Buf number;
184191 Buf string;
185192 Buf symbol;
src/semantic_info.hpp+23-14
......@@ -12,15 +12,6 @@
1212#include "hash_map.hpp"
1313#include "zig_llvm.hpp"
1414
15struct FnTableEntry {
16 LLVMValueRef fn_value;
17 AstNode *proto_node;
18 AstNode *fn_def_node;
19 bool is_extern;
20 bool internal_linkage;
21 unsigned calling_convention;
22};
23
2415struct TypeTableEntry {
2516 LLVMTypeRef type_ref;
2617 LLVMZigDIType *di_type;
......@@ -33,17 +24,35 @@ struct TypeTableEntry {
3324 TypeTableEntry *pointer_mut_parent;
3425};
3526
27struct ImportTableEntry {
28 AstNode *root;
29 Buf *path; // relative to root_source_dir
30 LLVMZigDIFile *di_file;
31};
32
33struct FnTableEntry {
34 LLVMValueRef fn_value;
35 AstNode *proto_node;
36 AstNode *fn_def_node;
37 bool is_extern;
38 bool internal_linkage;
39 unsigned calling_convention;
40 ImportTableEntry *import_entry;
41};
42
3643struct CodeGen {
3744 LLVMModuleRef module;
38 AstNode *root;
3945 ZigList<ErrorMsg> errors;
4046 LLVMBuilderRef builder;
4147 LLVMZigDIBuilder *dbuilder;
4248 LLVMZigDICompileUnit *compile_unit;
49
50 // reminder: hash tables must be initialized before use
4351 HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
4452 HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
4553 HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
4654 HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
55 HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
4756
4857 struct {
4958 TypeTableEntry *entry_u8;
......@@ -60,12 +69,10 @@ struct CodeGen {
6069 CodeGenBuildType build_type;
6170 LLVMTargetMachineRef target_machine;
6271 bool is_native_target;
63 Buf in_file;
64 Buf in_dir;
72 Buf *root_source_dir;
73 Buf *root_out_name;
6574 ZigList<LLVMZigDIScope *> block_scopes;
66 LLVMZigDIFile *di_file;
6775 ZigList<FnTableEntry *> fn_defs;
68 Buf *out_name;
6976 OutType out_type;
7077 FnTableEntry *cur_fn;
7178 bool c_stdint_used;
......@@ -73,6 +80,8 @@ struct CodeGen {
7380 int version_major;
7481 int version_minor;
7582 int version_patch;
83 bool verbose;
84 bool initialized;
7685};
7786
7887struct TypeNode {
src/tokenizer.cpp+3
......@@ -180,6 +180,8 @@ static void end_token(Tokenize *t) {
180180 t->cur_tok->id = TokenIdKeywordExport;
181181 } else if (mem_eql_str(token_mem, token_len, "as")) {
182182 t->cur_tok->id = TokenIdKeywordAs;
183 } else if (mem_eql_str(token_mem, token_len, "use")) {
184 t->cur_tok->id = TokenIdKeywordUse;
183185 }
184186
185187 t->cur_tok = nullptr;
......@@ -562,6 +564,7 @@ static const char * token_name(Token *token) {
562564 case TokenIdKeywordPub: return "Pub";
563565 case TokenIdKeywordExport: return "Export";
564566 case TokenIdKeywordAs: return "As";
567 case TokenIdKeywordUse: return "Use";
565568 case TokenIdLParen: return "LParen";
566569 case TokenIdRParen: return "RParen";
567570 case TokenIdComma: return "Comma";
src/tokenizer.hpp+1
......@@ -22,6 +22,7 @@ enum TokenId {
2222 TokenIdKeywordPub,
2323 TokenIdKeywordExport,
2424 TokenIdKeywordAs,
25 TokenIdKeywordUse,
2526 TokenIdLParen,
2627 TokenIdRParen,
2728 TokenIdComma,
test/run_tests.cpp+2
......@@ -47,6 +47,7 @@ static void add_simple_case(const char *case_name, const char *source, const cha
4747 test_case->compiler_args.append(tmp_exe_path);
4848 test_case->compiler_args.append("--release");
4949 test_case->compiler_args.append("--strip");
50 test_case->compiler_args.append("--verbose");
5051
5152 test_cases.append(test_case);
5253}
......@@ -70,6 +71,7 @@ static void add_compile_fail_case(const char *case_name, const char *source, int
7071 test_case->compiler_args.append(tmp_exe_path);
7172 test_case->compiler_args.append("--release");
7273 test_case->compiler_args.append("--strip");
74 test_case->compiler_args.append("--verbose");
7375
7476 test_cases.append(test_case);
7577