mirror of
https://github.com/ziglang/zig.git
synced 2026-02-21 16:54:52 +00:00
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:
parent
28fe994a10
commit
f1d338194e
@ -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"
|
||||
)
|
||||
|
||||
|
||||
|
||||
@ -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
75
doc/semantic_analysis.md
Normal 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.
|
||||
@ -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.
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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");
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
1556
src/analyze.cpp
1556
src/analyze.cpp
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
347
src/codegen.cpp
347
src/codegen.cpp
@ -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 = ¶m_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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
27
src/main.cpp
27
src/main.cpp
@ -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);
|
||||
|
||||
@ -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) {
|
||||
|
||||
141
src/parser.cpp
141
src/parser.cpp
@ -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);
|
||||
|
||||
@ -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";
|
||||
|
||||
@ -19,9 +19,8 @@ enum TokenId {
|
||||
TokenIdKeywordConst,
|
||||
TokenIdKeywordExtern,
|
||||
TokenIdKeywordPub,
|
||||
TokenIdKeywordUse,
|
||||
TokenIdKeywordExport,
|
||||
TokenIdKeywordImport,
|
||||
TokenIdKeywordCImport,
|
||||
TokenIdKeywordTrue,
|
||||
TokenIdKeywordFalse,
|
||||
TokenIdKeywordIf,
|
||||
|
||||
@ -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
4
std/index.zig
Normal 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");
|
||||
@ -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;
|
||||
16
std/os.zig
16
std/os.zig
@ -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,
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
28
std/rand.zig
28
std/rand.zig
@ -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;
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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
@ -1,4 +1,5 @@
|
||||
import "test_std.zig";
|
||||
// test std library
|
||||
const std = @import("std");
|
||||
|
||||
#attribute("test")
|
||||
fn empty_function() {}
|
||||
|
||||
@ -1 +0,0 @@
|
||||
import "std.zig";
|
||||
Loading…
x
Reference in New Issue
Block a user