rewrite how importing works

* Introduce the concept of packages. Closes #3
 * Add support for error notes.
 * Introduce `@import` and `@c_import` builtin functions and
   remove the `import` and `c_import` top level declarations.
 * Introduce the `use` top level declaration.
 * Add `--check-unused` parameter to perform semantic
   analysis and codegen on all top level declarations, not
   just exported ones and ones referenced by exported ones.
 * Delete the root export node and add `--library` argument.
This commit is contained in:
Andrew Kelley 2016-02-27 22:06:46 -07:00
parent 28fe994a10
commit f1d338194e
31 changed files with 1461 additions and 1835 deletions

View File

@ -137,12 +137,13 @@ set(ZIG_STD_SRC
"${CMAKE_SOURCE_DIR}/std/test_runner.zig"
"${CMAKE_SOURCE_DIR}/std/test_runner_libc.zig"
"${CMAKE_SOURCE_DIR}/std/test_runner_nolibc.zig"
"${CMAKE_SOURCE_DIR}/std/std.zig"
"${CMAKE_SOURCE_DIR}/std/io.zig"
"${CMAKE_SOURCE_DIR}/std/os.zig"
"${CMAKE_SOURCE_DIR}/std/syscall.zig"
"${CMAKE_SOURCE_DIR}/std/errno.zig"
"${CMAKE_SOURCE_DIR}/std/rand.zig"
"${CMAKE_SOURCE_DIR}/std/math.zig"
"${CMAKE_SOURCE_DIR}/std/index.zig"
)

View File

@ -5,9 +5,7 @@
```
Root = many(TopLevelDecl) "EOF"
TopLevelDecl = many(Directive) option(VisibleMod) (FnDef | ExternDecl | RootExportDecl | Import | ContainerDecl | GlobalVarDecl | ErrorValueDecl | CImportDecl | TypeDecl)
CImportDecl = "c_import" Block
TopLevelDecl = many(Directive) option(VisibleMod) (FnDef | ExternDecl | ContainerDecl | GlobalVarDecl | ErrorValueDecl | TypeDecl | UseDecl)
TypeDecl = "type" "Symbol" "=" TypeExpr ";"
@ -23,9 +21,7 @@ StructMember = many(Directive) option(VisibleMod) (StructField | FnDef)
StructField = "Symbol" option(":" Expression) ",")
Import = "import" "String" ";"
RootExportDecl = "export" "Symbol" "String" ";"
UseDecl = "use" Expression ";"
ExternDecl = "extern" (FnProto | VariableDeclaration) ";"

75
doc/semantic_analysis.md Normal file
View File

@ -0,0 +1,75 @@
# How Semantic Analysis Works
We start with a set of files. Typically the user only has one entry point file,
which imports the other files they want to use. However, the compiler may
choose to add more files to the compilation, for example bootstrap.zig which
contains the code that calls main.
Our goal now is to treat everything that is marked with the `export` keyword
as a root node, and then then parse and semantically analyze as little as
possible in order to fulfill these exports.
So, some parts of the code very well may have uncaught semantic errors, but as
long as the code is not referenced in any way, the compiler will not complain
because the code may as well not exist. This is similar to the fact that code
excluded from compilation with an `#ifdef` in C is not analyzed. Avoiding
analyzing unused code will save compilation time - one of Zig's goals.
So, for each file, we iterate over the top level declarations. The set of top
level declarations are:
* Function Definition
* Global Variable Declaration
* Container Declaration (struct or enum)
* Type Declaration
* Error Value Declaration
* Use Declaration
Each of these can have `export` attached to them except for error value
declarations and use declarations.
When we see a top level declaration during this iteration, we determine its
unique name identifier within the file. For example, for a function definition,
the unique name identifier is simply its name. Using this name we add the top
level declaration to a map.
If the top level declaration is exported, we add it to a set of exported top
level identifiers.
If the top level declaration is a use declaration, we add it to a set of use
declarations.
If the top level declaration is an error value declaration, we assign it a value
and increment the count of error values.
After this preliminary iteration over the top level declarations, we iterate
over the use declarations and resolve them. To resolve a use declaration, we
analyze the associated expression, verify that its type is the namespace type,
and then add all the items from the namespace into the top level declaration
map for the current file.
To analyze an expression, we recurse the abstract syntax tree of the
expression. Whenever we must look up a symbol, if the symbol exists already,
we can use it. Otherwise, we look it up in the top level declaration map.
If it exists, we can use it. Otherwise, we interrupt resolving this use
declaration to resolve the next one. If a dependency loop is detected, emit
an error. If all use declarations are resolved yet the symbol we need still
does not exist, emit an error.
To analyze an `@import` expression, find the referenced file, parse it, and
add it to the set of files to perform semantic analysis on.
Proceed through the rest of the use declarations the same way.
If we make it through the use declarations without an error, then we have a
complete map of all globals that exist in the current file.
Next we iterate over the set of exported top level declarations.
If it's a function definition, add it to the set of exported function
definitions and resolve the function prototype only. Otherwise, resolve the
top level declaration completely. This may involve recursively resolving other
top level declarations that expressions depend on.
Finally, iterate over the set of exported function definitions and analyze the
bodies.

View File

@ -8,7 +8,7 @@ How to pass a byvalue struct parameter in the C calling convention is
target-specific. Add logic for how to do function prototypes and function calls
for the target when an exported or external function has a byvalue struct.
Write the target-specific code in std.zig.
Write the target-specific code in the standard library.
Update the C integer types to be the correct size for the target.

View File

@ -14,7 +14,7 @@ syn keyword zigConditional if else switch
syn keyword zigRepeat while for
syn keyword zigConstant null undefined
syn keyword zigKeyword fn import c_import
syn keyword zigKeyword fn use
syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 void unreachable type error
syn keyword zigType c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong

View File

