refactor code to prepare for multiple files

verbose compiler output is now behind --verbose flag
This commit is contained in:
Andrew Kelley 2015-11-30 19:58:53 -07:00
parent ef482ece7c
commit 55b8472374
24 changed files with 474 additions and 287 deletions

View File

@ -22,16 +22,16 @@ include_directories(
) )
set(ZIG_SOURCES set(ZIG_SOURCES
"${CMAKE_SOURCE_DIR}/src/tokenizer.cpp"
"${CMAKE_SOURCE_DIR}/src/parser.cpp"
"${CMAKE_SOURCE_DIR}/src/analyze.cpp" "${CMAKE_SOURCE_DIR}/src/analyze.cpp"
"${CMAKE_SOURCE_DIR}/src/codegen.cpp"
"${CMAKE_SOURCE_DIR}/src/buffer.cpp" "${CMAKE_SOURCE_DIR}/src/buffer.cpp"
"${CMAKE_SOURCE_DIR}/src/error.cpp" "${CMAKE_SOURCE_DIR}/src/error.cpp"
"${CMAKE_SOURCE_DIR}/src/main.cpp" "${CMAKE_SOURCE_DIR}/src/main.cpp"
"${CMAKE_SOURCE_DIR}/src/parser.cpp"
"${CMAKE_SOURCE_DIR}/src/tokenizer.cpp"
"${CMAKE_SOURCE_DIR}/src/util.cpp"
"${CMAKE_SOURCE_DIR}/src/codegen.cpp"
"${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
"${CMAKE_SOURCE_DIR}/src/os.cpp" "${CMAKE_SOURCE_DIR}/src/os.cpp"
"${CMAKE_SOURCE_DIR}/src/util.cpp"
"${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
) )
set(TEST_SOURCES set(TEST_SOURCES

View File

@ -79,7 +79,9 @@ zig | C equivalent | Description
``` ```
Root : many(TopLevelDecl) token(EOF) Root : many(TopLevelDecl) token(EOF)
TopLevelDecl : FnDef | ExternBlock | RootExportDecl TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use
Use : many(Directive) token(Use) token(String) token(Semicolon)
RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon) RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token(Semicolon)

View File

@ -7,7 +7,7 @@ if exists("b:current_syntax")
finish finish
endif endif
syn keyword zigKeyword fn return mut const extern unreachable export pub as syn keyword zigKeyword fn return mut const extern unreachable export pub as use
syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void 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 zigCommentLine start="//" end="$" contains=zigTodo,@Spell
@ -19,6 +19,15 @@ syn region zigCommentBlockDocNest matchgroup=zigCommentBlockDoc start="/\*" end=
syn keyword zigTodo contained TODO XXX syn keyword zigTodo contained TODO XXX
syn match zigEscapeError display contained /\\./
syn match zigEscape display contained /\\\([nrt0\\'"]\|x\x\{2}\)/
syn match zigEscapeUnicode display contained /\\\(u\x\{4}\|U\x\{8}\)/
syn match zigEscapeUnicode display contained /\\u{\x\{1,6}}/
syn match zigStringContinuation display contained /\\\n\s*/
syn region zigString start=+b"+ skip=+\\\\\|\\"+ end=+"+ contains=zigEscape,zigEscapeError,zigStringContinuation
syn region zigString start=+"+ skip=+\\\\\|\\"+ end=+"+ contains=zigEscape,zigEscapeUnicode,zigEscapeError,zigStringContinuation,@Spell
syn region zigString start='b\?r\z(#*\)"' end='"\z1' contains=@Spell
let b:current_syntax = "zig" let b:current_syntax = "zig"
hi def link zigKeyword Keyword hi def link zigKeyword Keyword
@ -28,4 +37,8 @@ hi def link zigCommentLineDoc SpecialComment
hi def link zigCommentBlock zigCommentLine hi def link zigCommentBlock zigCommentLine
hi def link zigCommentBlockDoc zigCommentLineDoc hi def link zigCommentBlockDoc zigCommentLineDoc
hi def link zigTodo Todo hi def link zigTodo Todo
hi def link zigStringContinuation Special
hi def link zigString String
hi def link zigEscape Special
hi def link zigEscapeUnicode zigEscape
hi def link zigEscapeError Error

View File

@ -0,0 +1,5 @@
use "libc.zig";
fn print_text() {
puts("it works!");
}

View File

@ -0,0 +1,5 @@
#link("c")
extern {
fn puts(s: *mut u8) -> i32;
fn exit(code: i32) -> unreachable;
}

View File

@ -0,0 +1,9 @@
export executable "test";
use "libc.zig";
use "foo.zig";
fn _start() -> unreachable {
print_text();
exit(0);
}

View File

@ -0,0 +1,7 @@
#include "mathtest.h"
#include <stdio.h>
int main(int argc, char **argv) {
printf("%d\n", add(42, 1137));
return 0;
}

View File

@ -113,7 +113,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node) {
resolve_type(g, node->data.fn_proto.return_type); resolve_type(g, node->data.fn_proto.return_type);
} }
static void preview_function_declarations(CodeGen *g, AstNode *node) { static void preview_function_declarations(CodeGen *g, ImportTableEntry *import, AstNode *node) {
switch (node->type) { switch (node->type) {
case NodeTypeExternBlock: case NodeTypeExternBlock:
for (int i = 0; i < node->data.extern_block.directives->length; i += 1) { for (int i = 0; i < node->data.extern_block.directives->length; i += 1) {
@ -139,6 +139,7 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {
fn_table_entry->proto_node = fn_proto; fn_table_entry->proto_node = fn_proto;
fn_table_entry->is_extern = true; fn_table_entry->is_extern = true;
fn_table_entry->calling_convention = LLVMCCallConv; fn_table_entry->calling_convention = LLVMCCallConv;
fn_table_entry->import_entry = import;
g->fn_table.put(name, fn_table_entry); g->fn_table.put(name, fn_table_entry);
} }
break; break;
@ -156,6 +157,7 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {
node->codegen_node->data.fn_def_node.skip = true; node->codegen_node->data.fn_def_node.skip = true;
} else { } else {
FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1); FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
fn_table_entry->import_entry = import;
fn_table_entry->proto_node = proto_node; fn_table_entry->proto_node = proto_node;
fn_table_entry->fn_def_node = node; fn_table_entry->fn_def_node = node;
fn_table_entry->internal_linkage = proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport; fn_table_entry->internal_linkage = proto_node->data.fn_proto.visib_mod != FnProtoVisibModExport;
@ -190,8 +192,8 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {
} else { } else {
g->root_export_decl = node; g->root_export_decl = node;
if (!g->out_name) if (!g->root_out_name)
g->out_name = &node->data.root_export_decl.name; g->root_out_name = &node->data.root_export_decl.name;
Buf *out_type = &node->data.root_export_decl.type; Buf *out_type = &node->data.root_export_decl.type;
OutType export_out_type; OutType export_out_type;
@ -209,6 +211,9 @@ static void preview_function_declarations(CodeGen *g, AstNode *node) {
g->out_type = export_out_type; g->out_type = export_out_type;
} }
break; break;
case NodeTypeUse:
zig_panic("TODO use");
break;
case NodeTypeDirective: case NodeTypeDirective:
case NodeTypeParamDecl: case NodeTypeParamDecl:
case NodeTypeFnProto: case NodeTypeFnProto:
@ -346,6 +351,7 @@ static void analyze_expression(CodeGen *g, AstNode *node) {
case NodeTypeRootExportDecl: case NodeTypeRootExportDecl:
case NodeTypeExternBlock: case NodeTypeExternBlock:
case NodeTypeFnDef: case NodeTypeFnDef:
case NodeTypeUse:
zig_unreachable(); zig_unreachable();
} }
} }
@ -377,9 +383,9 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
case NodeTypeRootExportDecl: case NodeTypeRootExportDecl:
case NodeTypeExternBlock: case NodeTypeExternBlock:
case NodeTypeUse:
// already looked at these in the preview pass // already looked at these in the preview pass
break; break;
case NodeTypeDirective: case NodeTypeDirective:
case NodeTypeParamDecl: case NodeTypeParamDecl:
case NodeTypeFnProto: case NodeTypeFnProto:
@ -400,13 +406,13 @@ static void analyze_top_level_declaration(CodeGen *g, AstNode *node) {
} }
} }
static void analyze_root(CodeGen *g, AstNode *node) { static void analyze_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
assert(node->type == NodeTypeRoot); assert(node->type == NodeTypeRoot);
// find function declarations // find function declarations
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);
preview_function_declarations(g, child); preview_function_declarations(g, import, child);
} }
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) {
@ -414,7 +420,7 @@ static void analyze_root(CodeGen *g, AstNode *node) {
analyze_top_level_declaration(g, child); analyze_top_level_declaration(g, child);
} }
if (!g->out_name) { if (!g->root_out_name) {
add_node_error(g, node, add_node_error(g, node,
buf_sprintf("missing export declaration and output name not provided")); buf_sprintf("missing export declaration and output name not provided"));
} else if (g->out_type == OutTypeUnknown) { } else if (g->out_type == OutTypeUnknown) {
@ -423,88 +429,7 @@ static void analyze_root(CodeGen *g, AstNode *node) {
} }
} }
static void define_primitive_types(CodeGen *g) { void semantic_analyze(CodeGen *g, ImportTableEntry *import_table_entry) {
{ analyze_root(g, import_table_entry, import_table_entry->root);
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
entry->type_ref = LLVMInt8Type();
buf_init_from_str(&entry->name, "u8");
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 8, 8,
LLVMZigEncoding_DW_ATE_unsigned());
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_u8 = entry;
}
{
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
entry->type_ref = LLVMInt32Type();
buf_init_from_str(&entry->name, "i32");
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 32, 32,
LLVMZigEncoding_DW_ATE_signed());
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_i32 = entry;
}
{
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
entry->type_ref = LLVMVoidType();
buf_init_from_str(&entry->name, "void");
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 0, 0,
LLVMZigEncoding_DW_ATE_unsigned());
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_void = entry;
// invalid types are void
g->builtin_types.entry_invalid = entry;
}
{
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
entry->type_ref = LLVMVoidType();
buf_init_from_str(&entry->name, "unreachable");
entry->di_type = g->builtin_types.entry_invalid->di_type;
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_unreachable = entry;
}
}
void semantic_analyze(CodeGen *g) {
LLVMInitializeAllTargets();
LLVMInitializeAllTargetMCs();
LLVMInitializeAllAsmPrinters();
LLVMInitializeAllAsmParsers();
LLVMInitializeNativeTarget();
g->is_native_target = true;
char *native_triple = LLVMGetDefaultTargetTriple();
LLVMTargetRef target_ref;
char *err_msg = nullptr;
if (LLVMGetTargetFromTriple(native_triple, &target_ref, &err_msg)) {
zig_panic("unable to get target from triple: %s", err_msg);
}
char *native_cpu = LLVMZigGetHostCPUName();
char *native_features = LLVMZigGetNativeFeatures();
LLVMCodeGenOptLevel opt_level = (g->build_type == CodeGenBuildTypeDebug) ?
LLVMCodeGenLevelNone : LLVMCodeGenLevelAggressive;
LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC;
g->target_machine = LLVMCreateTargetMachine(target_ref, native_triple,
native_cpu, native_features, opt_level, reloc_mode, LLVMCodeModelDefault);
g->target_data_ref = LLVMGetTargetMachineData(g->target_machine);
g->module = LLVMModuleCreateWithName("ZigModule");
g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref);
g->builder = LLVMCreateBuilder();
g->dbuilder = LLVMZigCreateDIBuilder(g->module, true);
define_primitive_types(g);
analyze_root(g, g->root);
} }

