mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
refactor code to prepare for multiple files
verbose compiler output is now behind --verbose flag
This commit is contained in:
parent
ef482ece7c
commit
55b8472374
@ -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
|
||||||
|
|||||||
@ -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)
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
5
example/multiple_files/foo.zig
Normal file
5
example/multiple_files/foo.zig
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
use "libc.zig";
|
||||||
|
|
||||||
|
fn print_text() {
|
||||||
|
puts("it works!");
|
||||||
|
}
|
||||||
5
example/multiple_files/libc.zig
Normal file
5
example/multiple_files/libc.zig
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
#link("c")
|
||||||
|
extern {
|
||||||
|
fn puts(s: *mut u8) -> i32;
|
||||||
|
fn exit(code: i32) -> unreachable;
|
||||||
|
}
|
||||||
9
example/multiple_files/main.zig
Normal file
9
example/multiple_files/main.zig
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
export executable "test";
|
||||||
|
|
||||||
|
use "libc.zig";
|
||||||
|
use "foo.zig";
|
||||||
|
|
||||||
|
fn _start() -> unreachable {
|
||||||
|
print_text();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
7
example/shared_library/test.c
Normal file
7
example/shared_library/test.c
Normal 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;
|
||||||
|
}
|
||||||
105
src/analyze.cpp
105
src/analyze.cpp
@ -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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
255
src/codegen.cpp
255
src/codegen.cpp
@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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)";
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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);
|
||||||
|
|||||||
172
src/main.cpp
172
src/main.cpp
@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
55
src/os.cpp
55
src/os.cpp
@ -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;
|
||||||
|
}
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
||||||
|
|||||||
@ -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 {
|
||||||
|
|||||||
@ -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";
|
||||||
|
|||||||
@ -22,6 +22,7 @@ enum TokenId {
|
|||||||
TokenIdKeywordPub,
|
TokenIdKeywordPub,
|
||||||
TokenIdKeywordExport,
|
TokenIdKeywordExport,
|
||||||
TokenIdKeywordAs,
|
TokenIdKeywordAs,
|
||||||
|
TokenIdKeywordUse,
|
||||||
TokenIdLParen,
|
TokenIdLParen,
|
||||||
TokenIdRParen,
|
TokenIdRParen,
|
||||||
TokenIdComma,
|
TokenIdComma,
|
||||||
|
|||||||
@ -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);
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user