@ -1,39 +1,38 @@
export executable "guess_number";
import "std.zig";
import "rand.zig";
import "os.zig";
const std = @import("std");
const io = std.io;
const Rand = std.Rand;
const os = std.os;
pub fn main(args: [][]u8) -> %void {
%%stdout.printf("Welcome to the Guess Number Game in Zig.\n");
%%io.stdout.printf("Welcome to the Guess Number Game in Zig.\n");
var seed : u32 = undefined;
const seed_bytes = (&u8)(&seed)[0...4];
%%os_get_random_bytes(seed_bytes);
%%os.get_random_bytes(seed_bytes);
var rand = rand_new(seed);
var rand = Rand.init(seed);
const answer = rand.range_u64(0, 100) + 1;
while (true) {
%%stdout.printf("\nGuess a number between 1 and 100: ");
%%io.stdout.printf("\nGuess a number between 1 and 100: ");
var line_buf : [20]u8 = undefined;
const line_len = stdin.read(line_buf) %% |err| {
%%stdout.printf("Unable to read from stdin.\n");
const line_len = io.stdin.read(line_buf) %% |err| {
%%io.stdout.printf("Unable to read from stdin.\n");
return err;
};
const guess = parse_u64(line_buf[0...line_len - 1], 10) %% {
%%stdout.printf("Invalid number.\n");
const guess = io.parse_u64(line_buf[0...line_len - 1], 10) %% {
%%io.stdout.printf("Invalid number.\n");
continue;
};
if (guess > answer) {
%%stdout.printf("Guess lower.\n");
%%io.stdout.printf("Guess lower.\n");
} else if (guess < answer) {
%%stdout.printf("Guess higher.\n");
%%io.stdout.printf("Guess higher.\n");
} else {
%%stdout.printf("You win!\n");
%%io.stdout.printf("You win!\n");
return;
}
}

View File

@ -1,7 +1,5 @@
export executable "hello";
import "std.zig";
const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
%%stdout.printf("Hello, world!\n");
%%io.stdout.printf("Hello, world!\n");
}

View File

@ -1,11 +1,6 @@
#link("c")
export executable "hello";
c_import {
@c_include("stdio.h");
}
const c = @c_import(@c_include("stdio.h"));
export fn main(argc: c_int, argv: &&u8) -> c_int {
printf(c"Hello, world!\n");
c.printf(c"Hello, world!\n");
return 0;
}

View File

@ -76,6 +76,7 @@ struct ConstExprValue {
ConstStructValue x_struct;
ConstArrayValue x_array;
ConstPtrValue x_ptr;
ImportTableEntry *x_import;
} data;
};
@ -91,6 +92,7 @@ enum ReturnKnowledge {
struct Expr {
TypeTableEntry *type_entry;
ReturnKnowledge return_knowledge;
VariableTableEntry *variable;
LLVMValueRef const_llvm_val;
ConstExprValue const_val;
@ -103,13 +105,30 @@ struct StructValExprCodeGen {
AstNode *source_node;
};
enum VisibMod {
VisibModPrivate,
VisibModPub,
VisibModExport,
};
enum TldResolution {
TldResolutionUnresolved,
TldResolutionInvalid,
TldResolutionOk,
};
struct TopLevelDecl {
// reminder: hash tables must be initialized before use
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> deps;
// populated by parser
Buf *name;
ZigList<AstNode *> *directives;
VisibMod visib_mod;
// populated by semantic analyzer
ImportTableEntry *import;
// set this flag temporarily to detect infinite loops
bool in_current_deps;
bool dep_loop_flag;
TldResolution resolution;
AstNode *parent_decl;
};
struct TypeEnumField {
@ -120,7 +139,6 @@ struct TypeEnumField {
enum NodeType {
NodeTypeRoot,
NodeTypeRootExportDecl,
NodeTypeFnProto,
NodeTypeFnDef,
NodeTypeFnDecl,
@ -143,8 +161,7 @@ enum NodeType {
NodeTypeArrayAccessExpr,
NodeTypeSliceExpr,
NodeTypeFieldAccessExpr,
NodeTypeImport,
NodeTypeCImport,
NodeTypeUse,
NodeTypeBoolLiteral,
NodeTypeNullLiteral,
NodeTypeUndefinedLiteral,
@ -173,15 +190,8 @@ struct AstNodeRoot {
ZigList<AstNode *> top_level_decls;
};
enum VisibMod {
VisibModPrivate,
VisibModPub,
VisibModExport,
};
struct AstNodeFnProto {
ZigList<AstNode *> *directives; // can be null if no directives
VisibMod visib_mod;
TopLevelDecl top_level_decl;
Buf name;
ZigList<AstNode *> params;
AstNode *return_type;
@ -191,13 +201,10 @@ struct AstNodeFnProto {
// populated by semantic analyzer:
// the struct decl node this fn proto is inside. can be null.
AstNode *struct_node;
// the function definition this fn proto is inside. can be null.
AstNode *fn_def_node;
FnTableEntry *fn_table_entry;
bool skip;
TopLevelDecl top_level_decl;
Expr resolved_expr;
};
@ -263,41 +270,36 @@ struct AstNodeDefer {
};
struct AstNodeVariableDeclaration {
TopLevelDecl top_level_decl;
Buf symbol;
bool is_const;
bool is_extern;
VisibMod visib_mod;
// one or both of type and expr will be non null
AstNode *type;
AstNode *expr;
ZigList<AstNode *> *directives;
// populated by semantic analyzer
TopLevelDecl top_level_decl;
Expr resolved_expr;
VariableTableEntry *variable;
};
struct AstNodeTypeDecl {
VisibMod visib_mod;
ZigList<AstNode *> *directives;
TopLevelDecl top_level_decl;
Buf symbol;
AstNode *child_type;
// populated by semantic analyzer
TopLevelDecl top_level_decl;
// if this is set, don't process the node; we've already done so
// and here is the type (with id TypeTableEntryIdTypeDecl)
TypeTableEntry *override_type;
TypeTableEntry *child_type_entry;
};
struct AstNodeErrorValueDecl {
TopLevelDecl top_level_decl;
Buf name;
VisibMod visib_mod;
ZigList<AstNode *> *directives;
// populated by semantic analyzer
TopLevelDecl top_level_decl;
ErrorTableEntry *err;
};
@ -430,12 +432,6 @@ struct AstNodeDirective {
AstNode *expr;
};
struct AstNodeRootExportDecl {
Buf type;
Buf name;
ZigList<AstNode *> *directives;
};
enum PrefixOp {
PrefixOpInvalid,
PrefixOpBoolNot,
@ -458,19 +454,8 @@ struct AstNodePrefixOpExpr {
Expr resolved_expr;
};
struct AstNodeImport {
Buf path;
ZigList<AstNode *> *directives;
VisibMod visib_mod;
// populated by semantic analyzer
ImportTableEntry *import;
};
struct AstNodeCImport {
ZigList<AstNode *> *directives;
VisibMod visib_mod;
AstNode *block;
struct AstNodeUse {
AstNode *expr;
// populated by semantic analyzer
TopLevelDecl top_level_decl;
@ -600,23 +585,21 @@ enum ContainerKind {
};
struct AstNodeStructDecl {
TopLevelDecl top_level_decl;
Buf name;
ContainerKind kind;
ZigList<AstNode *> fields;
ZigList<AstNode *> fns;
ZigList<AstNode *> *directives;
VisibMod visib_mod;
// populated by semantic analyzer
BlockContext *block_context;
TypeTableEntry *type_entry;
TopLevelDecl top_level_decl;
};
struct AstNodeStructField {
TopLevelDecl top_level_decl;
Buf name;
AstNode *type;
ZigList<AstNode *> *directives;
VisibMod visib_mod;
};
struct AstNodeStringLiteral {
@ -695,8 +678,6 @@ struct AstNodeSymbolExpr {
// populated by semantic analyzer
Expr resolved_expr;
VariableTableEntry *variable;
FnTableEntry *fn_entry;
// set this to instead of analyzing the node, pretend it's a type entry and it's this one.
TypeTableEntry *override_type_entry;
TypeEnumField *enum_field;
@ -750,7 +731,6 @@ struct AstNode {
BlockContext *block_context;
union {
AstNodeRoot root;
AstNodeRootExportDecl root_export_decl;
AstNodeFnDef fn_def;
AstNodeFnDecl fn_decl;
AstNodeFnProto fn_proto;
@ -768,8 +748,7 @@ struct AstNode {
AstNodeFnCallExpr fn_call_expr;
AstNodeArrayAccessExpr array_access_expr;
AstNodeSliceExpr slice_expr;
AstNodeImport import;
AstNodeCImport c_import;
AstNodeUse use;
AstNodeIfBoolExpr if_bool_expr;
AstNodeIfVarExpr if_var_expr;
AstNodeWhileExpr while_expr;
@ -868,8 +847,7 @@ struct TypeTableEntryStruct {
uint64_t size_bytes;
bool is_invalid; // true if any fields are invalid
bool is_unknown_size_array;
// reminder: hash tables must be initialized before use
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
BlockContext *block_context;
// set this flag temporarily to detect infinite loops
bool embedded_in_current;
@ -895,8 +873,7 @@ struct TypeTableEntryEnum {
TypeTableEntry *tag_type;
TypeTableEntry *union_type;
// reminder: hash tables must be initialized before use
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
BlockContext *block_context;
// set this flag temporarily to detect infinite loops
bool embedded_in_current;
@ -947,6 +924,7 @@ enum TypeTableEntryId {
TypeTableEntryIdEnum,
TypeTableEntryIdFn,
TypeTableEntryIdTypeDecl,
TypeTableEntryIdNamespace,
};
struct TypeTableEntry {
@ -979,26 +957,26 @@ struct TypeTableEntry {
TypeTableEntry *error_parent;
};
struct ImporterInfo {
ImportTableEntry *import;
AstNode *source_node;
struct PackageTableEntry {
Buf root_src_dir;
Buf root_src_path; // relative to root_src_dir
// reminder: hash tables must be initialized before use
HashMap<Buf *, PackageTableEntry *, buf_hash, buf_eql_buf> package_table;
};
struct ImportTableEntry {
AstNode *root;
Buf *path; // relative to root_source_dir
Buf *path; // relative to root_package->root_src_dir
PackageTableEntry *package;
LLVMZigDIFile *di_file;
Buf *source_code;
ZigList<int> *line_offsets;
BlockContext *block_context;
ZigList<ImporterInfo> importers;
AstNode *c_import_node;
bool any_imports_failed;
// reminder: hash tables must be initialized before use
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> fn_table;
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table;
ZigList<AstNode *> use_decls;
};
struct FnTableEntry {
@ -1008,14 +986,12 @@ struct FnTableEntry {
ImportTableEntry *import_entry;
// Required to be a pre-order traversal of the AST. (parents must come before children)
ZigList<BlockContext *> all_block_contexts;
TypeTableEntry *member_of_struct;
Buf symbol_name;
TypeTableEntry *type_entry; // function type
bool is_inline;
bool internal_linkage;
bool is_extern;
bool is_test;
uint32_t ref_count; // if this is 0 we don't have to codegen it
ZigList<AstNode *> cast_alloca_list;
ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;
@ -1042,6 +1018,8 @@ enum BuiltinFnId {
BuiltinFnIdConstEval,
BuiltinFnIdCtz,
BuiltinFnIdClz,
BuiltinFnIdImport,
BuiltinFnIdCImport,
};
struct BuiltinFnEntry {
@ -1061,17 +1039,22 @@ struct CodeGen {
LLVMZigDIBuilder *dbuilder;
LLVMZigDICompileUnit *compile_unit;
ZigList<Buf *> lib_search_paths;
ZigList<Buf *> link_libs;
ZigList<Buf *> link_libs; // non-libc link libs
// reminder: hash tables must be initialized before use
HashMap<Buf *, ImportTableEntry *, buf_hash, buf_eql_buf> import_table;
HashMap<Buf *, BuiltinFnEntry *, buf_hash, buf_eql_buf> builtin_fn_table;
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> primitive_type_table;
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> unresolved_top_level_decls;
HashMap<FnTypeId *, TypeTableEntry *, fn_type_id_hash, fn_type_id_eql> fn_type_table;
HashMap<Buf *, ErrorTableEntry *, buf_hash, buf_eql_buf> error_table;
ZigList<ImportTableEntry *> import_queue;
int import_queue_index;
ZigList<AstNode *> export_queue;
int export_queue_index;
ZigList<AstNode *> use_queue;
int use_queue_index;
uint32_t next_unresolved_index;
struct {
@ -1095,6 +1078,7 @@ struct CodeGen {
TypeTableEntry *entry_unreachable;
TypeTableEntry *entry_type;
TypeTableEntry *entry_invalid;
TypeTableEntry *entry_namespace;
TypeTableEntry *entry_num_lit_int;
TypeTableEntry *entry_num_lit_float;
TypeTableEntry *entry_undef;
@ -1126,7 +1110,8 @@ struct CodeGen {
LLVMTargetMachineRef target_machine;
LLVMZigDIFile *dummy_di_file;
bool is_native_target;
Buf *root_source_dir;
PackageTableEntry *root_package;
PackageTableEntry *std_package;
Buf *root_out_name;
bool windows_subsystem_windows;
bool windows_subsystem_console;
@ -1176,6 +1161,8 @@ struct CodeGen {
ZigList<const char *> lib_dirs;
uint32_t test_fn_count;
bool check_unused;
};
struct VariableTableEntry {
@ -1202,7 +1189,8 @@ struct BlockContext {
AstNode *node;
// any variables that are introduced by this scope
HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
HashMap<Buf *, AstNode *, buf_hash, buf_eql_buf> decl_table;
HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> var_table;
// if the block is inside a function, this is the function it is in:
FnTableEntry *fn_entry;

File diff suppressed because it is too large Load Diff

View File

@ -12,11 +12,11 @@
void semantic_analyze(CodeGen *g);
ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg);
ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg);
TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
BlockContext *new_block_context(AstNode *node, BlockContext *parent);
Expr *get_resolved_expr(AstNode *node);
TopLevelDecl *get_resolved_top_level_decl(AstNode *node);
bool is_node_void_expr(AstNode *node);
TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits);
TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits);
@ -37,4 +37,8 @@ TypeTableEntry *get_underlying_type(TypeTableEntry *type_entry);
bool type_has_bits(TypeTableEntry *type_entry);
uint64_t get_memcpy_align(CodeGen *g, TypeTableEntry *type_entry);
ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package,
Buf *abs_full_path, Buf *src_dirname, Buf *src_basename, Buf *source_code);
#endif

View File

@ -101,8 +101,6 @@ static const char *node_type_str(NodeType node_type) {
switch (node_type) {
case NodeTypeRoot:
return "Root";
case NodeTypeRootExportDecl:
return "RootExportDecl";
case NodeTypeFnDef:
return "FnDef";
case NodeTypeFnDecl:
@ -145,10 +143,8 @@ static const char *node_type_str(NodeType node_type) {
return "Symbol";
case NodeTypePrefixOpExpr:
return "PrefixOpExpr";
case NodeTypeImport:
return "Import";
case NodeTypeCImport:
return "CImport";
case NodeTypeUse:
return "Use";
case NodeTypeBoolLiteral:
return "BoolLiteral";
case NodeTypeNullLiteral:
@ -214,11 +210,6 @@ void ast_print(FILE *f, AstNode *node, int indent) {
ast_print(f, child, indent + 2);
}
break;
case NodeTypeRootExportDecl:
fprintf(f, "%s %s '%s'\n", node_type_str(node->type),
buf_ptr(&node->data.root_export_decl.type),
buf_ptr(&node->data.root_export_decl.name));
break;
case NodeTypeFnDef:
{
fprintf(f, "%s\n", node_type_str(node->type));
@ -372,12 +363,9 @@ void ast_print(FILE *f, AstNode *node, int indent) {
case NodeTypeSymbol:
fprintf(f, "Symbol %s\n", buf_ptr(&node->data.symbol_expr.symbol));
break;
case NodeTypeImport:
fprintf(f, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.import.path));
break;
case NodeTypeCImport:
case NodeTypeUse:
fprintf(f, "%s\n", node_type_str(node->type));
ast_print(f, node->data.c_import.block, indent + 2);
ast_print(f, node->data.use.expr, indent + 2);
break;
case NodeTypeBoolLiteral:
fprintf(f, "%s '%s'\n", node_type_str(node->type),
@ -556,7 +544,7 @@ static void render_node(AstRender *ar, AstNode *node) {
print_indent(ar);
render_node(ar, child);
if (child->type == NodeTypeImport ||
if (child->type == NodeTypeUse ||
child->type == NodeTypeVariableDeclaration ||
child->type == NodeTypeTypeDecl ||
child->type == NodeTypeErrorValueDecl ||
@ -567,12 +555,10 @@ static void render_node(AstRender *ar, AstNode *node) {
fprintf(ar->f, "\n");
}
break;
case NodeTypeRootExportDecl:
zig_panic("TODO");
case NodeTypeFnProto:
{
const char *fn_name = buf_ptr(&node->data.fn_proto.name);
const char *pub_str = visib_mod_string(node->data.fn_proto.visib_mod);
const char *pub_str = visib_mod_string(node->data.fn_proto.top_level_decl.visib_mod);
const char *extern_str = extern_string(node->data.fn_proto.is_extern);
const char *inline_str = inline_string(node->data.fn_proto.is_inline);
fprintf(ar->f, "%s%s%sfn %s(", pub_str, inline_str, extern_str, fn_name);
@ -605,15 +591,19 @@ static void render_node(AstRender *ar, AstNode *node) {
break;
}
case NodeTypeFnDef:
if (node->data.fn_def.fn_proto->data.fn_proto.directives) {
for (int i = 0; i < node->data.fn_def.fn_proto->data.fn_proto.directives->length; i += 1) {
render_node(ar, node->data.fn_def.fn_proto->data.fn_proto.directives->at(i));
{
ZigList<AstNode *> *directives =
node->data.fn_def.fn_proto->data.fn_proto.top_level_decl.directives;
if (directives) {
for (int i = 0; i < directives->length; i += 1) {
render_node(ar, directives->at(i));
}
}
render_node(ar, node->data.fn_def.fn_proto);
fprintf(ar->f, " ");
render_node(ar, node->data.fn_def.body);
break;
}
render_node(ar, node->data.fn_def.fn_proto);
fprintf(ar->f, " ");
render_node(ar, node->data.fn_def.body);
break;
case NodeTypeFnDecl:
zig_panic("TODO");
case NodeTypeParamDecl:
@ -642,7 +632,7 @@ static void render_node(AstRender *ar, AstNode *node) {
zig_panic("TODO");
case NodeTypeVariableDeclaration:
{
const char *pub_str = visib_mod_string(node->data.variable_declaration.visib_mod);
const char *pub_str = visib_mod_string(node->data.variable_declaration.top_level_decl.visib_mod);
const char *extern_str = extern_string(node->data.variable_declaration.is_extern);
const char *var_name = buf_ptr(&node->data.variable_declaration.symbol);
const char *const_or_var = const_or_var_string(node->data.variable_declaration.is_const);
@ -659,7 +649,7 @@ static void render_node(AstRender *ar, AstNode *node) {
}
case NodeTypeTypeDecl:
{
const char *pub_str = visib_mod_string(node->data.type_decl.visib_mod);
const char *pub_str = visib_mod_string(node->data.type_decl.top_level_decl.visib_mod);
const char *var_name = buf_ptr(&node->data.type_decl.symbol);
fprintf(ar->f, "%stype %s = ", pub_str, var_name);
render_node(ar, node->data.type_decl.child_type);
@ -748,9 +738,7 @@ static void render_node(AstRender *ar, AstNode *node) {
fprintf(ar->f, ".%s", buf_ptr(rhs));
break;
}
case NodeTypeImport:
zig_panic("TODO");
case NodeTypeCImport:
case NodeTypeUse:
zig_panic("TODO");
case NodeTypeBoolLiteral:
zig_panic("TODO");
@ -785,7 +773,7 @@ static void render_node(AstRender *ar, AstNode *node) {
case NodeTypeStructDecl:
{
const char *struct_name = buf_ptr(&node->data.struct_decl.name);
const char *pub_str = visib_mod_string(node->data.struct_decl.visib_mod);
const char *pub_str = visib_mod_string(node->data.struct_decl.top_level_decl.visib_mod);
const char *container_str = container_string(node->data.struct_decl.kind);
fprintf(ar->f, "%s%s %s {\n", pub_str, container_str, struct_name);
ar->indent += ar->indent_size;

View File

@ -47,19 +47,30 @@ static void init_darwin_native(CodeGen *g) {
}
}
static PackageTableEntry *new_package(const char *root_src_dir, const char *root_src_path) {
PackageTableEntry *entry = allocate<PackageTableEntry>(1);
entry->package_table.init(4);
buf_init_from_str(&entry->root_src_dir, root_src_dir);
buf_init_from_str(&entry->root_src_path, root_src_path);
return entry;
}
CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) {
CodeGen *g = allocate<CodeGen>(1);
g->import_table.init(32);
g->builtin_fn_table.init(32);
g->primitive_type_table.init(32);
g->unresolved_top_level_decls.init(32);
g->fn_type_table.init(32);
g->error_table.init(16);
g->is_release_build = false;
g->is_test_build = false;
g->root_source_dir = root_source_dir;
g->error_value_count = 1;
g->root_package = new_package(buf_ptr(root_source_dir), "");
g->std_package = new_package(ZIG_STD_DIR, "index.zig");
g->root_package->package_table.put(buf_create_from_str("std"), g->std_package);
if (target) {
// cross compiling, so we can't rely on all the configured stuff since
// that's for native compilation
@ -117,6 +128,10 @@ void codegen_set_verbose(CodeGen *g, bool verbose) {
g->verbose = verbose;
}
void codegen_set_check_unused(CodeGen *g, bool check_unused) {
g->check_unused = check_unused;
}
void codegen_set_errmsg_color(CodeGen *g, ErrColor err_color) {
g->err_color = err_color;
}
@ -157,6 +172,14 @@ void codegen_add_lib_dir(CodeGen *g, const char *dir) {
g->lib_dirs.append(dir);
}
void codegen_add_link_lib(CodeGen *g, const char *lib) {
if (strcmp(lib, "c") == 0) {
g->link_libc = true;
} else {
g->link_libs.append(buf_create_from_str(lib));
}
}
void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole) {
g->windows_subsystem_windows = mwindows;
g->windows_subsystem_console = mconsole;
@ -316,6 +339,8 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
case BuiltinFnIdCInclude:
case BuiltinFnIdCDefine:
case BuiltinFnIdCUndef:
case BuiltinFnIdImport:
case BuiltinFnIdCImport:
zig_unreachable();
case BuiltinFnIdCtz:
case BuiltinFnIdClz:
@ -844,7 +869,7 @@ static LLVMValueRef gen_field_ptr(CodeGen *g, AstNode *node, TypeTableEntry **ou
LLVMValueRef struct_ptr;
if (struct_expr_node->type == NodeTypeSymbol) {
VariableTableEntry *var = struct_expr_node->data.symbol_expr.variable;
VariableTableEntry *var = get_resolved_expr(struct_expr_node)->variable;
assert(var);
if (var->is_ptr && var->type->id == TypeTableEntryIdPointer) {
@ -983,6 +1008,17 @@ static LLVMValueRef gen_array_access_expr(CodeGen *g, AstNode *node, bool is_lva
}
}
static LLVMValueRef gen_variable(CodeGen *g, AstNode *source_node, VariableTableEntry *variable) {
if (!type_has_bits(variable->type)) {
return nullptr;
} else if (variable->is_ptr) {
assert(variable->value_ref);
return get_handle_value(g, source_node, variable->value_ref, variable->type);
} else {
return variable->value_ref;
}
}
static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue) {
assert(node->type == NodeTypeFieldAccessExpr);
@ -1016,6 +1052,10 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lva
} else {
zig_unreachable();
}
} else if (struct_type->id == TypeTableEntryIdNamespace) {
VariableTableEntry *variable = get_resolved_expr(node)->variable;
assert(variable);
return gen_variable(g, node, variable);
} else {
zig_unreachable();
}
@ -1027,7 +1067,7 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,
LLVMValueRef target_ref;
if (node->type == NodeTypeSymbol) {
VariableTableEntry *var = node->data.symbol_expr.variable;
VariableTableEntry *var = get_resolved_expr(node)->variable;
assert(var);
*out_type_entry = var->type;
@ -2468,21 +2508,18 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeSymbol);
VariableTableEntry *variable = node->data.symbol_expr.variable;
VariableTableEntry *variable = get_resolved_expr(node)->variable;
if (variable) {
if (!type_has_bits(variable->type)) {
return nullptr;
} else if (variable->is_ptr) {
assert(variable->value_ref);
return get_handle_value(g, node, variable->value_ref, variable->type);
} else {
return variable->value_ref;
}
return gen_variable(g, node, variable);
}
zig_unreachable();
/* TODO delete
FnTableEntry *fn_entry = node->data.symbol_expr.fn_entry;
assert(fn_entry);
return fn_entry->fn_value;
*/
}
static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
@ -2703,14 +2740,12 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
// caught by constant expression eval codegen
zig_unreachable();
case NodeTypeRoot:
case NodeTypeRootExportDecl:
case NodeTypeFnProto:
case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeDirective:
case NodeTypeImport:
case NodeTypeCImport:
case NodeTypeUse:
case NodeTypeStructDecl:
case NodeTypeStructField:
case NodeTypeStructValueField:
@ -2891,6 +2926,7 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdVoid:
case TypeTableEntryIdNamespace:
zig_unreachable();
}
@ -2943,14 +2979,14 @@ static bool skip_fn_codegen(CodeGen *g, FnTableEntry *fn_entry) {
if (fn_entry == g->main_fn) {
return true;
}
return fn_entry->ref_count == 0;
return false;
}
if (fn_entry->is_test) {
return true;
}
return fn_entry->ref_count == 0;
return false;
}
static LLVMValueRef gen_test_fn_val(CodeGen *g, FnTableEntry *fn_entry) {
@ -3296,6 +3332,12 @@ static void define_builtin_types(CodeGen *g) {
entry->zero_bits = true;
g->builtin_types.entry_invalid = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNamespace);
buf_init_from_str(&entry->name, "(namespace)");
entry->zero_bits = true;
g->builtin_types.entry_namespace = entry;
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitFloat);
buf_init_from_str(&entry->name, "(float literal)");
@ -3499,14 +3541,6 @@ static void define_builtin_types(CodeGen *g) {
g->builtin_types.entry_type = entry;
g->primitive_type_table.put(&entry->name, entry);
}
{
// partially complete the error type. we complete it later after we know
// error_value_count.
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError);
buf_init_from_str(&entry->name, "error");
g->builtin_types.entry_pure_error = entry;
g->primitive_type_table.put(&entry->name, entry);
}
g->builtin_types.entry_u8 = get_int_type(g, false, 8);
g->builtin_types.entry_u16 = get_int_type(g, false, 16);
@ -3517,6 +3551,21 @@ static void define_builtin_types(CodeGen *g) {
g->builtin_types.entry_i32 = get_int_type(g, true, 32);
g->builtin_types.entry_i64 = get_int_type(g, true, 64);
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError);
buf_init_from_str(&entry->name, "error");
// TODO allow overriding this type and keep track of max value and emit an
// error if there are too many errors declared
g->err_tag_type = g->builtin_types.entry_u16;
g->builtin_types.entry_pure_error = entry;
entry->type_ref = g->err_tag_type->type_ref;
entry->di_type = g->err_tag_type->di_type;
g->primitive_type_table.put(&entry->name, entry);
}
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdEnum);
entry->zero_bits = true; // only allowed at compile time
@ -3685,12 +3734,11 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn_with_arg_count(g, BuiltinFnIdConstEval, "const_eval", 1);
create_builtin_fn_with_arg_count(g, BuiltinFnIdCtz, "ctz", 2);
create_builtin_fn_with_arg_count(g, BuiltinFnIdClz, "clz", 2);
create_builtin_fn_with_arg_count(g, BuiltinFnIdImport, "import", 1);
create_builtin_fn_with_arg_count(g, BuiltinFnIdCImport, "c_import", 1);
}
static void init(CodeGen *g, Buf *source_path) {
g->lib_search_paths.append(g->root_source_dir);
g->lib_search_paths.append(buf_create_from_str(ZIG_STD_DIR));
g->module = LLVMModuleCreateWithName(buf_ptr(source_path));
get_target_triple(&g->triple_str, &g->zig_target);
@ -3741,7 +3789,7 @@ static void init(CodeGen *g, Buf *source_path) {
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(source_path), buf_ptr(&g->root_package->root_src_dir),
buf_ptr(producer), is_optimized, flags, runtime_version,
"", 0, !g->strip_debug_symbols);
@ -3761,9 +3809,6 @@ void codegen_parseh(CodeGen *g, Buf *src_dirname, Buf *src_basename, Buf *source
ImportTableEntry *import = allocate<ImportTableEntry>(1);
import->source_code = source_code;
import->path = full_path;
import->fn_table.init(32);
import->type_table.init(8);
import->error_table.init(8);
g->root_import = import;
init(g, full_path);
@ -3791,214 +3836,7 @@ void codegen_render_ast(CodeGen *g, FILE *f, int indent_size) {
}
static int parse_version_string(Buf *buf, int *major, int *minor, int *patch) {
char *dot1 = strstr(buf_ptr(buf), ".");
if (!dot1)
return ErrorInvalidFormat;
char *dot2 = strstr(dot1 + 1, ".");
if (!dot2)
return ErrorInvalidFormat;
*major = (int)strtol(buf_ptr(buf), nullptr, 10);
*minor = (int)strtol(dot1 + 1, nullptr, 10);
*patch = (int)strtol(dot2 + 1, nullptr, 10);
return ErrorNone;
}
static void set_root_export_version(CodeGen *g, Buf *version_buf, AstNode *node) {
int err;
if ((err = parse_version_string(version_buf, &g->version_major, &g->version_minor, &g->version_patch))) {
add_node_error(g, node,
buf_sprintf("invalid version string"));
}
}
static ImportTableEntry *codegen_add_code(CodeGen *g, Buf *abs_full_path,
Buf *src_dirname, Buf *src_basename, Buf *source_code)
{
int err;
Buf *full_path = buf_alloc();
os_path_join(src_dirname, src_basename, full_path);
if (g->verbose) {
fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(full_path));
fprintf(stderr, "----------------\n");
fprintf(stderr, "%s\n", buf_ptr(source_code));
fprintf(stderr, "\nTokens:\n");
fprintf(stderr, "---------\n");
}
Tokenization tokenization = {0};
tokenize(source_code, &tokenization);
if (tokenization.err) {
ErrorMsg *err = err_msg_create_with_line(full_path, tokenization.err_line, tokenization.err_column,
source_code, tokenization.line_offsets, tokenization.err);
print_err_msg(err, g->err_color);
exit(1);
}
if (g->verbose) {
print_tokens(source_code, tokenization.tokens);
fprintf(stderr, "\nAST:\n");
fprintf(stderr, "------\n");
}
ImportTableEntry *import_entry = allocate<ImportTableEntry>(1);
import_entry->source_code = source_code;
import_entry->line_offsets = tokenization.line_offsets;
import_entry->path = full_path;
import_entry->fn_table.init(32);
import_entry->type_table.init(8);
import_entry->error_table.init(8);
import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color,
&g->next_node_index);
assert(import_entry->root);
if (g->verbose) {
ast_print(stderr, import_entry->root, 0);
}
import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
g->import_table.put(abs_full_path, import_entry);
import_entry->block_context = new_block_context(import_entry->root, nullptr);
import_entry->block_context->di_scope = LLVMZigFileToScope(import_entry->di_file);
assert(import_entry->root->type == NodeTypeRoot);
for (int decl_i = 0; decl_i < import_entry->root->data.root.top_level_decls.length; decl_i += 1) {
AstNode *top_level_decl = import_entry->root->data.root.top_level_decls.at(decl_i);
if (top_level_decl->type == NodeTypeRootExportDecl) {
if (g->root_import) {
add_node_error(g, top_level_decl,
buf_sprintf("root export declaration only valid in root source file"));
} else {
ZigList<AstNode *> *directives = top_level_decl->data.root_export_decl.directives;
if (directives) {
for (int i = 0; i < directives->length; i += 1) {
AstNode *directive_node = directives->at(i);
Buf *name = &directive_node->data.directive.name;
AstNode *param_node = directive_node->data.directive.expr;
assert(param_node->type == NodeTypeStringLiteral);
Buf *param = &param_node->data.string_literal.buf;
if (param) {
if (buf_eql_str(name, "version")) {
set_root_export_version(g, param, directive_node);
} else if (buf_eql_str(name, "link")) {
if (buf_eql_str(param, "c")) {
g->link_libc = true;
} else {
g->link_libs.append(param);
}
} else {
add_node_error(g, directive_node,
buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
}
}
}
}
if (g->root_export_decl) {
add_node_error(g, top_level_decl,
buf_sprintf("only one root export declaration allowed"));
} else {
g->root_export_decl = top_level_decl;
if (!g->root_out_name)
g->root_out_name = &top_level_decl->data.root_export_decl.name;
Buf *out_type = &top_level_decl->data.root_export_decl.type;
OutType export_out_type;
if (buf_eql_str(out_type, "executable")) {
export_out_type = OutTypeExe;
} else if (buf_eql_str(out_type, "library")) {
export_out_type = OutTypeLib;
} else if (buf_eql_str(out_type, "object")) {
export_out_type = OutTypeObj;
} else {
add_node_error(g, top_level_decl,
buf_sprintf("invalid export type: '%s'", buf_ptr(out_type)));
}
if (g->out_type == OutTypeUnknown) {
g->out_type = export_out_type;
}
}
}
} else if (top_level_decl->type == NodeTypeImport) {
Buf *import_target_path = &top_level_decl->data.import.path;
Buf full_path = BUF_INIT;
Buf *import_code = buf_alloc();
bool found_it = false;
for (int path_i = 0; path_i < g->lib_search_paths.length; path_i += 1) {
Buf *search_path = g->lib_search_paths.at(path_i);
os_path_join(search_path, import_target_path, &full_path);
Buf *abs_full_path = buf_alloc();
if ((err = os_path_real(&full_path, abs_full_path))) {
if (err == ErrorFileNotFound) {
continue;
} else {
g->error_during_imports = true;
add_node_error(g, top_level_decl,
buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
goto done_looking_at_imports;
}
}
auto entry = g->import_table.maybe_get(abs_full_path);
if (entry) {
found_it = true;
top_level_decl->data.import.import = entry->value;
} else {
if ((err = os_fetch_file_path(abs_full_path, import_code))) {
if (err == ErrorFileNotFound) {
continue;
} else {
g->error_during_imports = true;
add_node_error(g, top_level_decl,
buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
goto done_looking_at_imports;
}
}
top_level_decl->data.import.import = codegen_add_code(g,
abs_full_path, search_path, &top_level_decl->data.import.path, import_code);
found_it = true;
}
break;
}
if (!found_it) {
g->error_during_imports = true;
add_node_error(g, top_level_decl,
buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
}
} else if (top_level_decl->type == NodeTypeFnDef) {
AstNode *proto_node = top_level_decl->data.fn_def.fn_proto;
assert(proto_node->type == NodeTypeFnProto);
Buf *proto_name = &proto_node->data.fn_proto.name;
bool is_private = (proto_node->data.fn_proto.visib_mod == VisibModPrivate);
if (buf_eql_str(proto_name, "main") && !is_private) {
g->have_exported_main = true;
}
}
}
done_looking_at_imports:
return import_entry;
}
static ImportTableEntry *add_special_code(CodeGen *g, const char *basename) {
static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package, const char *basename) {
Buf *std_dir = buf_create_from_str(ZIG_STD_DIR);
Buf *code_basename = buf_create_from_str(basename);
Buf path_to_code_src = BUF_INIT;
@ -4013,12 +3851,22 @@ static ImportTableEntry *add_special_code(CodeGen *g, const char *basename) {
zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
}
return codegen_add_code(g, abs_full_path, std_dir, code_basename, import_code);
return add_source_file(g, package, abs_full_path, std_dir, code_basename, import_code);
}
static PackageTableEntry *create_bootstrap_pkg(CodeGen *g) {
PackageTableEntry *package = new_package(ZIG_STD_DIR, "");
package->package_table.put(buf_create_from_str("std"), g->std_package);
package->package_table.put(buf_create_from_str("@root"), g->root_package);
return package;
}
void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *source_code) {
Buf source_path = BUF_INIT;
os_path_join(src_dir, src_basename, &source_path);
buf_init_from_buf(&g->root_package->root_src_path, src_basename);
init(g, &source_path);
Buf *abs_full_path = buf_alloc();
@ -4027,19 +3875,14 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou
zig_panic("unable to open '%s': %s", buf_ptr(&source_path), err_str(err));
}
g->root_import = codegen_add_code(g, abs_full_path, src_dir, src_basename, source_code);
g->root_import = add_source_file(g, g->root_package, abs_full_path, src_dir, src_basename, source_code);
if (!g->root_out_name) {
add_node_error(g, g->root_import->root,
buf_sprintf("missing export declaration and output name not provided"));
} else if (g->out_type == OutTypeUnknown) {
add_node_error(g, g->root_import->root,
buf_sprintf("missing export declaration and export type not provided"));
}
assert(g->root_out_name);
assert(g->out_type != OutTypeUnknown);
if (!g->link_libc && !g->is_test_build) {
if (g->have_exported_main && (g->out_type == OutTypeObj || g->out_type == OutTypeExe)) {
g->bootstrap_import = add_special_code(g, "bootstrap.zig");
g->bootstrap_import = add_special_code(g, create_bootstrap_pkg(g), "bootstrap.zig");
}
}
@ -4120,7 +3963,7 @@ void codegen_generate_h_file(CodeGen *g) {
assert(proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
if (fn_proto->visib_mod != VisibModExport)
if (fn_proto->top_level_decl.visib_mod != VisibModExport)
continue;
Buf return_type_c = BUF_INIT;

View File

@ -19,6 +19,7 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target);
void codegen_set_clang_argv(CodeGen *codegen, const char **args, int len);
void codegen_set_is_release(CodeGen *codegen, bool is_release);
void codegen_set_is_test(CodeGen *codegen, bool is_test);
void codegen_set_check_unused(CodeGen *codegen, bool check_unused);
void codegen_set_is_static(CodeGen *codegen, bool is_static);
void codegen_set_strip(CodeGen *codegen, bool strip);
@ -34,6 +35,7 @@ void codegen_set_linker_path(CodeGen *g, Buf *linker_path);
void codegen_set_windows_subsystem(CodeGen *g, bool mwindows, bool mconsole);
void codegen_set_windows_unicode(CodeGen *g, bool municode);
void codegen_add_lib_dir(CodeGen *codegen, const char *dir);
void codegen_add_link_lib(CodeGen *codegen, const char *lib);
void codegen_set_mlinker_version(CodeGen *g, Buf *darwin_linker_version);
void codegen_set_rdynamic(CodeGen *g, bool rdynamic);
void codegen_set_mmacosx_version_min(CodeGen *g, Buf *mmacosx_version_min);

View File

@ -4,36 +4,57 @@
#include <stdio.h>
#define RED "\x1b[31;1m"
#define WHITE "\x1b[37;1m"
#define GREEN "\x1b[32;1m"
#define CYAN "\x1b[36;1m"
#define WHITE "\x1b[37;1m"
#define RESET "\x1b[0m"
void print_err_msg(ErrorMsg *err, ErrColor color) {
enum ErrType {
ErrTypeError,
ErrTypeNote,
};
static void print_err_msg_type(ErrorMsg *err, ErrColor color, ErrType err_type) {
const char *path = buf_ptr(err->path);
int line = err->line_start + 1;
int col = err->column_start + 1;
const char *text = buf_ptr(err->msg);
if (color == ErrColorOn || (color == ErrColorAuto && os_stderr_tty())) {
fprintf(stderr, WHITE "%s:%d:%d: " RED "error:" WHITE " %s" RESET "\n",
buf_ptr(err->path),
err->line_start + 1, err->column_start + 1,
buf_ptr(err->msg));
if (err_type == ErrTypeError) {
fprintf(stderr, WHITE "%s:%d:%d: " RED "error:" WHITE " %s" RESET "\n", path, line, col, text);
} else if (err_type == ErrTypeNote) {
fprintf(stderr, WHITE "%s:%d:%d: " CYAN "note:" WHITE " %s" RESET "\n", path, line, col, text);
} else {
zig_unreachable();
}
fprintf(stderr, "%s\n", buf_ptr(&err->line_buf));
for (int i = 0; i < err->column_start; i += 1) {
fprintf(stderr, " ");
}
fprintf(stderr, GREEN "^" RESET "\n");
} else {
fprintf(stderr, "%s:%d:%d: error: %s\n",
buf_ptr(err->path),
err->line_start + 1, err->column_start + 1,
buf_ptr(err->msg));
if (err_type == ErrTypeError) {
fprintf(stderr, "%s:%d:%d: error: %s\n", path, line, col, text);
} else if (err_type == ErrTypeNote) {
fprintf(stderr, " %s:%d:%d: note: %s\n", path, line, col, text);
} else {
zig_unreachable();
}
}
for (int i = 0; i < err->notes.length; i += 1) {
ErrorMsg *note = err->notes.at(i);
print_err_msg(note, color);
print_err_msg_type(note, color, ErrTypeNote);
}
}
void print_err_msg(ErrorMsg *err, ErrColor color) {
print_err_msg_type(err, color, ErrTypeError);
}
void err_msg_add_note(ErrorMsg *parent, ErrorMsg *note) {
parent->notes.append(note);
}

View File

@ -18,8 +18,8 @@
static int usage(const char *arg0) {
fprintf(stderr, "Usage: %s [command] [options]\n"
"Commands:\n"
" build [source] create executable, object, or library from source\n"
" test [source] create and run a test build\n"
" build [sources] create executable, object, or library from source\n"
" test [sources] create and run a test build\n"
" parseh [source] convert a c header file to zig extern declarations\n"
" version print version number and exit\n"
" targets list available compilation targets\n"
@ -40,6 +40,7 @@ static int usage(const char *arg0) {
" -isystem [dir] add additional search path for other .h files\n"
" -dirafter [dir] same as -isystem but do it last\n"
" --library-path [dir] add a directory to the library search path\n"
" --library [lib] link against lib\n"
" --target-arch [name] specify target architecture\n"
" --target-os [name] specify target operating system\n"
" --target-environ [name] specify target environment\n"
@ -50,6 +51,7 @@ static int usage(const char *arg0) {
" -rdynamic add all symbols to the dynamic symbol table\n"
" -mmacosx-version-min [ver] (darwin only) set Mac OS X deployment target\n"
" -mios-version-min [ver] (darwin only) set iOS deployment target\n"
" --check-unused perform semantic analysis on unused declarations\n"
, arg0);
return EXIT_FAILURE;
}
@ -118,6 +120,7 @@ int main(int argc, char **argv) {
const char *linker_path = nullptr;
ZigList<const char *> clang_argv = {0};
ZigList<const char *> lib_dirs = {0};
ZigList<const char *> link_libs = {0};
int err;
const char *target_arch = nullptr;
const char *target_os = nullptr;
@ -129,6 +132,7 @@ int main(int argc, char **argv) {
bool rdynamic = false;
const char *mmacosx_version_min = nullptr;
const char *mios_version_min = nullptr;
bool check_unused = false;
for (int i = 1; i < argc; i += 1) {
char *arg = argv[i];
@ -150,6 +154,8 @@ int main(int argc, char **argv) {
municode = true;
} else if (strcmp(arg, "-rdynamic") == 0) {
rdynamic = true;
} else if (strcmp(arg, "--check-unused") == 0) {
check_unused = true;
} else if (i + 1 >= argc) {
return usage(arg0);
} else {
@ -198,6 +204,8 @@ int main(int argc, char **argv) {
clang_argv.append(argv[i]);
} else if (strcmp(arg, "--library-path") == 0) {
lib_dirs.append(argv[i]);
} else if (strcmp(arg, "--library") == 0) {
link_libs.append(argv[i]);
} else if (strcmp(arg, "--target-arch") == 0) {
target_arch = argv[i];
} else if (strcmp(arg, "--target-os") == 0) {
@ -258,6 +266,16 @@ int main(int argc, char **argv) {
if (!in_file)
return usage(arg0);
if (cmd == CmdBuild && !out_name) {
fprintf(stderr, "--name [name] not provided\n\n");
return usage(arg0);
}
if (cmd == CmdBuild && out_type == OutTypeUnknown) {
fprintf(stderr, "--export [exe|lib|obj] not provided\n\n");
return usage(arg0);
}
init_all_targets();
ZigTarget alloc_target;
@ -313,6 +331,8 @@ int main(int argc, char **argv) {
codegen_set_is_release(g, is_release_build);
codegen_set_is_test(g, cmd == CmdTest);
codegen_set_check_unused(g, check_unused);
codegen_set_clang_argv(g, clang_argv.items, clang_argv.length);
codegen_set_strip(g, strip);
codegen_set_is_static(g, is_static);
@ -342,6 +362,9 @@ int main(int argc, char **argv) {
for (int i = 0; i < lib_dirs.length; i += 1) {
codegen_add_lib_dir(g, lib_dirs.at(i));
}
for (int i = 0; i < link_libs.length; i += 1) {
codegen_add_link_lib(g, link_libs.at(i));
}
codegen_set_windows_subsystem(g, mwindows, mconsole);
codegen_set_windows_unicode(g, municode);

View File

@ -121,9 +121,9 @@ static AstNode *create_typed_var_decl_node(Context *c, bool is_const, const char
AstNode *node = create_node(c, NodeTypeVariableDeclaration);
buf_init_from_str(&node->data.variable_declaration.symbol, var_name);
node->data.variable_declaration.is_const = is_const;
node->data.variable_declaration.visib_mod = c->visib_mod;
node->data.variable_declaration.top_level_decl.visib_mod = c->visib_mod;
node->data.variable_declaration.expr = init_node;
node->data.variable_declaration.directives = nullptr;
node->data.variable_declaration.top_level_decl.directives = nullptr;
node->data.variable_declaration.type = type_node;
normalize_parent_ptrs(node);
return node;
@ -146,7 +146,7 @@ static AstNode *create_struct_field_node(Context *c, const char *name, AstNode *
assert(type_node);
AstNode *node = create_node(c, NodeTypeStructField);
buf_init_from_str(&node->data.struct_field.name, name);
node->data.struct_field.visib_mod = VisibModPub;
node->data.struct_field.top_level_decl.visib_mod = VisibModPub;
node->data.struct_field.type = type_node;
normalize_parent_ptrs(node);
@ -202,7 +202,7 @@ static AstNode *create_num_lit_signed(Context *c, int64_t x) {
static AstNode *create_type_decl_node(Context *c, const char *name, AstNode *child_type_node) {
AstNode *node = create_node(c, NodeTypeTypeDecl);
buf_init_from_str(&node->data.type_decl.symbol, name);
node->data.type_decl.visib_mod = c->visib_mod;
node->data.type_decl.top_level_decl.visib_mod = c->visib_mod;
node->data.type_decl.child_type = child_type_node;
normalize_parent_ptrs(node);
@ -219,7 +219,7 @@ static AstNode *create_fn_proto_node(Context *c, Buf *name, TypeTableEntry *fn_t
assert(fn_type->id == TypeTableEntryIdFn);
AstNode *node = create_node(c, NodeTypeFnProto);
node->data.fn_proto.is_inline = true;
node->data.fn_proto.visib_mod = c->visib_mod;
node->data.fn_proto.top_level_decl.visib_mod = c->visib_mod;
buf_init_from_buf(&node->data.fn_proto.name, name);
node->data.fn_proto.return_type = make_type_node(c, fn_type->data.fn.fn_type_id.return_type);
@ -677,7 +677,7 @@ static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
buf_init_from_buf(&node->data.fn_proto.name, &fn_name);
node->data.fn_proto.is_extern = fn_type->data.fn.fn_type_id.is_extern;
node->data.fn_proto.visib_mod = c->visib_mod;
node->data.fn_proto.top_level_decl.visib_mod = c->visib_mod;
node->data.fn_proto.is_var_args = fn_type->data.fn.fn_type_id.is_var_args;
node->data.fn_proto.return_type = make_type_node(c, fn_type->data.fn.fn_type_id.return_type);
@ -861,7 +861,7 @@ static void visit_enum_decl(Context *c, const EnumDecl *enum_decl) {
AstNode *enum_node = create_node(c, NodeTypeStructDecl);
buf_init_from_buf(&enum_node->data.struct_decl.name, full_type_name);
enum_node->data.struct_decl.kind = ContainerKindEnum;
enum_node->data.struct_decl.visib_mod = VisibModExport;
enum_node->data.struct_decl.top_level_decl.visib_mod = VisibModExport;
enum_node->data.struct_decl.type_entry = enum_type;
for (uint32_t i = 0; i < field_count; i += 1) {
@ -1043,7 +1043,7 @@ static void visit_record_decl(Context *c, const RecordDecl *record_decl) {
AstNode *struct_node = create_node(c, NodeTypeStructDecl);
buf_init_from_buf(&struct_node->data.struct_decl.name, &struct_type->name);
struct_node->data.struct_decl.kind = ContainerKindStruct;
struct_node->data.struct_decl.visib_mod = VisibModExport;
struct_node->data.struct_decl.top_level_decl.visib_mod = VisibModExport;
struct_node->data.struct_decl.type_entry = struct_type;
for (uint32_t i = 0; i < struct_type->data.structure.src_field_count; i += 1) {

View File

@ -20,7 +20,6 @@ struct ParseContext {
ZigList<Token> *tokens;
ImportTableEntry *owner;
ErrColor err_color;
bool parsed_root_export;
uint32_t *next_node_index;
};
@ -1741,8 +1740,8 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token
AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, first_token);
node->data.variable_declaration.is_const = is_const;
node->data.variable_declaration.visib_mod = visib_mod;
node->data.variable_declaration.directives = directives;
node->data.variable_declaration.top_level_decl.visib_mod = visib_mod;
node->data.variable_declaration.top_level_decl.directives = directives;
Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
ast_buf_from_token(pc, name_token, &node->data.variable_declaration.symbol);
@ -2251,8 +2250,8 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeFnProto, first_token);
node->data.fn_proto.visib_mod = visib_mod;
node->data.fn_proto.directives = directives;
node->data.fn_proto.top_level_decl.visib_mod = visib_mod;
node->data.fn_proto.top_level_decl.directives = directives;
Token *fn_name = &pc->tokens->at(*token_index);
if (fn_name->id == TokenIdSymbol) {
@ -2345,76 +2344,23 @@ static AstNode *ast_parse_extern_decl(ParseContext *pc, int *token_index, bool m
}
/*
RootExportDecl : "export" "Symbol" "String" ";"
UseDecl = "use" Expression ";"
*/
static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index,
ZigList<AstNode*> *directives)
{
Token *export_type = &pc->tokens->at(*token_index);
if (export_type->id != TokenIdSymbol)
return nullptr;
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeRootExportDecl, export_type);
node->data.root_export_decl.directives = directives;
ast_buf_from_token(pc, export_type, &node->data.root_export_decl.type);
Token *export_name = &pc->tokens->at(*token_index);
*token_index += 1;
ast_expect_token(pc, export_name, TokenIdStringLiteral);
parse_string_literal(pc, export_name, &node->data.root_export_decl.name, nullptr, nullptr);
Token *semicolon = &pc->tokens->at(*token_index);
*token_index += 1;
ast_expect_token(pc, semicolon, TokenIdSemicolon);
normalize_parent_ptrs(node);
return node;
}
/*
Import : "import" "String" ";"
*/
static AstNode *ast_parse_import(ParseContext *pc, int *token_index,
static AstNode *ast_parse_use(ParseContext *pc, int *token_index,
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
Token *import_kw = &pc->tokens->at(*token_index);
if (import_kw->id != TokenIdKeywordImport)
Token *use_kw = &pc->tokens->at(*token_index);
if (use_kw->id != TokenIdKeywordUse)
return nullptr;
*token_index += 1;
Token *import_name = ast_eat_token(pc, token_index, TokenIdStringLiteral);
AstNode *node = ast_create_node(pc, NodeTypeUse, use_kw);
node->data.use.top_level_decl.visib_mod = visib_mod;
node->data.use.top_level_decl.directives = directives;
node->data.use.expr = ast_parse_expression(pc, token_index, true);
ast_eat_token(pc, token_index, TokenIdSemicolon);
AstNode *node = ast_create_node(pc, NodeTypeImport, import_kw);
node->data.import.visib_mod = visib_mod;
node->data.import.directives = directives;
parse_string_literal(pc, import_name, &node->data.import.path, nullptr, nullptr);
normalize_parent_ptrs(node);
return node;
}
/*
CImportDecl : "c_import" Block
*/
static AstNode *ast_parse_c_import(ParseContext *pc, int *token_index,
ZigList<AstNode*> *directives, VisibMod visib_mod)
{
Token *c_import_kw = &pc->tokens->at(*token_index);
if (c_import_kw->id != TokenIdKeywordCImport)
return nullptr;
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeCImport, c_import_kw);
node->data.c_import.visib_mod = visib_mod;
node->data.c_import.directives = directives;
node->data.c_import.block = ast_parse_block(pc, token_index, true);
normalize_parent_ptrs(node);
return node;
}
@ -2445,8 +2391,8 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index,
AstNode *node = ast_create_node(pc, NodeTypeStructDecl, first_token);
node->data.struct_decl.kind = kind;
ast_buf_from_token(pc, struct_name, &node->data.struct_decl.name);
node->data.struct_decl.visib_mod = visib_mod;
node->data.struct_decl.directives = directives;
node->data.struct_decl.top_level_decl.visib_mod = visib_mod;
node->data.struct_decl.top_level_decl.directives = directives;
ast_eat_token(pc, token_index, TokenIdLBrace);
@ -2486,8 +2432,8 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index,
AstNode *field_node = ast_create_node(pc, NodeTypeStructField, token);
*token_index += 1;
field_node->data.struct_field.visib_mod = visib_mod;
field_node->data.struct_field.directives = directive_list;
field_node->data.struct_field.top_level_decl.visib_mod = visib_mod;
field_node->data.struct_field.top_level_decl.directives = directive_list;
ast_buf_from_token(pc, token, &field_node->data.struct_field.name);
@ -2529,8 +2475,8 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index,
ast_eat_token(pc, token_index, TokenIdSemicolon);
AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token);
node->data.error_value_decl.visib_mod = visib_mod;
node->data.error_value_decl.directives = directives;
node->data.error_value_decl.top_level_decl.visib_mod = visib_mod;
node->data.error_value_decl.top_level_decl.directives = directives;
ast_buf_from_token(pc, name_tok, &node->data.error_value_decl.name);
normalize_parent_ptrs(node);
@ -2559,15 +2505,15 @@ static AstNode *ast_parse_type_decl(ParseContext *pc, int *token_index,
ast_eat_token(pc, token_index, TokenIdSemicolon);
node->data.type_decl.visib_mod = visib_mod;
node->data.type_decl.directives = directives;
node->data.type_decl.top_level_decl.visib_mod = visib_mod;
node->data.type_decl.top_level_decl.directives = directives;
normalize_parent_ptrs(node);
return node;
}
/*
TopLevelDecl = many(Directive) option(VisibleMod) (FnDef | ExternDecl | RootExportDecl | Import | ContainerDecl | GlobalVarDecl | ErrorValueDecl | CImportDecl | TypeDecl)
TopLevelDecl = many(Directive) option(VisibleMod) (FnDef | ExternDecl | Import | ContainerDecl | GlobalVarDecl | ErrorValueDecl | CImportDecl | TypeDecl)
*/
static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
for (;;) {
@ -2587,17 +2533,6 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
visib_mod = VisibModPrivate;
}
bool try_to_parse_root_export = (visib_mod == VisibModExport && !pc->parsed_root_export);
pc->parsed_root_export = true;
if (try_to_parse_root_export) {
AstNode *root_export_decl_node = ast_parse_root_export_decl(pc, token_index, directives);
if (root_export_decl_node) {
top_level_decls->append(root_export_decl_node);
continue;
}
}
AstNode *fn_def_node = ast_parse_fn_def(pc, token_index, false, directives, visib_mod);
if (fn_def_node) {
top_level_decls->append(fn_def_node);
@ -2610,15 +2545,9 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
continue;
}
AstNode *import_node = ast_parse_import(pc, token_index, directives, visib_mod);
if (import_node) {
top_level_decls->append(import_node);
continue;
}
AstNode *c_import_node = ast_parse_c_import(pc, token_index, directives, visib_mod);
if (c_import_node) {
top_level_decls->append(c_import_node);
AstNode *use_node = ast_parse_use(pc, token_index, directives, visib_mod);
if (use_node) {
top_level_decls->append(use_node);
continue;
}
@ -2706,12 +2635,9 @@ void normalize_parent_ptrs(AstNode *node) {
case NodeTypeRoot:
set_list_fields(&node->data.root.top_level_decls);
break;
case NodeTypeRootExportDecl:
set_list_fields(node->data.root_export_decl.directives);
break;
case NodeTypeFnProto:
set_field(&node->data.fn_proto.return_type);
set_list_fields(node->data.fn_proto.directives);
set_list_fields(node->data.fn_proto.top_level_decl.directives);
set_list_fields(&node->data.fn_proto.params);
break;
case NodeTypeFnDef:
@ -2737,12 +2663,12 @@ void normalize_parent_ptrs(AstNode *node) {
set_field(&node->data.defer.expr);
break;
case NodeTypeVariableDeclaration:
set_list_fields(node->data.variable_declaration.directives);
set_list_fields(node->data.variable_declaration.top_level_decl.directives);
set_field(&node->data.variable_declaration.type);
set_field(&node->data.variable_declaration.expr);
break;
case NodeTypeTypeDecl:
set_list_fields(node->data.type_decl.directives);
set_list_fields(node->data.type_decl.top_level_decl.directives);
set_field(&node->data.type_decl.child_type);
break;
case NodeTypeErrorValueDecl:
@ -2788,12 +2714,9 @@ void normalize_parent_ptrs(AstNode *node) {
case NodeTypeFieldAccessExpr:
set_field(&node->data.field_access_expr.struct_expr);
break;
case NodeTypeImport:
set_list_fields(node->data.import.directives);
break;
case NodeTypeCImport:
set_list_fields(node->data.c_import.directives);
set_field(&node->data.c_import.block);
case NodeTypeUse:
set_field(&node->data.use.expr);
set_list_fields(node->data.use.top_level_decl.directives);
break;
case NodeTypeBoolLiteral:
// none
@ -2863,11 +2786,11 @@ void normalize_parent_ptrs(AstNode *node) {
case NodeTypeStructDecl:
set_list_fields(&node->data.struct_decl.fields);
set_list_fields(&node->data.struct_decl.fns);
set_list_fields(node->data.struct_decl.directives);
set_list_fields(node->data.struct_decl.top_level_decl.directives);
break;
case NodeTypeStructField:
set_field(&node->data.struct_field.type);
set_list_fields(node->data.struct_field.directives);
set_list_fields(node->data.struct_field.top_level_decl.directives);
break;
case NodeTypeContainerInitExpr:
set_field(&node->data.container_init_expr.type);

View File

@ -99,7 +99,7 @@
const char * zig_keywords[] = {
"true", "false", "null", "fn", "return", "var", "const", "extern",
"pub", "export", "import", "c_import", "if", "else", "goto", "asm",
"pub", "export", "use", "if", "else", "goto", "asm",
"volatile", "struct", "enum", "while", "for", "continue", "break",
"null", "noalias", "switch", "undefined", "error", "type", "inline",
"defer",
@ -232,10 +232,8 @@ static void end_token(Tokenize *t) {
t->cur_tok->id = TokenIdKeywordPub;
} else if (mem_eql_str(token_mem, token_len, "export")) {
t->cur_tok->id = TokenIdKeywordExport;
} else if (mem_eql_str(token_mem, token_len, "c_import")) {
t->cur_tok->id = TokenIdKeywordCImport;
} else if (mem_eql_str(token_mem, token_len, "import")) {
t->cur_tok->id = TokenIdKeywordImport;
} else if (mem_eql_str(token_mem, token_len, "use")) {
t->cur_tok->id = TokenIdKeywordUse;
} else if (mem_eql_str(token_mem, token_len, "true")) {
t->cur_tok->id = TokenIdKeywordTrue;
} else if (mem_eql_str(token_mem, token_len, "false")) {
@ -1071,8 +1069,7 @@ const char * token_name(TokenId id) {
case TokenIdKeywordExtern: return "extern";
case TokenIdKeywordPub: return "pub";
case TokenIdKeywordExport: return "export";
case TokenIdKeywordImport: return "import";
case TokenIdKeywordCImport: return "c_import";
case TokenIdKeywordUse: return "use";
case TokenIdKeywordTrue: return "true";
case TokenIdKeywordFalse: return "false";
case TokenIdKeywordIf: return "if";

View File

@ -19,9 +19,8 @@ enum TokenId {
TokenIdKeywordConst,
TokenIdKeywordExtern,
TokenIdKeywordPub,
TokenIdKeywordUse,
TokenIdKeywordExport,
TokenIdKeywordImport,
TokenIdKeywordCImport,
TokenIdKeywordTrue,
TokenIdKeywordFalse,
TokenIdKeywordIf,

View File

@ -1,7 +1,7 @@
import "syscall.zig";
// This file is in a package which has the root source file exposed as "@root".
// The compiler treats this file special by implicitly importing the function `main`
// from the root source file as the symbol `zig_user_main`.
const root = @import("@root");
const syscall = @import("syscall.zig");
const want_start_symbol = switch(@compile_var("os")) {
linux => true,
@ -26,7 +26,7 @@ export fn _start() -> unreachable {
},
else => unreachable{},
}
call_main()
call_main_and_exit()
}
fn strlen(ptr: &const u8) -> isize {
@ -37,23 +37,24 @@ fn strlen(ptr: &const u8) -> isize {
return count;
}
fn call_main() -> unreachable {
fn call_main() -> %void {
var args: [argc][]u8 = undefined;
for (args) |arg, i| {
const ptr = argv[i];
args[i] = ptr[0...strlen(ptr)];
}
zig_user_main(args) %% exit(1);
exit(0);
return root.main(args);
}
fn call_main_and_exit() -> unreachable {
call_main() %% syscall.exit(1);
syscall.exit(0);
}
#condition(want_main_symbol)
export fn main(argc: i32, argv: &&u8) -> i32 {
var args: [argc][]u8 = undefined;
for (args) |arg, i| {
const ptr = argv[i];
args[i] = ptr[0...strlen(ptr)];
}
zig_user_main(args) %% return 1;
export fn main(c_argc: i32, c_argv: &&u8) -> i32 {
argc = c_argc;
argv = c_argv;
call_main() %% return 1;
return 0;
}

4
std/index.zig Normal file
View File

@ -0,0 +1,4 @@
pub const Rand = @import("rand.zig").Rand;
pub const io = @import("io.zig");
pub const os = @import("os.zig");
pub const math = @import("math.zig");

View File

@ -1,6 +1,6 @@
import "syscall.zig";
import "errno.zig";
import "math.zig";
const syscall = @import("syscall.zig");
const errno = @import("errno.zig");
const math = @import("math.zig");
pub const stdin_fileno = 0;
pub const stdout_fileno = 1;
@ -55,7 +55,7 @@ pub struct OutStream {
const dest_space_left = os.buffer.len - os.index;
while (src_bytes_left > 0) {
const copy_amt = min_isize(dest_space_left, src_bytes_left);
const copy_amt = math.min_isize(dest_space_left, src_bytes_left);
@memcpy(&os.buffer[os.index], &str[src_index], copy_amt);
os.index += copy_amt;
if (os.index == os.buffer.len) {
@ -105,19 +105,19 @@ pub struct OutStream {
}
pub fn flush(os: &OutStream) -> %void {
const amt_written = write(os.fd, &os.buffer[0], os.index);
const amt_written = syscall.write(os.fd, &os.buffer[0], os.index);
os.index = 0;
if (amt_written < 0) {
return switch (-amt_written) {
EINVAL => unreachable{},
EDQUOT => error.DiskQuota,
EFBIG => error.FileTooBig,
EINTR => error.SigInterrupt,
EIO => error.Io,
ENOSPC => error.NoSpaceLeft,
EPERM => error.BadPerm,
EPIPE => error.PipeFail,
else => error.Unexpected,
errno.EINVAL => unreachable{},
errno.EDQUOT => error.DiskQuota,
errno.EFBIG => error.FileTooBig,
errno.EINTR => error.SigInterrupt,
errno.EIO => error.Io,
errno.ENOSPC => error.NoSpaceLeft,
errno.EPERM => error.BadPerm,
errno.EPIPE => error.PipeFail,
else => error.Unexpected,
}
}
}
@ -139,15 +139,15 @@ pub struct InStream {
fd: isize,
pub fn read(is: &InStream, buf: []u8) -> %isize {
const amt_read = read(is.fd, &buf[0], buf.len);
const amt_read = syscall.read(is.fd, &buf[0], buf.len);
if (amt_read < 0) {
return switch (-amt_read) {
EINVAL => unreachable{},
EFAULT => unreachable{},
EBADF => error.BadFd,
EINTR => error.SigInterrupt,
EIO => error.Io,
else => error.Unexpected,
errno.EINVAL => unreachable{},
errno.EFAULT => unreachable{},
errno.EBADF => error.BadFd,
errno.EINTR => error.SigInterrupt,
errno.EIO => error.Io,
else => error.Unexpected,
}
}
return amt_read;
@ -168,8 +168,8 @@ pub struct InStream {
#attribute("cold")
pub fn abort() -> unreachable {
raise(SIGABRT);
raise(SIGKILL);
syscall.raise(syscall.SIGABRT);
syscall.raise(syscall.SIGKILL);
while (true) {}
}
@ -253,15 +253,15 @@ pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize {
decs = max_u64_base10_digits - 1;
}
if (x == f64_get_pos_inf()) {
if (x == math.f64_get_pos_inf()) {
const buf2 = "+Inf";
@memcpy(&out_buf[0], &buf2[0], buf2.len);
return 4;
} else if (x == f64_get_neg_inf()) {
} else if (x == math.f64_get_neg_inf()) {
const buf2 = "-Inf";
@memcpy(&out_buf[0], &buf2[0], buf2.len);
return 4;
} else if (f64_is_nan(x)) {
} else if (math.f64_is_nan(x)) {
const buf2 = "NaN";
@memcpy(&out_buf[0], &buf2[0], buf2.len);
return 3;
@ -275,7 +275,7 @@ pub fn buf_print_f64(out_buf: []u8, x: f64, decimals: isize) -> isize {
// 11 exponent bits
// 52 significand bits (+ 1 implicit always non-zero bit)
const bits = f64_to_bits(x);
const bits = math.f64_to_bits(x);
if (bits & (1 << 63) != 0) {
buf[0] = '-';
len += 1;

View File

@ -1,19 +1,19 @@
import "syscall.zig";
import "errno.zig";
const syscall = @import("syscall.zig");
const errno = @import("errno.zig");
pub error SigInterrupt;
pub error Unexpected;
pub fn os_get_random_bytes(buf: []u8) -> %void {
pub fn get_random_bytes(buf: []u8) -> %void {
switch (@compile_var("os")) {
linux => {
const amt_got = getrandom(buf.ptr, buf.len, 0);
const amt_got = syscall.getrandom(buf.ptr, buf.len, 0);
if (amt_got < 0) {
return switch (-amt_got) {
EINVAL => unreachable{},
EFAULT => unreachable{},
EINTR => error.SigInterrupt,
else => error.Unexpected,
errno.EINVAL => unreachable{},
errno.EFAULT => unreachable{},
errno.EINTR => error.SigInterrupt,
else => error.Unexpected,
}
}
},

View File

@ -84,26 +84,26 @@ pub struct Rand {
}
return bytes_left;
}
}
/// Initialize random state with the given seed.
pub fn rand_new(seed: u32) -> Rand {
var r: Rand = undefined;
r.index = 0;
r.array[0] = seed;
var i : isize = 1;
var prev_value: u64 = seed;
while (i < ARRAY_SIZE) {
r.array[i] = u32((prev_value ^ (prev_value << 30)) * 0x6c078965 + u32(i));
prev_value = r.array[i];
i += 1;
/// Initialize random state with the given seed.
pub fn init(seed: u32) -> Rand {
var r: Rand = undefined;
r.index = 0;
r.array[0] = seed;
var i : isize = 1;
var prev_value: u64 = seed;
while (i < ARRAY_SIZE) {
r.array[i] = u32((prev_value ^ (prev_value << 30)) * 0x6c078965 + u32(i));
prev_value = r.array[i];
i += 1;
}
return r;
}
return r;
}
#attribute("test")
fn test_float32() {
var r = rand_new(42);
var r = Rand.init(42);
// TODO for loop with range
var i: i32 = 0;

View File

@ -1,4 +1,4 @@
import "std.zig";
const io = @import("std").io;
struct TestFn {
name: []u8,
@ -9,19 +9,19 @@ extern var zig_test_fn_list: []TestFn;
pub fn run_tests() -> %void {
for (zig_test_fn_list) |test_fn, i| {
%%stderr.print_str("Test ");
%%stderr.print_i64(i + 1);
%%stderr.print_str("/");
%%stderr.print_i64(zig_test_fn_list.len);
%%stderr.print_str(" ");
%%stderr.print_str(test_fn.name);
%%stderr.print_str("...");
%%stderr.flush();
%%io.stderr.print_str("Test ");
%%io.stderr.print_i64(i + 1);
%%io.stderr.print_str("/");
%%io.stderr.print_i64(zig_test_fn_list.len);
%%io.stderr.print_str(" ");
%%io.stderr.print_str(test_fn.name);
%%io.stderr.print_str("...");
%%io.stderr.flush();
test_fn.func();
%%stderr.print_str("OK\n");
%%stderr.flush();
%%io.stderr.print_str("OK\n");
%%io.stderr.flush();
}
}

View File

@ -1,6 +1,6 @@
import "test_runner.zig";
const test_runner = @import("test_runner.zig");
export fn main(argc: c_int, argv: &&u8) -> c_int {
run_tests() %% return -1;
test_runner.run_tests() %% return -1;
return 0;
}

View File

@ -1,5 +1,5 @@
import "test_runner.zig";
const test_runner = @import("test_runner.zig");
pub fn main(args: [][]u8) -> %void {
return run_tests();
return test_runner.run_tests();
}

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +1,5 @@
import "test_std.zig";
// test std library
const std = @import("std");
#attribute("test")
fn empty_function() {}

View File

@ -1 +0,0 @@
import "std.zig";