View File

@ -9,7 +9,8 @@
#define ZIG_ANALYZE_HPP #define ZIG_ANALYZE_HPP
struct CodeGen; struct CodeGen;
struct ImportTableEntry;
void semantic_analyze(CodeGen *g); void semantic_analyze(CodeGen *g, ImportTableEntry *entry);
#endif #endif

View File

@ -11,26 +11,21 @@
#include "os.hpp" #include "os.hpp"
#include "config.h" #include "config.h"
#include "error.hpp" #include "error.hpp"
#include "semantic_info.hpp" #include "semantic_info.hpp"
#include "analyze.hpp"
#include <stdio.h> #include <stdio.h>
#include <errno.h> #include <errno.h>
CodeGen *create_codegen(AstNode *root, Buf *in_full_path) { CodeGen *codegen_create(Buf *root_source_dir) {
CodeGen *g = allocate<CodeGen>(1); CodeGen *g = allocate<CodeGen>(1);
g->root = root;
g->fn_table.init(32); g->fn_table.init(32);
g->str_table.init(32); g->str_table.init(32);
g->type_table.init(32); g->type_table.init(32);
g->link_table.init(32); g->link_table.init(32);
g->is_static = false; g->import_table.init(32);
g->build_type = CodeGenBuildTypeDebug; g->build_type = CodeGenBuildTypeDebug;
g->strip_debug_symbols = false; g->root_source_dir = root_source_dir;
g->out_name = nullptr;
g->out_type = OutTypeUnknown;
os_path_split(in_full_path, &g->in_dir, &g->in_file);
return g; return g;
} }
@ -42,6 +37,10 @@ void codegen_set_is_static(CodeGen *g, bool is_static) {
g->is_static = is_static; g->is_static = is_static;
} }
void codegen_set_verbose(CodeGen *g, bool verbose) {
g->verbose = verbose;
}
void codegen_set_strip(CodeGen *g, bool strip) { void codegen_set_strip(CodeGen *g, bool strip) {
g->strip_debug_symbols = strip; g->strip_debug_symbols = strip;
} }
@ -51,7 +50,7 @@ void codegen_set_out_type(CodeGen *g, OutType out_type) {
} }
void codegen_set_out_name(CodeGen *g, Buf *out_name) { void codegen_set_out_name(CodeGen *g, Buf *out_name) {
g->out_name = out_name; g->root_out_name = out_name;
} }
static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node); static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);
@ -425,16 +424,17 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
case NodeTypeBlock: case NodeTypeBlock:
case NodeTypeExternBlock: case NodeTypeExternBlock:
case NodeTypeDirective: case NodeTypeDirective:
case NodeTypeUse:
zig_unreachable(); zig_unreachable();
} }
zig_unreachable(); zig_unreachable();
} }
static void gen_block(CodeGen *g, AstNode *block_node, bool add_implicit_return) { static void gen_block(CodeGen *g, ImportTableEntry *import, AstNode *block_node, bool add_implicit_return) {
assert(block_node->type == NodeTypeBlock); assert(block_node->type == NodeTypeBlock);
LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder, g->block_scopes.last(), LLVMZigDILexicalBlock *di_block = LLVMZigCreateLexicalBlock(g->dbuilder, g->block_scopes.last(),
g->di_file, block_node->line + 1, block_node->column + 1); import->di_file, block_node->line + 1, block_node->column + 1);
g->block_scopes.append(LLVMZigLexicalBlockToScope(di_block)); g->block_scopes.append(LLVMZigLexicalBlockToScope(di_block));
add_debug_source_node(g, block_node); add_debug_source_node(g, block_node);
@ -466,22 +466,11 @@ static LLVMZigDISubroutineType *create_di_function_type(CodeGen *g, AstNodeFnPro
return LLVMZigCreateSubroutineType(g->dbuilder, di_file, types, types_len, 0); return LLVMZigCreateSubroutineType(g->dbuilder, di_file, types, types_len, 0);
} }
void code_gen(CodeGen *g) { static void do_code_gen(CodeGen *g) {
assert(!g->errors.length); assert(!g->errors.length);
Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING);
bool is_optimized = g->build_type == CodeGenBuildTypeRelease;
const char *flags = "";
unsigned runtime_version = 0;
g->compile_unit = LLVMZigCreateCompileUnit(g->dbuilder, LLVMZigLang_DW_LANG_C99(),
buf_ptr(&g->in_file), buf_ptr(&g->in_dir),
buf_ptr(producer), is_optimized, flags, runtime_version,
"", 0, !g->strip_debug_symbols);
g->block_scopes.append(LLVMZigCompileUnitToScope(g->compile_unit)); g->block_scopes.append(LLVMZigCompileUnitToScope(g->compile_unit));
g->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&g->in_file), buf_ptr(&g->in_dir));
// Generate function prototypes // Generate function prototypes
auto it = g->fn_table.entry_iterator(); auto it = g->fn_table.entry_iterator();
@ -523,6 +512,7 @@ void code_gen(CodeGen *g) {
// Generate function definitions. // Generate function definitions.
for (int i = 0; i < g->fn_defs.length; i += 1) { for (int i = 0; i < g->fn_defs.length; i += 1) {
FnTableEntry *fn_table_entry = g->fn_defs.at(i); FnTableEntry *fn_table_entry = g->fn_defs.at(i);
ImportTableEntry *import = fn_table_entry->import_entry;
AstNode *fn_def_node = fn_table_entry->fn_def_node; AstNode *fn_def_node = fn_table_entry->fn_def_node;
LLVMValueRef fn = fn_table_entry->fn_value; LLVMValueRef fn = fn_table_entry->fn_value;
g->cur_fn = fn_table_entry; g->cur_fn = fn_table_entry;
@ -532,14 +522,15 @@ void code_gen(CodeGen *g) {
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto; AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
// Add debug info. // Add debug info.
LLVMZigDIScope *fn_scope = LLVMZigFileToScope(g->di_file); LLVMZigDIScope *fn_scope = LLVMZigFileToScope(import->di_file);
unsigned line_number = fn_def_node->line + 1; unsigned line_number = fn_def_node->line + 1;
unsigned scope_line = line_number; unsigned scope_line = line_number;
bool is_definition = true; bool is_definition = true;
unsigned flags = 0; unsigned flags = 0;
bool is_optimized = g->build_type == CodeGenBuildTypeRelease;
LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder, LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder,
fn_scope, buf_ptr(&fn_proto->name), "", g->di_file, line_number, fn_scope, buf_ptr(&fn_proto->name), "", import->di_file, line_number,
create_di_function_type(g, fn_proto, g->di_file), fn_table_entry->internal_linkage, create_di_function_type(g, fn_proto, import->di_file), fn_table_entry->internal_linkage,
is_definition, scope_line, flags, is_optimized, fn); is_definition, scope_line, flags, is_optimized, fn);
g->block_scopes.append(LLVMZigSubprogramToScope(subprogram)); g->block_scopes.append(LLVMZigSubprogramToScope(subprogram));
@ -555,7 +546,7 @@ void code_gen(CodeGen *g) {
LLVMGetParams(fn, codegen_fn_def->params); LLVMGetParams(fn, codegen_fn_def->params);
bool add_implicit_return = codegen_fn_def->add_implicit_return; bool add_implicit_return = codegen_fn_def->add_implicit_return;
gen_block(g, fn_def_node->data.fn_def.body, add_implicit_return); gen_block(g, import, fn_def_node->data.fn_def.body, add_implicit_return);
g->block_scopes.pop(); g->block_scopes.pop();
} }
@ -563,7 +554,9 @@ void code_gen(CodeGen *g) {
LLVMZigDIBuilderFinalize(g->dbuilder); LLVMZigDIBuilderFinalize(g->dbuilder);
LLVMDumpModule(g->module); if (g->verbose) {
LLVMDumpModule(g->module);
}
// in release mode, we're sooooo confident that we've generated correct ir, // in release mode, we're sooooo confident that we've generated correct ir,
// that we skip the verify module step in order to get better performance. // that we skip the verify module step in order to get better performance.
@ -573,13 +566,168 @@ void code_gen(CodeGen *g) {
#endif #endif
} }
void code_gen_optimize(CodeGen *g) { static void define_primitive_types(CodeGen *g) {
LLVMZigOptimizeModule(g->target_machine, g->module); {
LLVMDumpModule(g->module); TypeTableEntry *entry = allocate<TypeTableEntry>(1);
entry->type_ref = LLVMInt8Type();
buf_init_from_str(&entry->name, "u8");
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 8, 8,
LLVMZigEncoding_DW_ATE_unsigned());
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_u8 = entry;
}
{
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
entry->type_ref = LLVMInt32Type();
buf_init_from_str(&entry->name, "i32");
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 32, 32,
LLVMZigEncoding_DW_ATE_signed());
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_i32 = entry;
}
{
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
entry->type_ref = LLVMVoidType();
buf_init_from_str(&entry->name, "void");
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name), 0, 0,
LLVMZigEncoding_DW_ATE_unsigned());
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_void = entry;
// invalid types are void
g->builtin_types.entry_invalid = entry;
}
{
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
entry->type_ref = LLVMVoidType();
buf_init_from_str(&entry->name, "unreachable");
entry->di_type = g->builtin_types.entry_invalid->di_type;
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_unreachable = entry;
}
} }
ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g) {
return &g->errors;
static void init(CodeGen *g, Buf *source_path) {
LLVMInitializeAllTargets();
LLVMInitializeAllTargetMCs();
LLVMInitializeAllAsmPrinters();
LLVMInitializeAllAsmParsers();
LLVMInitializeNativeTarget();
g->is_native_target = true;
char *native_triple = LLVMGetDefaultTargetTriple();
LLVMTargetRef target_ref;
char *err_msg = nullptr;
if (LLVMGetTargetFromTriple(native_triple, &target_ref, &err_msg)) {
zig_panic("unable to get target from triple: %s", err_msg);
}
char *native_cpu = LLVMZigGetHostCPUName();
char *native_features = LLVMZigGetNativeFeatures();
LLVMCodeGenOptLevel opt_level = (g->build_type == CodeGenBuildTypeDebug) ?
LLVMCodeGenLevelNone : LLVMCodeGenLevelAggressive;
LLVMRelocMode reloc_mode = g->is_static ? LLVMRelocStatic : LLVMRelocPIC;
g->target_machine = LLVMCreateTargetMachine(target_ref, native_triple,
native_cpu, native_features, opt_level, reloc_mode, LLVMCodeModelDefault);
g->target_data_ref = LLVMGetTargetMachineData(g->target_machine);
g->module = LLVMModuleCreateWithName("ZigModule");
g->pointer_size_bytes = LLVMPointerSize(g->target_data_ref);
g->builder = LLVMCreateBuilder();
g->dbuilder = LLVMZigCreateDIBuilder(g->module, true);
define_primitive_types(g);
Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING);
bool is_optimized = g->build_type == CodeGenBuildTypeRelease;
const char *flags = "";
unsigned runtime_version = 0;
g->compile_unit = LLVMZigCreateCompileUnit(g->dbuilder, LLVMZigLang_DW_LANG_C99(),
buf_ptr(source_path), buf_ptr(g->root_source_dir),
buf_ptr(producer), is_optimized, flags, runtime_version,
"", 0, !g->strip_debug_symbols);
}
void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code) {
if (!g->initialized) {
g->initialized = true;
init(g, source_path);
}
Buf full_path = BUF_INIT;
os_path_join(g->root_source_dir, source_path, &full_path);
Buf dirname = BUF_INIT;
Buf basename = BUF_INIT;
os_path_split(&full_path, &dirname, &basename);
if (g->verbose) {
fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(source_path));
fprintf(stderr, "----------------\n");
fprintf(stderr, "%s\n", buf_ptr(source_code));
fprintf(stderr, "\nTokens:\n");
fprintf(stderr, "---------\n");
}
ZigList<Token> *tokens = tokenize(source_code);
if (g->verbose) {
print_tokens(source_code, tokens);
fprintf(stderr, "\nAST:\n");
fprintf(stderr, "------\n");
}
ImportTableEntry *import_entry = allocate<ImportTableEntry>(1);
import_entry->root = ast_parse(source_code, tokens);
assert(import_entry->root);
if (g->verbose) {
ast_print(import_entry->root, 0);
fprintf(stderr, "\nSemantic Analysis:\n");
fprintf(stderr, "--------------------\n");
}
import_entry->path = source_path;
import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(&basename), buf_ptr(&dirname));
g->import_table.put(source_path, import_entry);
semantic_analyze(g, import_entry);
if (g->errors.length == 0) {
if (g->verbose) {
fprintf(stderr, "OK\n");
}
} else {
for (int i = 0; i < g->errors.length; i += 1) {
ErrorMsg *err = &g->errors.at(i);
fprintf(stderr, "Error: Line %d, column %d: %s\n",
err->line_start + 1, err->column_start + 1,
buf_ptr(err->msg));
}
exit(1);
}
if (g->verbose) {
fprintf(stderr, "\nCode Generation:\n");
fprintf(stderr, "------------------\n");
}
do_code_gen(g);
} }
static Buf *to_c_type(CodeGen *g, AstNode *type_node) { static Buf *to_c_type(CodeGen *g, AstNode *type_node) {
@ -601,15 +749,15 @@ static Buf *to_c_type(CodeGen *g, AstNode *type_node) {
} }
static void generate_h_file(CodeGen *g) { static void generate_h_file(CodeGen *g) {
Buf *h_file_out_path = buf_sprintf("%s.h", buf_ptr(g->out_name)); Buf *h_file_out_path = buf_sprintf("%s.h", buf_ptr(g->root_out_name));
FILE *out_h = fopen(buf_ptr(h_file_out_path), "wb"); FILE *out_h = fopen(buf_ptr(h_file_out_path), "wb");
if (!out_h) if (!out_h)
zig_panic("unable to open %s: %s", buf_ptr(h_file_out_path), strerror(errno)); zig_panic("unable to open %s: %s", buf_ptr(h_file_out_path), strerror(errno));
Buf *export_macro = buf_sprintf("%s_EXPORT", buf_ptr(g->out_name)); Buf *export_macro = buf_sprintf("%s_EXPORT", buf_ptr(g->root_out_name));
buf_upcase(export_macro); buf_upcase(export_macro);
Buf *extern_c_macro = buf_sprintf("%s_EXTERN_C", buf_ptr(g->out_name)); Buf *extern_c_macro = buf_sprintf("%s_EXTERN_C", buf_ptr(g->root_out_name));
buf_upcase(extern_c_macro); buf_upcase(extern_c_macro);
Buf h_buf = BUF_INIT; Buf h_buf = BUF_INIT;
@ -644,7 +792,8 @@ static void generate_h_file(CodeGen *g) {
} }
} }
Buf *ifdef_dance_name = buf_sprintf("%s_%s_H", buf_ptr(g->out_name), buf_ptr(g->out_name)); Buf *ifdef_dance_name = buf_sprintf("%s_%s_H",
buf_ptr(g->root_out_name), buf_ptr(g->root_out_name));
buf_upcase(ifdef_dance_name); buf_upcase(ifdef_dance_name);
fprintf(out_h, "#ifndef %s\n", buf_ptr(ifdef_dance_name)); fprintf(out_h, "#ifndef %s\n", buf_ptr(ifdef_dance_name));
@ -677,9 +826,27 @@ static void generate_h_file(CodeGen *g) {
zig_panic("unable to close h file: %s", strerror(errno)); zig_panic("unable to close h file: %s", strerror(errno));
} }
void code_gen_link(CodeGen *g, const char *out_file) { void codegen_link(CodeGen *g, const char *out_file) {
bool is_optimized = (g->build_type == CodeGenBuildTypeRelease);
if (is_optimized) {
if (g->verbose) {
fprintf(stderr, "\nOptimization:\n");
fprintf(stderr, "---------------\n");
}
LLVMZigOptimizeModule(g->target_machine, g->module);
if (g->verbose) {
LLVMDumpModule(g->module);
}
}
if (g->verbose) {
fprintf(stderr, "\nLink:\n");
fprintf(stderr, "-------\n");
}
if (!out_file) { if (!out_file) {
out_file = buf_ptr(g->out_name); out_file = buf_ptr(g->root_out_name);
} }
Buf out_file_o = BUF_INIT; Buf out_file_o = BUF_INIT;
@ -728,8 +895,8 @@ void code_gen_link(CodeGen *g, const char *out_file) {
if (g->out_type == OutTypeLib) { if (g->out_type == OutTypeLib) {
Buf *out_lib_so = buf_sprintf("lib%s.so.%d.%d.%d", 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_ptr(g->root_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); Buf *soname = buf_sprintf("lib%s.so.%d", buf_ptr(g->root_out_name), g->version_major);
args.append("-shared"); args.append("-shared");
args.append("-soname"); args.append("-soname");
args.append(buf_ptr(soname)); args.append(buf_ptr(soname));
@ -756,4 +923,8 @@ void code_gen_link(CodeGen *g, const char *out_file) {
if (g->out_type == OutTypeLib) { if (g->out_type == OutTypeLib) {
generate_h_file(g); generate_h_file(g);
} }
if (g->verbose) {
fprintf(stderr, "OK\n");
}
} }

View File

@ -29,7 +29,7 @@ struct ErrorMsg {
}; };
CodeGen *create_codegen(AstNode *root, Buf *in_file); CodeGen *codegen_create(Buf *root_source_dir);
enum CodeGenBuildType { enum CodeGenBuildType {
CodeGenBuildTypeDebug, CodeGenBuildTypeDebug,
@ -38,15 +38,12 @@ enum CodeGenBuildType {
void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type); void codegen_set_build_type(CodeGen *codegen, CodeGenBuildType build_type);
void codegen_set_is_static(CodeGen *codegen, bool is_static); void codegen_set_is_static(CodeGen *codegen, bool is_static);
void codegen_set_strip(CodeGen *codegen, bool strip); void codegen_set_strip(CodeGen *codegen, bool strip);
void codegen_set_verbose(CodeGen *codegen, bool verbose);
void codegen_set_out_type(CodeGen *codegen, OutType out_type); void codegen_set_out_type(CodeGen *codegen, OutType out_type);
void codegen_set_out_name(CodeGen *codegen, Buf *out_name); void codegen_set_out_name(CodeGen *codegen, Buf *out_name);
void code_gen_optimize(CodeGen *g); void codegen_add_code(CodeGen *g, Buf *source_path, Buf *source_code);
void code_gen(CodeGen *g); void codegen_link(CodeGen *g, const char *out_file);
void code_gen_link(CodeGen *g, const char *out_file);
ZigList<ErrorMsg> *codegen_error_messages(CodeGen *g);
#endif #endif

View File

@ -5,6 +5,7 @@ const char *err_str(int err) {
case ErrorNone: return "(no error)"; 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";
case ErrorSemanticAnalyzeFail: return "semantic analyze failed";
} }
return "(invalid error)"; return "(invalid error)";
} }

View File

@ -12,6 +12,7 @@ enum Error {
ErrorNone, ErrorNone,
ErrorNoMem, ErrorNoMem,
ErrorInvalidFormat, ErrorInvalidFormat,
ErrorSemanticAnalyzeFail,
}; };
const char *err_str(int err); const char *err_str(int err);

View File

@ -6,25 +6,11 @@
*/ */
#include "config.h" #include "config.h"
#include "util.hpp"
#include "list.hpp"
#include "buffer.hpp" #include "buffer.hpp"
#include "parser.hpp"
#include "tokenizer.hpp"
#include "error.hpp"
#include "codegen.hpp" #include "codegen.hpp"
#include "analyze.hpp" #include "os.hpp"
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <stdint.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <inttypes.h>
static int usage(const char *arg0) { static int usage(const char *arg0) {
fprintf(stderr, "Usage: %s [command] [options] target\n" fprintf(stderr, "Usage: %s [command] [options] target\n"
@ -38,6 +24,7 @@ static int usage(const char *arg0) {
" --export [exe|lib|obj] override output type\n" " --export [exe|lib|obj] override output type\n"
" --name [name] override output name\n" " --name [name] override output name\n"
" --output [file] override destination path\n" " --output [file] override destination path\n"
" --verbose turn on compiler debug output\n"
, arg0); , arg0);
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@ -47,98 +34,47 @@ static int version(void) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static Buf *fetch_file(FILE *f) { struct Build {
int fd = fileno(f); const char *in_file;
struct stat st; const char *out_file;
if (fstat(fd, &st)) bool release;
zig_panic("unable to stat file: %s", strerror(errno)); bool strip;
off_t big_size = st.st_size; bool is_static;
if (big_size > INT_MAX) OutType out_type;
zig_panic("file too big"); const char *out_name;
int size = (int)big_size; bool verbose;
};
Buf *buf = buf_alloc_fixed(size); static int build(const char *arg0, Build *b) {
size_t amt_read = fread(buf_ptr(buf), 1, buf_len(buf), f); if (!b->in_file)
if (amt_read != (size_t)buf_len(buf))
zig_panic("error reading: %s", strerror(errno));
return buf;
}
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)
return usage(arg0); return usage(arg0);
FILE *in_f; Buf in_file_buf = BUF_INIT;
if (strcmp(in_file, "-") == 0) { buf_init_from_str(&in_file_buf, b->in_file);
in_f = stdin;
char *result = getcwd(cur_dir, sizeof(cur_dir)); Buf root_source_dir = BUF_INIT;
if (!result) Buf root_source_code = BUF_INIT;
zig_panic("unable to get current working directory: %s", strerror(errno)); Buf root_source_name = BUF_INIT;
if (buf_eql_str(&in_file_buf, "-")) {
os_get_cwd(&root_source_dir);
os_fetch_file(stdin, &root_source_code);
buf_init_from_str(&root_source_name, "");
} else { } else {
in_f = fopen(in_file, "rb"); os_path_split(&in_file_buf, &root_source_dir, &root_source_name);
if (!in_f) os_fetch_file_path(buf_create_from_str(b->in_file), &root_source_code);
zig_panic("unable to open %s for reading: %s\n", in_file, strerror(errno));
} }
fprintf(stderr, "Original source:\n"); CodeGen *g = codegen_create(&root_source_dir);
fprintf(stderr, "----------------\n"); codegen_set_build_type(g, b->release ? CodeGenBuildTypeRelease : CodeGenBuildTypeDebug);
Buf *in_data = fetch_file(in_f); codegen_set_strip(g, b->strip);
fprintf(stderr, "%s\n", buf_ptr(in_data)); codegen_set_is_static(g, b->is_static);
if (b->out_type != OutTypeUnknown)
fprintf(stderr, "\nTokens:\n"); codegen_set_out_type(g, b->out_type);
fprintf(stderr, "---------\n"); if (b->out_name)
ZigList<Token> *tokens = tokenize(in_data); codegen_set_out_name(g, buf_create_from_str(b->out_name));
print_tokens(in_data, tokens); codegen_set_verbose(g, b->verbose);
codegen_add_code(g, &root_source_name, &root_source_code);
fprintf(stderr, "\nAST:\n"); codegen_link(g, b->out_file);
fprintf(stderr, "------\n");
AstNode *root = ast_parse(in_data, tokens);
assert(root);
ast_print(root, 0);
fprintf(stderr, "\nSemantic Analysis:\n");
fprintf(stderr, "--------------------\n");
CodeGen *codegen = create_codegen(root, buf_create_from_str(in_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) {
fprintf(stderr, "OK\n");
} else {
for (int i = 0; i < errors->length; i += 1) {
ErrorMsg *err = &errors->at(i);
fprintf(stderr, "Error: Line %d, column %d: %s\n",
err->line_start + 1, err->column_start + 1,
buf_ptr(err->msg));
}
return 1;
}
fprintf(stderr, "\nCode Generation:\n");
fprintf(stderr, "------------------\n");
code_gen(codegen);
if (release) {
fprintf(stderr, "\nOptimization:\n");
fprintf(stderr, "---------------\n");
code_gen_optimize(codegen);
}
fprintf(stderr, "\nLink:\n");
fprintf(stderr, "-------\n");
code_gen_link(codegen, out_file);
fprintf(stderr, "OK\n");
return 0; return 0;
} }
@ -151,43 +87,39 @@ enum Cmd {
int main(int argc, char **argv) { int main(int argc, char **argv) {
char *arg0 = argv[0]; char *arg0 = argv[0];
char *in_file = NULL;
char *out_file = NULL;
bool release = false;
bool strip = false;
bool is_static = false;
OutType out_type = OutTypeUnknown;
char *out_name = NULL;
Build b = {0};
Cmd cmd = CmdNone; Cmd cmd = CmdNone;
for (int i = 1; i < argc; i += 1) { for (int i = 1; i < argc; i += 1) {
char *arg = argv[i]; char *arg = argv[i];
if (arg[0] == '-' && arg[1] == '-') { if (arg[0] == '-' && arg[1] == '-') {
if (strcmp(arg, "--release") == 0) { if (strcmp(arg, "--release") == 0) {
release = true; b.release = true;
} else if (strcmp(arg, "--strip") == 0) { } else if (strcmp(arg, "--strip") == 0) {
strip = true; b.strip = true;
} else if (strcmp(arg, "--static") == 0) { } else if (strcmp(arg, "--static") == 0) {
is_static = true; b.is_static = true;
} else if (strcmp(arg, "--verbose") == 0) {
b.verbose = true;
} else if (i + 1 >= argc) { } else if (i + 1 >= argc) {
return usage(arg0); return usage(arg0);
} else { } else {
i += 1; i += 1;
if (strcmp(arg, "--output") == 0) { if (strcmp(arg, "--output") == 0) {
out_file = argv[i]; b.out_file = argv[i];
} else if (strcmp(arg, "--export") == 0) { } else if (strcmp(arg, "--export") == 0) {
if (strcmp(argv[i], "exe") == 0) { if (strcmp(argv[i], "exe") == 0) {
out_type = OutTypeExe; b.out_type = OutTypeExe;
} else if (strcmp(argv[i], "lib") == 0) { } else if (strcmp(argv[i], "lib") == 0) {
out_type = OutTypeLib; b.out_type = OutTypeLib;
} else if (strcmp(argv[i], "obj") == 0) { } else if (strcmp(argv[i], "obj") == 0) {
out_type = OutTypeObj; b.out_type = OutTypeObj;
} else { } else {
return usage(arg0); return usage(arg0);
} }
} else if (strcmp(arg, "--name") == 0) { } else if (strcmp(arg, "--name") == 0) {
out_name = argv[i]; b.out_name = argv[i];
} else { } else {
return usage(arg0); return usage(arg0);
} }
@ -206,8 +138,8 @@ int main(int argc, char **argv) {
case CmdNone: case CmdNone:
zig_unreachable(); zig_unreachable();
case CmdBuild: case CmdBuild:
if (!in_file) { if (!b.in_file) {
in_file = arg; b.in_file = arg;
} else { } else {
return usage(arg0); return usage(arg0);
} }
@ -222,7 +154,7 @@ int main(int argc, char **argv) {
case CmdNone: case CmdNone:
return usage(arg0); return usage(arg0);
case CmdBuild: case CmdBuild:
return build(arg0, in_file, out_file, release, strip, is_static, out_type, out_name); return build(arg0, &b);
case CmdVersion: case CmdVersion:
return version(); return version();
} }

View File

@ -13,8 +13,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/wait.h> #include <sys/wait.h>
#include <stdio.h>
#include <fcntl.h> #include <fcntl.h>
#include <limits.h>
void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached) { void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached) {
pid_t pid = fork(); pid_t pid = fork();
@ -37,7 +37,7 @@ void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detache
zig_panic("execvp failed: %s", strerror(errno)); zig_panic("execvp failed: %s", strerror(errno));
} }
static void read_all_fd(int fd, Buf *out_buf) { static void read_all_fd_stream(int fd, Buf *out_buf) {
static const ssize_t buf_size = 0x2000; static const ssize_t buf_size = 0x2000;
buf_resize(out_buf, buf_size); buf_resize(out_buf, buf_size);
ssize_t actual_buf_len = 0; ssize_t actual_buf_len = 0;
@ -72,6 +72,12 @@ void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) {
buf_init_from_buf(out_basename, full_path); buf_init_from_buf(out_basename, full_path);
} }
void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path) {
buf_init_from_buf(out_full_path, dirname);
buf_append_char(out_full_path, '/');
buf_append_buf(out_full_path, basename);
}
void os_exec_process(const char *exe, ZigList<const char *> &args, void os_exec_process(const char *exe, ZigList<const char *> &args,
int *return_code, Buf *out_stderr, Buf *out_stdout) int *return_code, Buf *out_stderr, Buf *out_stdout)
{ {
@ -117,8 +123,8 @@ void os_exec_process(const char *exe, ZigList<const char *> &args,
waitpid(pid, return_code, 0); waitpid(pid, return_code, 0);
read_all_fd(stdout_pipe[0], out_stdout); read_all_fd_stream(stdout_pipe[0], out_stdout);
read_all_fd(stderr_pipe[0], out_stderr); read_all_fd_stream(stderr_pipe[0], out_stderr);
} }
} }
@ -133,3 +139,44 @@ void os_write_file(Buf *full_path, Buf *contents) {
if (close(fd) == -1) if (close(fd) == -1)
zig_panic("close failed"); zig_panic("close failed");
} }
int os_fetch_file(FILE *f, Buf *out_contents) {
int fd = fileno(f);
struct stat st;
if (fstat(fd, &st))
zig_panic("unable to stat file: %s", strerror(errno));
off_t big_size = st.st_size;
if (big_size > INT_MAX)
zig_panic("file too big");
int size = (int)big_size;
buf_resize(out_contents, size);
ssize_t ret = read(fd, buf_ptr(out_contents), size);
if (ret != size)
zig_panic("unable to read file: %s", strerror(errno));
return 0;
}
int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
FILE *f = fopen(buf_ptr(full_path), "rb");
if (!f)
zig_panic("unable to open %s: %s\n", buf_ptr(full_path), strerror(errno));
int result = os_fetch_file(f, out_contents);
fclose(f);
return result;
}
int os_get_cwd(Buf *out_cwd) {
int err = ERANGE;
buf_resize(out_cwd, 512);
while (err == ERANGE) {
buf_resize(out_cwd, buf_len(out_cwd) * 2);
err = getcwd(buf_ptr(out_cwd), buf_len(out_cwd)) ? 0 : errno;
}
if (err)
zig_panic("unable to get cwd: %s", strerror(err));
return 0;
}

View File

@ -11,13 +11,22 @@
#include "list.hpp" #include "list.hpp"
#include "buffer.hpp" #include "buffer.hpp"
#include <stdio.h>
void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached); void os_spawn_process(const char *exe, ZigList<const char *> &args, bool detached);
void os_exec_process(const char *exe, ZigList<const char *> &args, void os_exec_process(const char *exe, ZigList<const char *> &args,
int *return_code, Buf *out_stderr, Buf *out_stdout); int *return_code, Buf *out_stderr, Buf *out_stdout);
void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename); void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename);
void os_path_join(Buf *dirname, Buf *basename, Buf *out_full_path);
void os_write_file(Buf *full_path, Buf *contents); void os_write_file(Buf *full_path, Buf *contents);
int os_fetch_file(FILE *file, Buf *out_contents);
int os_fetch_file_path(Buf *full_path, Buf *out_contents);
int os_get_cwd(Buf *out_cwd);
#endif #endif

View File

@ -100,6 +100,8 @@ const char *node_type_str(NodeType node_type) {
return "Symbol"; return "Symbol";
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
return "PrefixOpExpr"; return "PrefixOpExpr";
case NodeTypeUse:
return "Use";
} }
zig_unreachable(); zig_unreachable();
} }
@ -241,6 +243,9 @@ void ast_print(AstNode *node, int indent) {
fprintf(stderr, "PrimaryExpr Symbol %s\n", fprintf(stderr, "PrimaryExpr Symbol %s\n",
buf_ptr(&node->data.symbol)); buf_ptr(&node->data.symbol));
break; break;
case NodeTypeUse:
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.use.path));
break;
} }
} }
@ -1231,7 +1236,36 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b
} }
/* /*
TopLevelDecl : FnDef | ExternBlock | RootExportDecl Use : many(Directive) token(Use) token(String) token(Semicolon)
*/
static AstNode *ast_parse_use(ParseContext *pc, int *token_index, bool mandatory) {
assert(mandatory == false);
Token *use_kw = &pc->tokens->at(*token_index);
if (use_kw->id != TokenIdKeywordUse)
return nullptr;
*token_index += 1;
Token *use_name = &pc->tokens->at(*token_index);
*token_index += 1;
ast_expect_token(pc, use_name, TokenIdStringLiteral);
Token *semicolon = &pc->tokens->at(*token_index);
*token_index += 1;
ast_expect_token(pc, semicolon, TokenIdSemicolon);
AstNode *node = ast_create_node(NodeTypeUse, use_kw);
parse_string_literal(pc, use_name, &node->data.use.path);
node->data.use.directives = pc->directive_list;
pc->directive_list = nullptr;
return node;
}
/*
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use
*/ */
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 (;;) {
@ -1258,6 +1292,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
continue; continue;
} }
AstNode *use_node = ast_parse_use(pc, token_index, false);
if (use_node) {
top_level_decls->append(use_node);
continue;
}
if (pc->directive_list->length > 0) { if (pc->directive_list->length > 0) {
ast_error(directive_token, "invalid directive"); ast_error(directive_token, "invalid directive");
} }

View File

@ -35,6 +35,7 @@ enum NodeType {
NodeTypeSymbol, NodeTypeSymbol,
NodeTypePrefixOpExpr, NodeTypePrefixOpExpr,
NodeTypeFnCallExpr, NodeTypeFnCallExpr,
NodeTypeUse,
}; };
struct AstNodeRoot { struct AstNodeRoot {
@ -158,6 +159,11 @@ struct AstNodePrefixOpExpr {
AstNode *primary_expr; AstNode *primary_expr;
}; };
struct AstNodeUse {
Buf path;
ZigList<AstNode *> *directives;
};
struct AstNode { struct AstNode {
enum NodeType type; enum NodeType type;
AstNode *parent; AstNode *parent;
@ -180,6 +186,7 @@ struct AstNode {
AstNodeCastExpr cast_expr; AstNodeCastExpr cast_expr;
AstNodePrefixOpExpr prefix_op_expr; AstNodePrefixOpExpr prefix_op_expr;
AstNodeFnCallExpr fn_call_expr; AstNodeFnCallExpr fn_call_expr;
AstNodeUse use;
Buf number; Buf number;
Buf string; Buf string;
Buf symbol; Buf symbol;

View File

@ -12,15 +12,6 @@
#include "hash_map.hpp" #include "hash_map.hpp"
#include "zig_llvm.hpp" #include "zig_llvm.hpp"
struct FnTableEntry {
LLVMValueRef fn_value;
AstNode *proto_node;
AstNode *fn_def_node;
bool is_extern;
bool internal_linkage;
unsigned calling_convention;
};
struct TypeTableEntry { struct TypeTableEntry {
LLVMTypeRef type_ref; LLVMTypeRef type_ref;
LLVMZigDIType *di_type; LLVMZigDIType *di_type;
@ -33,17 +24,35 @@ struct TypeTableEntry {
TypeTableEntry *pointer_mut_parent; TypeTableEntry *pointer_mut_parent;
}; };
struct ImportTableEntry {
AstNode *root;
Buf *path; // relative to root_source_dir
LLVMZigDIFile *di_file;
};
struct FnTableEntry {
LLVMValueRef fn_value;
AstNode *proto_node;
AstNode *fn_def_node;
bool is_extern;
bool internal_linkage;
unsigned calling_convention;
ImportTableEntry *import_entry;
};
struct CodeGen { struct CodeGen {
LLVMModuleRef module; LLVMModuleRef module;
AstNode *root;
ZigList<ErrorMsg> errors; ZigList<ErrorMsg> errors;
LLVMBuilderRef builder; LLVMBuilderRef builder;
LLVMZigDIBuilder *dbuilder; LLVMZigDIBuilder *dbuilder;
LLVMZigDICompileUnit *compile_unit; LLVMZigDICompileUnit *compile_unit;
// reminder: hash tables must be initialized before use
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table; HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table; HashMap<Buf *, LLVMValueRef, buf_hash, buf_eql_buf> str_table;
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table; HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table; HashMap<Buf *, bool, buf_hash, buf_eql_buf> link_table;
HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
struct { struct {
TypeTableEntry *entry_u8; TypeTableEntry *entry_u8;
@ -60,12 +69,10 @@ struct CodeGen {
CodeGenBuildType build_type; CodeGenBuildType build_type;
LLVMTargetMachineRef target_machine; LLVMTargetMachineRef target_machine;
bool is_native_target; bool is_native_target;
Buf in_file; Buf *root_source_dir;
Buf in_dir; Buf *root_out_name;
ZigList<LLVMZigDIScope *> block_scopes; ZigList<LLVMZigDIScope *> block_scopes;
LLVMZigDIFile *di_file;
ZigList<FnTableEntry *> fn_defs; ZigList<FnTableEntry *> fn_defs;
Buf *out_name;
OutType out_type; OutType out_type;
FnTableEntry *cur_fn; FnTableEntry *cur_fn;
bool c_stdint_used; bool c_stdint_used;
@ -73,6 +80,8 @@ struct CodeGen {
int version_major; int version_major;
int version_minor; int version_minor;
int version_patch; int version_patch;
bool verbose;
bool initialized;
}; };
struct TypeNode { struct TypeNode {

View File

@ -180,6 +180,8 @@ static void end_token(Tokenize *t) {
t->cur_tok->id = TokenIdKeywordExport; t->cur_tok->id = TokenIdKeywordExport;
} else if (mem_eql_str(token_mem, token_len, "as")) { } else if (mem_eql_str(token_mem, token_len, "as")) {
t->cur_tok->id = TokenIdKeywordAs; t->cur_tok->id = TokenIdKeywordAs;
} else if (mem_eql_str(token_mem, token_len, "use")) {
t->cur_tok->id = TokenIdKeywordUse;
} }
t->cur_tok = nullptr; t->cur_tok = nullptr;
@ -562,6 +564,7 @@ static const char * token_name(Token *token) {
case TokenIdKeywordPub: return "Pub"; case TokenIdKeywordPub: return "Pub";
case TokenIdKeywordExport: return "Export"; case TokenIdKeywordExport: return "Export";
case TokenIdKeywordAs: return "As"; case TokenIdKeywordAs: return "As";
case TokenIdKeywordUse: return "Use";
case TokenIdLParen: return "LParen"; case TokenIdLParen: return "LParen";
case TokenIdRParen: return "RParen"; case TokenIdRParen: return "RParen";
case TokenIdComma: return "Comma"; case TokenIdComma: return "Comma";

View File

@ -22,6 +22,7 @@ enum TokenId {
TokenIdKeywordPub, TokenIdKeywordPub,
TokenIdKeywordExport, TokenIdKeywordExport,
TokenIdKeywordAs, TokenIdKeywordAs,
TokenIdKeywordUse,
TokenIdLParen, TokenIdLParen,
TokenIdRParen, TokenIdRParen,
TokenIdComma, TokenIdComma,

View File

@ -47,6 +47,7 @@ static void add_simple_case(const char *case_name, const char *source, const cha
test_case->compiler_args.append(tmp_exe_path); test_case->compiler_args.append(tmp_exe_path);
test_case->compiler_args.append("--release"); test_case->compiler_args.append("--release");
test_case->compiler_args.append("--strip"); test_case->compiler_args.append("--strip");
test_case->compiler_args.append("--verbose");
test_cases.append(test_case); test_cases.append(test_case);
} }
@ -70,6 +71,7 @@ static void add_compile_fail_case(const char *case_name, const char *source, int
test_case->compiler_args.append(tmp_exe_path); test_case->compiler_args.append(tmp_exe_path);
test_case->compiler_args.append("--release"); test_case->compiler_args.append("--release");
test_case->compiler_args.append("--strip"); test_case->compiler_args.append("--strip");
test_case->compiler_args.append("--verbose");
test_cases.append(test_case); test_cases.append(test_case);