Commit f1d338194e
Changed files (31)
doc
example
guess_number
hello_world
src
std
doc/vim/syntax/zig.vim
@@ -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
doc/langref.md
@@ -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) ";"
doc/semantic_analysis.md
@@ -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.
doc/targets.md
@@ -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.
example/guess_number/main.zig
@@ -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;
}
}
example/hello_world/hello.zig
@@ -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");
}
example/hello_world/hello_libc.zig
@@ -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;
}
src/all_types.hpp
@@ -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;
src/analyze.cpp
@@ -14,8 +14,10 @@
#include "config.h"
#include "ast_render.hpp"
-static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node);
+static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEntry *import,
+ BlockContext *context, TypeTableEntry *expected_type, AstNode *node, bool pointer_only);
static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import,
BlockContext *context, TypeTableEntry *expected_type, AstNode *node);
static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type);
@@ -27,13 +29,18 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *
static TypeTableEntry *analyze_block_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node);
static TypeTableEntry *resolve_expr_const_val_as_void(CodeGen *g, AstNode *node);
-static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, BlockContext *context,
- FnTableEntry *fn);
+static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn);
static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node, TypeTableEntry *type);
static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, AstNode *node,
TypeTableEntry *expected_type, uint64_t x);
-static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *node);
-static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, AstNode *node);
+static AstNode *find_decl(BlockContext *context, Buf *name);
+static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node, bool pointer_only);
+static TopLevelDecl *get_as_top_level_decl(AstNode *node);
+static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
+ BlockContext *context, AstNode *source_node,
+ AstNodeVariableDeclaration *variable_declaration,
+ bool expr_is_maybe, AstNode *decl_node);
+static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node);
static AstNode *first_executing_node(AstNode *node) {
switch (node->type) {
@@ -52,7 +59,6 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeSwitchRange:
return first_executing_node(node->data.switch_range.start);
case NodeTypeRoot:
- case NodeTypeRootExportDecl:
case NodeTypeFnProto:
case NodeTypeFnDef:
case NodeTypeFnDecl:
@@ -69,8 +75,7 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeCharLiteral:
case NodeTypeSymbol:
case NodeTypePrefixOpExpr:
- case NodeTypeImport:
- case NodeTypeCImport:
+ case NodeTypeUse:
case NodeTypeBoolLiteral:
case NodeTypeNullLiteral:
case NodeTypeUndefinedLiteral:
@@ -109,43 +114,47 @@ ErrorMsg *add_node_error(CodeGen *g, AstNode *node, Buf *msg) {
return err;
}
+ErrorMsg *add_error_note(CodeGen *g, ErrorMsg *parent_msg, AstNode *node, Buf *msg) {
+ // if this assert fails, then parseh generated code that
+ // failed semantic analysis, which isn't supposed to happen
+ assert(!node->owner->c_import_node);
+
+ ErrorMsg *err = err_msg_create_with_line(node->owner->path, node->line, node->column,
+ node->owner->source_code, node->owner->line_offsets, msg);
+
+ err_msg_add_note(parent_msg, err);
+ return err;
+}
+
TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
TypeTableEntry *entry = allocate<TypeTableEntry>(1);
entry->arrays_by_size.init(2);
entry->id = id;
+ return entry;
+}
- switch (id) {
- case TypeTableEntryIdInvalid:
- case TypeTableEntryIdMetaType:
- case TypeTableEntryIdVoid:
- case TypeTableEntryIdBool:
- case TypeTableEntryIdUnreachable:
- case TypeTableEntryIdInt:
- case TypeTableEntryIdFloat:
- case TypeTableEntryIdPointer:
- case TypeTableEntryIdArray:
- case TypeTableEntryIdNumLitFloat:
- case TypeTableEntryIdNumLitInt:
- case TypeTableEntryIdMaybe:
- case TypeTableEntryIdFn:
- case TypeTableEntryIdErrorUnion:
- case TypeTableEntryIdPureError:
- case TypeTableEntryIdUndefLit:
- case TypeTableEntryIdTypeDecl:
- // nothing to init
- break;
- case TypeTableEntryIdStruct:
- entry->data.structure.fn_table.init(8);
- break;
- case TypeTableEntryIdEnum:
- entry->data.enumeration.fn_table.init(8);
- break;
-
+static BlockContext **get_container_block_context_ptr(TypeTableEntry *type_entry) {
+ if (type_entry->id == TypeTableEntryIdStruct) {
+ return &type_entry->data.structure.block_context;
+ } else if (type_entry->id == TypeTableEntryIdEnum) {
+ return &type_entry->data.enumeration.block_context;
}
+ zig_unreachable();
+}
+
+static BlockContext *get_container_block_context(TypeTableEntry *type_entry) {
+ return *get_container_block_context_ptr(type_entry);
+}
+static TypeTableEntry *new_container_type_entry(TypeTableEntryId id, AstNode *source_node,
+ BlockContext *parent_context)
+{
+ TypeTableEntry *entry = new_type_table_entry(id);
+ *get_container_block_context_ptr(entry) = new_block_context(source_node, parent_context);
return entry;
}
+
static int bits_needed_for_unsigned(uint64_t x) {
if (x <= UINT8_MAX) {
return 8;
@@ -182,6 +191,7 @@ static bool type_is_complete(TypeTableEntry *type_entry) {
case TypeTableEntryIdPureError:
case TypeTableEntryIdFn:
case TypeTableEntryIdTypeDecl:
+ case TypeTableEntryIdNamespace:
return true;
}
zig_unreachable();
@@ -671,7 +681,7 @@ TypeTableEntry *get_partial_container_type(CodeGen *g, ImportTableEntry *import,
ContainerKind kind, AstNode *decl_node, const char *name)
{
TypeTableEntryId type_id = container_to_type(kind);
- TypeTableEntry *entry = new_type_table_entry(type_id);
+ TypeTableEntry *entry = new_container_type_entry(type_id, decl_node, import->block_context);
switch (kind) {
case ContainerKindStruct:
@@ -730,13 +740,19 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
return const_val->data.x_type;
}
+static TypeTableEntry *analyze_type_expr_pointer_only(CodeGen *g, ImportTableEntry *import,
+ BlockContext *context, AstNode *node, bool pointer_only)
+{
+ AstNode **node_ptr = node->parent_field;
+ analyze_expression_pointer_only(g, import, context, nullptr, *node_ptr, pointer_only);
+ return resolve_type(g, *node_ptr);
+}
+
// Calls analyze_expression on node, and then resolve_type.
static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node)
{
- AstNode **node_ptr = node->parent_field;
- analyze_expression(g, import, context, nullptr, *node_ptr);
- return resolve_type(g, *node_ptr);
+ return analyze_type_expr_pointer_only(g, import, context, node, false);
}
static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@@ -750,7 +766,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
}
FnTypeId fn_type_id = {0};
- fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->visib_mod == VisibModExport);
+ fn_type_id.is_extern = fn_proto->is_extern || (fn_proto->top_level_decl.visib_mod == VisibModExport);
fn_type_id.is_naked = is_naked;
fn_type_id.is_cold = is_cold;
fn_type_id.param_count = node->data.fn_proto.params.length;
@@ -782,6 +798,7 @@ static TypeTableEntry *analyze_fn_proto_type(CodeGen *g, ImportTableEntry *impor
case TypeTableEntryIdUndefLit:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdUnreachable:
+ case TypeTableEntryIdNamespace:
fn_proto->skip = true;
add_node_error(g, child->data.param_decl.type,
buf_sprintf("parameter of type '%s' not allowed'", buf_ptr(&type_entry->name)));
@@ -880,9 +897,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
bool is_naked = false;
bool is_test = false;
- if (fn_proto->directives) {
- for (int i = 0; i < fn_proto->directives->length; i += 1) {
- AstNode *directive_node = fn_proto->directives->at(i);
+ if (fn_proto->top_level_decl.directives) {
+ for (int i = 0; i < fn_proto->top_level_decl.directives->length; i += 1) {
+ AstNode *directive_node = fn_proto->top_level_decl.directives->at(i);
Buf *name = &directive_node->data.directive.name;
if (buf_eql_str(name, "attribute")) {
@@ -907,12 +924,12 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
buf_sprintf("invalid function attribute: '%s'", buf_ptr(name)));
}
} else if (buf_eql_str(name, "condition")) {
- if (fn_proto->visib_mod == VisibModExport) {
+ if (fn_proto->top_level_decl.visib_mod == VisibModExport) {
bool include;
bool ok = resolve_const_expr_bool(g, import, import->block_context,
&directive_node->data.directive.expr, &include);
if (ok && !include) {
- fn_proto->visib_mod = VisibModPub;
+ fn_proto->top_level_decl.visib_mod = VisibModPub;
}
} else {
add_node_error(g, directive_node,
@@ -925,12 +942,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
}
}
- bool is_internal = (fn_proto->visib_mod != VisibModExport);
+ bool is_internal = (fn_proto->top_level_decl.visib_mod != VisibModExport);
bool is_c_compat = !is_internal || fn_proto->is_extern;
fn_table_entry->internal_linkage = !is_c_compat;
- if (!is_internal) {
- fn_table_entry->ref_count += 1;
- }
@@ -972,18 +986,19 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
LLVMAddFunctionAttr(fn_table_entry->fn_value, LLVMNoUnwindAttribute);
}
- // Add debug info.
- unsigned line_number = node->line + 1;
- unsigned scope_line = line_number;
- bool is_definition = fn_table_entry->fn_def_node != nullptr;
- unsigned flags = 0;
- bool is_optimized = g->is_release_build;
- LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder,
- import->block_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "",
- import->di_file, line_number,
- fn_type->di_type, fn_table_entry->internal_linkage,
- is_definition, scope_line, flags, is_optimized, fn_table_entry->fn_value);
if (fn_table_entry->fn_def_node) {
+ // Add debug info.
+ unsigned line_number = node->line + 1;
+ unsigned scope_line = line_number;
+ bool is_definition = fn_table_entry->fn_def_node != nullptr;
+ unsigned flags = 0;
+ bool is_optimized = g->is_release_build;
+ LLVMZigDISubprogram *subprogram = LLVMZigCreateFunction(g->dbuilder,
+ import->block_context->di_scope, buf_ptr(&fn_table_entry->symbol_name), "",
+ import->di_file, line_number,
+ fn_type->di_type, fn_table_entry->internal_linkage,
+ is_definition, scope_line, flags, is_optimized, fn_table_entry->fn_value);
+
BlockContext *context = new_block_context(fn_table_entry->fn_def_node, import->block_context);
fn_table_entry->fn_def_node->data.fn_def.block_context = context;
context->di_scope = LLVMZigSubprogramToScope(subprogram);
@@ -1295,59 +1310,43 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
struct_type->zero_bits = (debug_size_in_bits == 0);
}
-static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
- AstNode *proto_node)
-{
+static void get_fully_qualified_decl_name(Buf *buf, AstNode *decl_node, uint8_t sep) {
+ TopLevelDecl *tld = get_as_top_level_decl(decl_node);
+ AstNode *parent_decl = tld->parent_decl;
+
+ if (parent_decl) {
+ get_fully_qualified_decl_name(buf, parent_decl, sep);
+ buf_append_char(buf, sep);
+ buf_append_buf(buf, tld->name);
+ } else {
+ buf_init_from_buf(buf, tld->name);
+ }
+}
+
+static void preview_fn_proto(CodeGen *g, ImportTableEntry *import, AstNode *proto_node) {
if (proto_node->data.fn_proto.skip) {
return;
}
+
+ AstNode *parent_decl = proto_node->data.fn_proto.top_level_decl.parent_decl;
+
AstNode *fn_def_node = proto_node->data.fn_proto.fn_def_node;
- AstNode *struct_node = proto_node->data.fn_proto.struct_node;
bool is_extern = proto_node->data.fn_proto.is_extern;
- TypeTableEntry *struct_type;
- if (struct_node) {
- assert(struct_node->type == NodeTypeStructDecl);
- struct_type = struct_node->data.struct_decl.type_entry;
- } else {
- struct_type = nullptr;
- }
Buf *proto_name = &proto_node->data.fn_proto.name;
- auto fn_table = struct_type ? &struct_type->data.structure.fn_table : &import->fn_table;
-
- auto entry = fn_table->maybe_get(proto_name);
- bool skip = false;
- bool is_pub = (proto_node->data.fn_proto.visib_mod != VisibModPrivate);
- if (entry) {
- add_node_error(g, proto_node,
- buf_sprintf("redefinition of '%s'", buf_ptr(proto_name)));
- proto_node->data.fn_proto.skip = true;
- skip = true;
- }
if (!is_extern && proto_node->data.fn_proto.is_var_args) {
add_node_error(g, proto_node,
buf_sprintf("variadic arguments only allowed in extern functions"));
}
- if (skip) {
- return;
- }
FnTableEntry *fn_table_entry = allocate<FnTableEntry>(1);
fn_table_entry->import_entry = import;
fn_table_entry->proto_node = proto_node;
fn_table_entry->fn_def_node = fn_def_node;
fn_table_entry->is_extern = is_extern;
- fn_table_entry->member_of_struct = struct_type;
- if (struct_type) {
- buf_resize(&fn_table_entry->symbol_name, 0);
- buf_appendf(&fn_table_entry->symbol_name, "%s_%s",
- buf_ptr(&struct_type->name),
- buf_ptr(proto_name));
- } else {
- buf_init_from_buf(&fn_table_entry->symbol_name, proto_name);
- }
+ get_fully_qualified_decl_name(&fn_table_entry->symbol_name, proto_node, '_');
g->fn_protos.append(fn_table_entry);
@@ -1355,39 +1354,13 @@ static void preview_fn_proto(CodeGen *g, ImportTableEntry *import,
g->fn_defs.append(fn_table_entry);
}
- fn_table->put(proto_name, fn_table_entry);
-
- bool is_main_fn = !struct_type && (import == g->root_import) && buf_eql_str(proto_name, "main");
+ bool is_main_fn = !parent_decl && (import == g->root_import) && buf_eql_str(proto_name, "main");
if (is_main_fn) {
g->main_fn = fn_table_entry;
-
- if (g->bootstrap_import && !g->is_test_build) {
- g->bootstrap_import->fn_table.put(buf_create_from_str("zig_user_main"), fn_table_entry);
- }
- }
- bool is_test_main_fn = !struct_type && (import == g->test_runner_import) && buf_eql_str(proto_name, "main");
- if (is_test_main_fn) {
- assert(g->bootstrap_import);
- assert(g->is_test_build);
- g->bootstrap_import->fn_table.put(proto_name, fn_table_entry);
}
proto_node->data.fn_proto.fn_table_entry = fn_table_entry;
resolve_function_proto(g, proto_node, fn_table_entry, import);
-
- if (is_pub && !struct_type) {
- for (int i = 0; i < import->importers.length; i += 1) {
- ImporterInfo importer = import->importers.at(i);
- auto table_entry = importer.import->fn_table.maybe_get(proto_name);
- if (table_entry) {
- add_node_error(g, importer.source_node,
- buf_sprintf("import of function '%s' overrides existing definition",
- buf_ptr(proto_name)));
- } else {
- importer.import->fn_table.put(proto_name, fn_table_entry);
- }
- }
- }
}
static void preview_error_value_decl(CodeGen *g, AstNode *node) {
@@ -1403,110 +1376,40 @@ static void preview_error_value_decl(CodeGen *g, AstNode *node) {
// duplicate error definitions allowed and they get the same value
err->value = existing_entry->value->value;
} else {
+ assert(g->error_value_count < (1 << g->err_tag_type->data.integral.bit_count));
err->value = g->error_value_count;
g->error_value_count += 1;
g->error_table.put(&err->name, err);
}
node->data.error_value_decl.err = err;
+ node->data.error_value_decl.top_level_decl.resolution = TldResolutionOk;
}
-static void resolve_error_value_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
- assert(node->type == NodeTypeErrorValueDecl);
-
- ErrorTableEntry *err = node->data.error_value_decl.err;
-
- import->error_table.put(&err->name, err);
-
- bool is_pub = (node->data.error_value_decl.visib_mod != VisibModPrivate);
- if (is_pub) {
- for (int i = 0; i < import->importers.length; i += 1) {
- ImporterInfo importer = import->importers.at(i);
- importer.import->error_table.put(&err->name, err);
- }
- }
-}
-
-static void resolve_c_import_decl(CodeGen *g, ImportTableEntry *parent_import, AstNode *node) {
- assert(node->type == NodeTypeCImport);
-
- AstNode *block_node = node->data.c_import.block;
-
- BlockContext *child_context = new_block_context(node, parent_import->block_context);
- child_context->c_import_buf = buf_alloc();
-
- TypeTableEntry *resolved_type = analyze_block_expr(g, parent_import, child_context,
- g->builtin_types.entry_void, block_node);
-
- if (resolved_type->id == TypeTableEntryIdInvalid) {
+static void resolve_top_level_decl(CodeGen *g, AstNode *node, bool pointer_only) {
+ TopLevelDecl *tld = get_as_top_level_decl(node);
+ if (tld->resolution != TldResolutionUnresolved) {
return;
}
-
- find_libc_include_path(g);
-
- ImportTableEntry *child_import = allocate<ImportTableEntry>(1);
- child_import->fn_table.init(32);
- child_import->type_table.init(8);
- child_import->error_table.init(8);
- child_import->c_import_node = node;
-
- child_import->importers.append({parent_import, node});
-
- if (node->data.c_import.visib_mod != VisibModPrivate) {
- for (int i = 0; i < parent_import->importers.length; i += 1) {
- ImporterInfo importer = parent_import->importers.at(i);
- child_import->importers.append(importer);
- }
- }
-
- ZigList<ErrorMsg *> errors = {0};
-
- int err;
- if ((err = parse_h_buf(child_import, &errors, child_context->c_import_buf, g, node))) {
- zig_panic("unable to parse h file: %s\n", err_str(err));
- }
-
- if (errors.length > 0) {
- ErrorMsg *parent_err_msg = add_node_error(g, node, buf_sprintf("C import failed"));
- for (int i = 0; i < errors.length; i += 1) {
- ErrorMsg *err_msg = errors.at(i);
- err_msg_add_note(parent_err_msg, err_msg);
- }
-
- for (int i = 0; i < child_import->importers.length; i += 1) {
- child_import->importers.at(i).import->any_imports_failed = true;
- }
+ if (pointer_only && node->type == NodeTypeStructDecl) {
return;
}
- if (g->verbose) {
- fprintf(stderr, "\nc_import:\n");
- fprintf(stderr, "-----------\n");
- ast_render(stderr, child_import->root, 4);
- }
-
- child_import->di_file = parent_import->di_file;
- child_import->block_context = new_block_context(child_import->root, nullptr);
-
- detect_top_level_decl_deps(g, child_import, child_import->root);
- analyze_top_level_decls_root(g, child_import, child_import->root);
-}
+ ImportTableEntry *import = tld->import;
+ assert(import);
-static void satisfy_dep(CodeGen *g, AstNode *node) {
- Buf *name = get_resolved_top_level_decl(node)->name;
- if (name) {
- g->unresolved_top_level_decls.maybe_remove(name);
+ if (tld->dep_loop_flag) {
+ add_node_error(g, node, buf_sprintf("'%s' depends on itself", buf_ptr(tld->name)));
+ tld->resolution = TldResolutionInvalid;
+ return;
+ } else {
+ tld->dep_loop_flag = true;
}
-}
-static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
switch (node->type) {
case NodeTypeFnProto:
preview_fn_proto(g, import, node);
break;
- case NodeTypeRootExportDecl:
- // handled earlier
- return;
case NodeTypeStructDecl:
{
TypeTableEntry *type_entry = node->data.struct_decl.type_entry;
@@ -1526,8 +1429,10 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
}
case NodeTypeVariableDeclaration:
{
- VariableTableEntry *var = analyze_variable_declaration(g, import, import->block_context,
- nullptr, node);
+ AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;
+ VariableTableEntry *var = analyze_variable_declaration_raw(g, import, import->block_context,
+ node, variable_declaration, false, node);
+
g->global_vars.append(var);
break;
}
@@ -1547,34 +1452,13 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
entry = get_typedecl_type(g, buf_ptr(decl_name), child_type);
}
}
-
- import->type_table.put(decl_name, entry);
-
- bool is_pub = (node->data.type_decl.visib_mod != VisibModPrivate);
- if (is_pub) {
- for (int i = 0; i < import->importers.length; i += 1) {
- ImporterInfo importer = import->importers.at(i);
- auto table_entry = importer.import->type_table.maybe_get(&entry->name);
- if (table_entry) {
- add_node_error(g, importer.source_node,
- buf_sprintf("import of type '%s' overrides existing definition",
- buf_ptr(&entry->name)));
- } else {
- importer.import->type_table.put(&entry->name, entry);
- }
- }
- }
-
+ node->data.type_decl.child_type_entry = entry;
break;
}
case NodeTypeErrorValueDecl:
- resolve_error_value_decl(g, import, node);
break;
- case NodeTypeImport:
- // nothing to do here
- return;
- case NodeTypeCImport:
- resolve_c_import_decl(g, import, node);
+ case NodeTypeUse:
+ zig_panic("TODO resolve_top_level_decl NodeTypeUse");
break;
case NodeTypeFnDef:
case NodeTypeDirective:
@@ -1619,8 +1503,8 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
zig_unreachable();
}
-
- satisfy_dep(g, node);
+ tld->resolution = TldResolutionOk;
+ tld->dep_loop_flag = false;
}
static FnTableEntry *get_context_fn_entry(BlockContext *context) {
@@ -1656,6 +1540,7 @@ static bool type_has_codegen_value(TypeTableEntry *type_entry) {
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdUndefLit:
+ case TypeTableEntryIdNamespace:
return false;
case TypeTableEntryIdBool:
@@ -2063,7 +1948,8 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
BlockContext *context = allocate<BlockContext>(1);
context->node = node;
context->parent = parent;
- context->variable_table.init(4);
+ context->decl_table.init(1);
+ context->var_table.init(1);
if (parent) {
context->parent_loop_node = parent->parent_loop_node;
@@ -2085,23 +1971,28 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
return context;
}
-static VariableTableEntry *find_variable(BlockContext *context, Buf *name, bool local_only) {
- while (context && (!local_only || context->fn_entry)) {
- auto entry = context->variable_table.maybe_get(name);
- if (entry)
+static AstNode *find_decl(BlockContext *context, Buf *name) {
+ while (context) {
+ auto entry = context->decl_table.maybe_get(name);
+ if (entry) {
return entry->value;
-
+ }
context = context->parent;
}
return nullptr;
}
-static TypeTableEntry *find_container(ImportTableEntry *import, Buf *name) {
- auto entry = import->type_table.maybe_get(name);
- if (entry)
- return entry->value;
- else
- return nullptr;
+static VariableTableEntry *find_variable(CodeGen *g, BlockContext *orig_context, Buf *name) {
+ BlockContext *context = orig_context;
+ while (context) {
+ auto entry = context->var_table.maybe_get(name);
+ if (entry) {
+ return entry->value;
+ }
+ context = context->parent;
+ }
+
+ return nullptr;
}
static TypeEnumField *get_enum_field(TypeTableEntry *enum_type, Buf *name) {
@@ -2155,6 +2046,7 @@ static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *imp
static TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name) {
assert(type_entry->id == TypeTableEntryIdStruct);
+ assert(type_entry->data.structure.complete);
for (uint32_t i = 0; i < type_entry->data.structure.src_field_count; i += 1) {
TypeStructField *field = &type_entry->data.structure.fields[i];
if (buf_eql_buf(field->name, name)) {
@@ -2330,8 +2222,8 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
{
assert(node->type == NodeTypeFieldAccessExpr);
- AstNode *struct_expr_node = node->data.field_access_expr.struct_expr;
- TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, struct_expr_node);
+ AstNode **struct_expr_node = &node->data.field_access_expr.struct_expr;
+ TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, *struct_expr_node);
Buf *field_name = &node->data.field_access_expr.field_name;
bool wrapped_in_fn_call = node->data.field_access_expr.is_fn_call;
@@ -2342,17 +2234,30 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
TypeTableEntry *bare_struct_type = (struct_type->id == TypeTableEntryIdStruct) ?
struct_type : struct_type->data.pointer.child_type;
+ if (!bare_struct_type->data.structure.complete) {
+ resolve_struct_type(g, bare_struct_type->data.structure.decl_node->owner, bare_struct_type);
+ }
+
node->data.field_access_expr.bare_struct_type = bare_struct_type;
node->data.field_access_expr.type_struct_field = find_struct_type_field(bare_struct_type, field_name);
if (node->data.field_access_expr.type_struct_field) {
return node->data.field_access_expr.type_struct_field->type_entry;
} else if (wrapped_in_fn_call) {
- auto table_entry = bare_struct_type->data.structure.fn_table.maybe_get(field_name);
- if (table_entry) {
+ BlockContext *container_block_context = get_container_block_context(bare_struct_type);
+ auto entry = container_block_context->decl_table.maybe_get(field_name);
+ AstNode *fn_decl_node = entry ? entry->value : nullptr;
+ if (fn_decl_node && fn_decl_node->type == NodeTypeFnProto) {
+ resolve_top_level_decl(g, fn_decl_node, false);
+ TopLevelDecl *tld = get_as_top_level_decl(fn_decl_node);
+ if (tld->resolution == TldResolutionInvalid) {
+ return g->builtin_types.entry_invalid;
+ }
+
node->data.field_access_expr.is_member_fn = true;
- return resolve_expr_const_val_as_fn(g, node, context, table_entry->value);
+ FnTableEntry *fn_entry = fn_decl_node->data.fn_proto.fn_table_entry;
+ return resolve_expr_const_val_as_fn(g, node, fn_entry);
} else {
- add_node_error(g, node, buf_sprintf("no member named '%s' in '%s'",
+ add_node_error(g, node, buf_sprintf("no function named '%s' in '%s'",
buf_ptr(field_name), buf_ptr(&bare_struct_type->name)));
return g->builtin_types.entry_invalid;
}
@@ -2372,7 +2277,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
return g->builtin_types.entry_invalid;
}
} else if (struct_type->id == TypeTableEntryIdMetaType) {
- TypeTableEntry *child_type = resolve_type(g, struct_expr_node);
+ TypeTableEntry *child_type = resolve_type(g, *struct_expr_node);
if (child_type->id == TypeTableEntryIdInvalid) {
return g->builtin_types.entry_invalid;
@@ -2381,12 +2286,15 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
} else if (child_type->id == TypeTableEntryIdEnum) {
return analyze_enum_value_expr(g, import, context, node, nullptr, child_type, field_name);
} else if (child_type->id == TypeTableEntryIdStruct) {
- auto entry = child_type->data.structure.fn_table.maybe_get(field_name);
- if (entry) {
- return resolve_expr_const_val_as_fn(g, node, context, entry->value);
+ BlockContext *container_block_context = get_container_block_context(child_type);
+ auto entry = container_block_context->decl_table.maybe_get(field_name);
+ AstNode *decl_node = entry ? entry->value : nullptr;
+ if (decl_node) {
+ bool pointer_only = false;
+ return analyze_decl_ref(g, node, decl_node, pointer_only);
} else {
add_node_error(g, node,
- buf_sprintf("struct '%s' has no function called '%s'",
+ buf_sprintf("container '%s' has no member called '%s'",
buf_ptr(&child_type->name), buf_ptr(field_name)));
return g->builtin_types.entry_invalid;
}
@@ -2397,6 +2305,26 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name)));
return g->builtin_types.entry_invalid;
}
+ } else if (struct_type->id == TypeTableEntryIdNamespace) {
+ ConstExprValue *const_val = &get_resolved_expr(*struct_expr_node)->const_val;
+ assert(const_val->ok);
+ ImportTableEntry *namespace_import = const_val->data.x_import;
+ AstNode *decl_node = find_decl(namespace_import->block_context, field_name);
+ if (decl_node) {
+ TopLevelDecl *tld = get_as_top_level_decl(decl_node);
+ if (tld->visib_mod == VisibModPrivate) {
+ ErrorMsg *msg = add_node_error(g, node,
+ buf_sprintf("'%s' is private", buf_ptr(field_name)));
+ add_error_note(g, msg, decl_node, buf_sprintf("declared here"));
+ }
+ bool pointer_only = false;
+ return analyze_decl_ref(g, node, decl_node, pointer_only);
+ } else {
+ add_node_error(g, node,
+ buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
+ buf_ptr(namespace_import->path)));
+ return g->builtin_types.entry_invalid;
+ }
} else {
if (struct_type->id != TypeTableEntryIdInvalid) {
add_node_error(g, node,
@@ -2500,12 +2428,7 @@ static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode
return other_expr->type_entry;
}
-static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, BlockContext *context,
- FnTableEntry *fn)
-{
- if (!context->codegen_excluded) {
- fn->ref_count += 1;
- }
+static TypeTableEntry *resolve_expr_const_val_as_fn(CodeGen *g, AstNode *node, FnTableEntry *fn) {
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_fn = fn;
@@ -2635,7 +2558,7 @@ static TypeTableEntry *resolve_expr_const_val_as_bignum_op(CodeGen *g, AstNode *
static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *node, Buf *err_name)
{
- auto err_table_entry = import->error_table.maybe_get(err_name);
+ auto err_table_entry = g->error_table.maybe_get(err_name);
if (err_table_entry) {
return resolve_expr_const_val_as_err(g, node, err_table_entry->value);
@@ -2647,9 +2570,48 @@ static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *
return g->builtin_types.entry_invalid;
}
+static TypeTableEntry *analyze_var_ref(CodeGen *g, AstNode *source_node, VariableTableEntry *var) {
+ get_resolved_expr(source_node)->variable = var;
+ if (var->is_const) {
+ AstNode *decl_node = var->decl_node;
+ if (decl_node->type == NodeTypeVariableDeclaration) {
+ AstNode *expr_node = decl_node->data.variable_declaration.expr;
+ ConstExprValue *other_const_val = &get_resolved_expr(expr_node)->const_val;
+ if (other_const_val->ok) {
+ return resolve_expr_const_val_as_other_expr(g, source_node, expr_node);
+ }
+ }
+ }
+ return var->type;
+}
+
+static TypeTableEntry *analyze_decl_ref(CodeGen *g, AstNode *source_node, AstNode *decl_node,
+ bool pointer_only)
+{
+ resolve_top_level_decl(g, decl_node, pointer_only);
+ TopLevelDecl *tld = get_as_top_level_decl(decl_node);
+ if (tld->resolution == TldResolutionInvalid) {
+ return g->builtin_types.entry_invalid;
+ }
+
+ if (decl_node->type == NodeTypeVariableDeclaration) {
+ VariableTableEntry *var = decl_node->data.variable_declaration.variable;
+ return analyze_var_ref(g, source_node, var);
+ } else if (decl_node->type == NodeTypeFnProto) {
+ FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry;
+ assert(fn_entry->type_entry);
+ return resolve_expr_const_val_as_fn(g, source_node, fn_entry);
+ } else if (decl_node->type == NodeTypeStructDecl) {
+ return resolve_expr_const_val_as_type(g, source_node, decl_node->data.struct_decl.type_entry);
+ } else if (decl_node->type == NodeTypeTypeDecl) {
+ return resolve_expr_const_val_as_type(g, source_node, decl_node->data.type_decl.child_type_entry);
+ } else {
+ zig_unreachable();
+ }
+}
static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
+ TypeTableEntry *expected_type, AstNode *node, bool pointer_only)
{
if (node->data.symbol_expr.override_type_entry) {
return resolve_expr_const_val_as_type(g, node, node->data.symbol_expr.override_type_entry);
@@ -2662,32 +2624,14 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
return resolve_expr_const_val_as_type(g, node, primitive_table_entry->value);
}
- VariableTableEntry *var = find_variable(context, variable_name, false);
+ VariableTableEntry *var = find_variable(g, context, variable_name);
if (var) {
- node->data.symbol_expr.variable = var;
- if (var->is_const) {
- AstNode *decl_node = var->decl_node;
- if (decl_node->type == NodeTypeVariableDeclaration) {
- AstNode *expr_node = decl_node->data.variable_declaration.expr;
- ConstExprValue *other_const_val = &get_resolved_expr(expr_node)->const_val;
- if (other_const_val->ok) {
- return resolve_expr_const_val_as_other_expr(g, node, expr_node);
- }
- }
- }
- return var->type;
- }
-
- TypeTableEntry *container_type = find_container(import, variable_name);
- if (container_type) {
- return resolve_expr_const_val_as_type(g, node, container_type);
+ return analyze_var_ref(g, node, var);
}
- auto fn_table_entry = import->fn_table.maybe_get(variable_name);
- if (fn_table_entry) {
- assert(fn_table_entry->value->type_entry);
- node->data.symbol_expr.fn_entry = fn_table_entry->value;
- return resolve_expr_const_val_as_fn(g, node, context, fn_table_entry->value);
+ AstNode *decl_node = find_decl(context, variable_name);
+ if (decl_node) {
+ return analyze_decl_ref(g, node, decl_node, pointer_only);
}
if (import->any_imports_failed) {
@@ -2760,18 +2704,21 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc
TypeTableEntry *expected_rhs_type = nullptr;
lhs_node->block_context = block_context;
if (lhs_node->type == NodeTypeSymbol) {
- Buf *name = &lhs_node->data.symbol_expr.symbol;
- if (purpose == LValPurposeAddressOf) {
- expected_rhs_type = analyze_symbol_expr(g, import, block_context, nullptr, lhs_node);
- } else {
- VariableTableEntry *var = find_variable(block_context, name, false);
+ bool pointer_only = purpose == LValPurposeAddressOf;
+ expected_rhs_type = analyze_symbol_expr(g, import, block_context, nullptr, lhs_node, pointer_only);
+ if (expected_rhs_type->id == TypeTableEntryIdInvalid) {
+ return g->builtin_types.entry_invalid;
+ }
+ if (purpose != LValPurposeAddressOf) {
+ Buf *name = &lhs_node->data.symbol_expr.symbol;
+ VariableTableEntry *var = find_variable(g, block_context, name);
if (var) {
if (var->is_const) {
add_node_error(g, lhs_node, buf_sprintf("cannot assign to constant"));
expected_rhs_type = g->builtin_types.entry_invalid;
} else {
expected_rhs_type = var->type;
- lhs_node->data.symbol_expr.variable = var;
+ get_resolved_expr(lhs_node)->variable = var;
}
} else {
add_node_error(g, lhs_node,
@@ -3176,29 +3123,36 @@ static VariableTableEntry *add_local_var(CodeGen *g, AstNode *source_node, Impor
if (name) {
buf_init_from_buf(&variable_entry->name, name);
- VariableTableEntry *existing_var;
- existing_var = find_variable(context, name, context->fn_entry != nullptr);
-
- if (existing_var) {
- add_node_error(g, source_node, buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
- variable_entry->type = g->builtin_types.entry_invalid;
- } else {
- auto primitive_table_entry = g->primitive_type_table.maybe_get(name);
- TypeTableEntry *type;
- if (primitive_table_entry) {
- type = primitive_table_entry->value;
- } else {
- type = find_container(import, name);
- }
- if (type) {
- add_node_error(g, source_node, buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
+ if (type_entry->id != TypeTableEntryIdInvalid) {
+ VariableTableEntry *existing_var = find_variable(g, context, name);
+ if (existing_var) {
+ ErrorMsg *msg = add_node_error(g, source_node,
+ buf_sprintf("redeclaration of variable '%s'", buf_ptr(name)));
+ add_error_note(g, msg, existing_var->decl_node, buf_sprintf("previous declaration is here"));
variable_entry->type = g->builtin_types.entry_invalid;
+ } else {
+ auto primitive_table_entry = g->primitive_type_table.maybe_get(name);
+ if (primitive_table_entry) {
+ TypeTableEntry *type = primitive_table_entry->value;
+ add_node_error(g, source_node,
+ buf_sprintf("variable shadows type '%s'", buf_ptr(&type->name)));
+ variable_entry->type = g->builtin_types.entry_invalid;
+ } else {
+ AstNode *decl_node = find_decl(context, name);
+ if (decl_node && decl_node->type != NodeTypeVariableDeclaration) {
+ ErrorMsg *msg = add_node_error(g, source_node,
+ buf_sprintf("redefinition of '%s'", buf_ptr(name)));
+ add_error_note(g, msg, decl_node, buf_sprintf("previous definition is here"));
+ variable_entry->type = g->builtin_types.entry_invalid;
+ }
+ }
}
}
- context->variable_table.put(&variable_entry->name, variable_entry);
+ context->var_table.put(&variable_entry->name, variable_entry);
} else {
+ // TODO replace _anon with @anon and make sure all tests still pass
buf_init_from_str(&variable_entry->name, "_anon");
}
if (context->fn_entry) {
@@ -3248,10 +3202,10 @@ static TypeTableEntry *analyze_unwrap_error_expr(CodeGen *g, ImportTableEntry *i
static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *source_node,
AstNodeVariableDeclaration *variable_declaration,
- bool expr_is_maybe)
+ bool expr_is_maybe, AstNode *decl_node)
{
bool is_const = variable_declaration->is_const;
- bool is_export = (variable_declaration->visib_mod == VisibModExport);
+ bool is_export = (variable_declaration->top_level_decl.visib_mod == VisibModExport);
bool is_extern = variable_declaration->is_extern;
TypeTableEntry *explicit_type = nullptr;
@@ -3312,22 +3266,6 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
variable_declaration->variable = var;
-
- bool is_pub = (variable_declaration->visib_mod != VisibModPrivate);
- if (is_pub) {
- for (int i = 0; i < import->importers.length; i += 1) {
- ImporterInfo importer = import->importers.at(i);
- auto table_entry = importer.import->block_context->variable_table.maybe_get(&var->name);
- if (table_entry) {
- add_node_error(g, importer.source_node,
- buf_sprintf("import of variable '%s' overrides existing definition",
- buf_ptr(&var->name)));
- } else {
- importer.import->block_context->variable_table.put(&var->name, var);
- }
- }
- }
-
return var;
}
@@ -3335,7 +3273,7 @@ static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableE
BlockContext *context, TypeTableEntry *expected_type, AstNode *node)
{
AstNodeVariableDeclaration *variable_declaration = &node->data.variable_declaration;
- return analyze_variable_declaration_raw(g, import, context, node, variable_declaration, false);
+ return analyze_variable_declaration_raw(g, import, context, node, variable_declaration, false, nullptr);
}
static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *import,
@@ -3516,7 +3454,8 @@ static TypeTableEntry *analyze_for_expr(CodeGen *g, ImportTableEntry *import, Bl
AstNode *elem_var_node = node->data.for_expr.elem_node;
elem_var_node->block_context = child_context;
Buf *elem_var_name = &elem_var_node->data.symbol_expr.symbol;
- node->data.for_expr.elem_var = add_local_var(g, elem_var_node, import, child_context, elem_var_name, child_type, true);
+ node->data.for_expr.elem_var = add_local_var(g, elem_var_node, import, child_context, elem_var_name,
+ child_type, true);
AstNode *index_var_node = node->data.for_expr.index_node;
if (index_var_node) {
@@ -3673,7 +3612,8 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import,
BlockContext *child_context = new_block_context(node, parent_context);
- analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true);
+ analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true,
+ nullptr);
VariableTableEntry *var = node->data.if_var_expr.var_decl.variable;
if (var->type->id == TypeTableEntryIdInvalid) {
return g->builtin_types.entry_invalid;
@@ -4069,39 +4009,178 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
return g->builtin_types.entry_invalid;
}
-static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
+static TypeTableEntry *resolve_expr_const_val_as_import(CodeGen *g, AstNode *node, ImportTableEntry *import) {
+ Expr *expr = get_resolved_expr(node);
+ expr->const_val.ok = true;
+ expr->const_val.data.x_import = import;
+ return g->builtin_types.entry_namespace;
+}
+
+static TypeTableEntry *analyze_import(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+ AstNode *node)
{
assert(node->type == NodeTypeFnCallExpr);
- AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
- Buf *name = &fn_ref_expr->data.symbol_expr.symbol;
-
- auto entry = g->builtin_fn_table.maybe_get(name);
+ if (context != import->block_context) {
+ add_node_error(g, node, buf_sprintf("@import valid only at top level scope"));
+ return g->builtin_types.entry_invalid;
+ }
- if (!entry) {
- add_node_error(g, node,
- buf_sprintf("invalid builtin function: '%s'", buf_ptr(name)));
+ AstNode *first_param_node = node->data.fn_call_expr.params.at(0);
+ Buf *import_target_str = resolve_const_expr_str(g, import, context, first_param_node->parent_field);
+ if (!import_target_str) {
return g->builtin_types.entry_invalid;
}
- BuiltinFnEntry *builtin_fn = entry->value;
- int actual_param_count = node->data.fn_call_expr.params.length;
+ Buf *import_target_path;
+ Buf *search_dir;
+ assert(import->package);
+ PackageTableEntry *target_package;
+ auto package_entry = import->package->package_table.maybe_get(import_target_str);
+ if (package_entry) {
+ target_package = package_entry->value;
+ import_target_path = &target_package->root_src_path;
+ search_dir = &target_package->root_src_dir;
+ } else {
+ // try it as a filename
+ target_package = import->package;
+ import_target_path = import_target_str;
+ search_dir = &import->package->root_src_dir;
+ }
- node->data.fn_call_expr.builtin_fn = builtin_fn;
+ Buf full_path = BUF_INIT;
+ os_path_join(search_dir, import_target_path, &full_path);
- if (builtin_fn->param_count != actual_param_count) {
- add_node_error(g, node,
- buf_sprintf("expected %d arguments, got %d",
- builtin_fn->param_count, actual_param_count));
+ Buf *import_code = buf_alloc();
+ Buf *abs_full_path = buf_alloc();
+ int err;
+ if ((err = os_path_real(&full_path, abs_full_path))) {
+ if (err == ErrorFileNotFound) {
+ add_node_error(g, node,
+ buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
+ return g->builtin_types.entry_invalid;
+ } else {
+ g->error_during_imports = true;
+ add_node_error(g, node,
+ buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
+ return g->builtin_types.entry_invalid;
+ }
+ }
+
+ auto import_entry = g->import_table.maybe_get(abs_full_path);
+ if (import_entry) {
+ return resolve_expr_const_val_as_import(g, node, import_entry->value);
+ }
+
+ if ((err = os_fetch_file_path(abs_full_path, import_code))) {
+ if (err == ErrorFileNotFound) {
+ add_node_error(g, node,
+ buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
+ return g->builtin_types.entry_invalid;
+ } else {
+ add_node_error(g, node,
+ buf_sprintf("unable to open '%s': %s", buf_ptr(&full_path), err_str(err)));
+ return g->builtin_types.entry_invalid;
+ }
+ }
+ ImportTableEntry *target_import = add_source_file(g, target_package,
+ abs_full_path, search_dir, import_target_path, import_code);
+
+ scan_decls(g, target_import, target_import->block_context, target_import->root);
+
+ return resolve_expr_const_val_as_import(g, node, target_import);
+}
+
+static TypeTableEntry *analyze_c_import(CodeGen *g, ImportTableEntry *parent_import,
+ BlockContext *parent_context, AstNode *node)
+{
+ assert(node->type == NodeTypeFnCallExpr);
+
+ if (parent_context != parent_import->block_context) {
+ add_node_error(g, node, buf_sprintf("@c_import valid only at top level scope"));
return g->builtin_types.entry_invalid;
}
- builtin_fn->ref_count += 1;
+ AstNode *block_node = node->data.fn_call_expr.params.at(0);
- switch (builtin_fn->id) {
- case BuiltinFnIdInvalid:
- zig_unreachable();
+ BlockContext *child_context = new_block_context(node, parent_context);
+ child_context->c_import_buf = buf_alloc();
+
+ TypeTableEntry *resolved_type = analyze_expression(g, parent_import, child_context,
+ g->builtin_types.entry_void, block_node);
+
+ if (resolved_type->id == TypeTableEntryIdInvalid) {
+ return resolved_type;
+ }
+
+ find_libc_include_path(g);
+
+ ImportTableEntry *child_import = allocate<ImportTableEntry>(1);
+ child_import->c_import_node = node;
+
+ ZigList<ErrorMsg *> errors = {0};
+
+ int err;
+ if ((err = parse_h_buf(child_import, &errors, child_context->c_import_buf, g, node))) {
+ zig_panic("unable to parse h file: %s\n", err_str(err));
+ }
+
+ if (errors.length > 0) {
+ ErrorMsg *parent_err_msg = add_node_error(g, node, buf_sprintf("C import failed"));
+ for (int i = 0; i < errors.length; i += 1) {
+ ErrorMsg *err_msg = errors.at(i);
+ err_msg_add_note(parent_err_msg, err_msg);
+ }
+
+ return g->builtin_types.entry_invalid;
+ }
+
+ if (g->verbose) {
+ fprintf(stderr, "\nc_import:\n");
+ fprintf(stderr, "-----------\n");
+ ast_render(stderr, child_import->root, 4);
+ }
+
+ child_import->di_file = parent_import->di_file;
+ child_import->block_context = new_block_context(child_import->root, nullptr);
+
+ scan_decls(g, child_import, child_import->block_context, child_import->root);
+ return resolve_expr_const_val_as_import(g, node, child_import);
+}
+
+static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+ TypeTableEntry *expected_type, AstNode *node)
+{
+ assert(node->type == NodeTypeFnCallExpr);
+
+ AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
+ Buf *name = &fn_ref_expr->data.symbol_expr.symbol;
+
+ auto entry = g->builtin_fn_table.maybe_get(name);
+
+ if (!entry) {
+ add_node_error(g, node,
+ buf_sprintf("invalid builtin function: '%s'", buf_ptr(name)));
+ return g->builtin_types.entry_invalid;
+ }
+
+ BuiltinFnEntry *builtin_fn = entry->value;
+ int actual_param_count = node->data.fn_call_expr.params.length;
+
+ node->data.fn_call_expr.builtin_fn = builtin_fn;
+
+ if (builtin_fn->param_count != actual_param_count) {
+ add_node_error(g, node,
+ buf_sprintf("expected %d arguments, got %d",
+ builtin_fn->param_count, actual_param_count));
+ return g->builtin_types.entry_invalid;
+ }
+
+ builtin_fn->ref_count += 1;
+
+ switch (builtin_fn->id) {
+ case BuiltinFnIdInvalid:
+ zig_unreachable();
case BuiltinFnIdAddWithOverflow:
case BuiltinFnIdSubWithOverflow:
case BuiltinFnIdMulWithOverflow:
@@ -4252,6 +4331,7 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdUndefLit:
+ case TypeTableEntryIdNamespace:
add_node_error(g, expr_node,
buf_sprintf("type '%s' not eligible for @typeof", buf_ptr(&type_entry->name)));
return g->builtin_types.entry_invalid;
@@ -4391,6 +4471,10 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
return g->builtin_types.entry_invalid;
}
}
+ case BuiltinFnIdImport:
+ return analyze_import(g, import, context, node);
+ case BuiltinFnIdCImport:
+ return analyze_c_import(g, import, context, node);
}
zig_unreachable();
@@ -4456,12 +4540,7 @@ static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import,
node->data.fn_call_expr.fn_entry = fn_table_entry;
- if (!context->codegen_excluded) {
- fn_table_entry->ref_count += 1;
- }
-
return analyze_fn_call_ptr(g, import, context, expected_type, node, fn_table_entry->type_entry, struct_type);
-
}
static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@@ -4515,10 +4594,16 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
}
} else if (child_type->id == TypeTableEntryIdStruct) {
Buf *field_name = &fn_ref_expr->data.field_access_expr.field_name;
- auto entry = child_type->data.structure.fn_table.maybe_get(field_name);
- if (entry) {
- return analyze_fn_call_raw(g, import, context, expected_type, node,
- entry->value, nullptr);
+ BlockContext *container_block_context = get_container_block_context(child_type);
+ auto entry = container_block_context->decl_table.maybe_get(field_name);
+ AstNode *decl_node = entry ? entry->value : nullptr;
+ if (decl_node && decl_node->type == NodeTypeFnProto) {
+ bool pointer_only = false;
+ resolve_top_level_decl(g, decl_node, pointer_only);
+
+ FnTableEntry *fn_entry = decl_node->data.fn_proto.fn_table_entry;
+ assert(fn_entry);
+ return analyze_fn_call_raw(g, import, context, expected_type, node, fn_entry, nullptr);
} else {
add_node_error(g, node,
buf_sprintf("struct '%s' has no function called '%s'",
@@ -4565,19 +4650,19 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
TypeTableEntry *expected_type, AstNode *node)
{
PrefixOp prefix_op = node->data.prefix_op_expr.prefix_op;
- AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
+ AstNode **expr_node = &node->data.prefix_op_expr.primary_expr;
switch (prefix_op) {
case PrefixOpInvalid:
zig_unreachable();
case PrefixOpBoolNot:
{
TypeTableEntry *type_entry = analyze_expression(g, import, context, g->builtin_types.entry_bool,
- expr_node);
+ *expr_node);
if (type_entry->id == TypeTableEntryIdInvalid) {
return g->builtin_types.entry_bool;
}
- ConstExprValue *target_const_val = &get_resolved_expr(expr_node)->const_val;
+ ConstExprValue *target_const_val = &get_resolved_expr(*expr_node)->const_val;
if (!target_const_val->ok) {
return g->builtin_types.entry_bool;
}
@@ -4588,7 +4673,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
case PrefixOpBinNot:
{
TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type,
- expr_node);
+ *expr_node);
if (expr_type->id == TypeTableEntryIdInvalid) {
return expr_type;
} else if (expr_type->id == TypeTableEntryIdInt ||
@@ -4596,7 +4681,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
{
return expr_type;
} else {
- add_node_error(g, expr_node, buf_sprintf("invalid binary not type: '%s'",
+ add_node_error(g, *expr_node, buf_sprintf("invalid binary not type: '%s'",
buf_ptr(&expr_type->name)));
return g->builtin_types.entry_invalid;
}
@@ -4604,8 +4689,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
}
case PrefixOpNegation:
{
- TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type,
- expr_node);
+ TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type, *expr_node);
if (expr_type->id == TypeTableEntryIdInvalid) {
return expr_type;
} else if ((expr_type->id == TypeTableEntryIdInt &&
@@ -4614,7 +4698,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
expr_type->id == TypeTableEntryIdNumLitInt ||
expr_type->id == TypeTableEntryIdNumLitFloat)
{
- ConstExprValue *target_const_val = &get_resolved_expr(expr_node)->const_val;
+ ConstExprValue *target_const_val = &get_resolved_expr(*expr_node)->const_val;
if (!target_const_val->ok) {
return expr_type;
}
@@ -4635,12 +4719,13 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
bool is_const = (prefix_op == PrefixOpConstAddressOf);
TypeTableEntry *child_type = analyze_lvalue(g, import, context,
- expr_node, LValPurposeAddressOf, is_const);
+ *expr_node, LValPurposeAddressOf, is_const);
if (child_type->id == TypeTableEntryIdInvalid) {
return g->builtin_types.entry_invalid;
} else if (child_type->id == TypeTableEntryIdMetaType) {
- TypeTableEntry *meta_type = analyze_type_expr(g, import, context, expr_node);
+ TypeTableEntry *meta_type = analyze_type_expr_pointer_only(g, import, context,
+ *expr_node, true);
if (meta_type->id == TypeTableEntryIdInvalid) {
return g->builtin_types.entry_invalid;
} else if (meta_type->id == TypeTableEntryIdUnreachable) {
@@ -4653,7 +4738,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
} else if (child_type->id == TypeTableEntryIdNumLitInt ||
child_type->id == TypeTableEntryIdNumLitFloat)
{
- add_node_error(g, expr_node,
+ add_node_error(g, *expr_node,
buf_sprintf("unable to get address of type '%s'", buf_ptr(&child_type->name)));
return g->builtin_types.entry_invalid;
} else {
@@ -4662,13 +4747,13 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
}
case PrefixOpDereference:
{
- TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node);
+ TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, *expr_node);
if (type_entry->id == TypeTableEntryIdInvalid) {
return type_entry;
} else if (type_entry->id == TypeTableEntryIdPointer) {
return type_entry->data.pointer.child_type;
} else {
- add_node_error(g, expr_node,
+ add_node_error(g, *expr_node,
buf_sprintf("indirection requires pointer operand ('%s' invalid)",
buf_ptr(&type_entry->name)));
return g->builtin_types.entry_invalid;
@@ -4676,12 +4761,12 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
}
case PrefixOpMaybe:
{
- TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node);
+ TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, *expr_node);
if (type_entry->id == TypeTableEntryIdInvalid) {
return type_entry;
} else if (type_entry->id == TypeTableEntryIdMetaType) {
- TypeTableEntry *meta_type = resolve_type(g, expr_node);
+ TypeTableEntry *meta_type = resolve_type(g, *expr_node);
if (meta_type->id == TypeTableEntryIdInvalid) {
return g->builtin_types.entry_invalid;
} else if (meta_type->id == TypeTableEntryIdUnreachable) {
@@ -4691,10 +4776,10 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
return resolve_expr_const_val_as_type(g, node, get_maybe_type(g, meta_type));
}
} else if (type_entry->id == TypeTableEntryIdUnreachable) {
- add_node_error(g, expr_node, buf_sprintf("unable to wrap unreachable in maybe type"));
+ add_node_error(g, *expr_node, buf_sprintf("unable to wrap unreachable in maybe type"));
return g->builtin_types.entry_invalid;
} else {
- ConstExprValue *target_const_val = &get_resolved_expr(expr_node)->const_val;
+ ConstExprValue *target_const_val = &get_resolved_expr(*expr_node)->const_val;
TypeTableEntry *maybe_type = get_maybe_type(g, type_entry);
if (!target_const_val->ok) {
return maybe_type;
@@ -4704,12 +4789,12 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
}
case PrefixOpError:
{
- TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node);
+ TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, *expr_node);
if (type_entry->id == TypeTableEntryIdInvalid) {
return type_entry;
} else if (type_entry->id == TypeTableEntryIdMetaType) {
- TypeTableEntry *meta_type = resolve_type(g, expr_node);
+ TypeTableEntry *meta_type = resolve_type(g, *expr_node);
if (meta_type->id == TypeTableEntryIdInvalid) {
return meta_type;
} else if (meta_type->id == TypeTableEntryIdUnreachable) {
@@ -4719,7 +4804,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
return resolve_expr_const_val_as_type(g, node, get_error_type(g, meta_type));
}
} else if (type_entry->id == TypeTableEntryIdUnreachable) {
- add_node_error(g, expr_node, buf_sprintf("unable to wrap unreachable in error type"));
+ add_node_error(g, *expr_node, buf_sprintf("unable to wrap unreachable in error type"));
return g->builtin_types.entry_invalid;
} else {
// TODO eval const expr
@@ -4729,28 +4814,28 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
}
case PrefixOpUnwrapError:
{
- TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node);
+ TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, *expr_node);
if (type_entry->id == TypeTableEntryIdInvalid) {
return type_entry;
} else if (type_entry->id == TypeTableEntryIdErrorUnion) {
return type_entry->data.error.child_type;
} else {
- add_node_error(g, expr_node,
+ add_node_error(g, *expr_node,
buf_sprintf("expected error type, got '%s'", buf_ptr(&type_entry->name)));
return g->builtin_types.entry_invalid;
}
}
case PrefixOpUnwrapMaybe:
{
- TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node);
+ TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, *expr_node);
if (type_entry->id == TypeTableEntryIdInvalid) {
return type_entry;
} else if (type_entry->id == TypeTableEntryIdMaybe) {
return type_entry->data.maybe.child_type;
} else {
- add_node_error(g, expr_node,
+ add_node_error(g, *expr_node,
buf_sprintf("expected maybe type, got '%s'", buf_ptr(&type_entry->name)));
return g->builtin_types.entry_invalid;
}
@@ -5094,7 +5179,7 @@ static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, Bl
}
} else {
Buf *variable_name = &asm_output->variable_name;
- VariableTableEntry *var = find_variable(context, variable_name, false);
+ VariableTableEntry *var = find_variable(g, context, variable_name);
if (var) {
asm_output->variable = var;
return var->type;
@@ -5120,10 +5205,8 @@ static TypeTableEntry *analyze_goto(CodeGen *g, ImportTableEntry *import, BlockC
return g->builtin_types.entry_unreachable;
}
-// When you call analyze_expression, the node you pass might no longer be the child node
-// you thought it was due to implicit casting rewriting the AST.
-static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
+static TypeTableEntry *analyze_expression_pointer_only(CodeGen *g, ImportTableEntry *import,
+ BlockContext *context, TypeTableEntry *expected_type, AstNode *node, bool pointer_only)
{
assert(!expected_type || expected_type->id != TypeTableEntryIdInvalid);
TypeTableEntry *return_type = nullptr;
@@ -5197,7 +5280,7 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
return_type = analyze_undefined_literal_expr(g, import, context, expected_type, node);
break;
case NodeTypeSymbol:
- return_type = analyze_symbol_expr(g, import, context, expected_type, node);
+ return_type = analyze_symbol_expr(g, import, context, expected_type, node, pointer_only);
break;
case NodeTypePrefixOpExpr:
return_type = analyze_prefix_op_expr(g, import, context, expected_type, node);
@@ -5235,10 +5318,8 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeRoot:
- case NodeTypeRootExportDecl:
case NodeTypeFnDef:
- case NodeTypeImport:
- case NodeTypeCImport:
+ case NodeTypeUse:
case NodeTypeLabel:
case NodeTypeStructDecl:
case NodeTypeStructField:
@@ -5263,7 +5344,17 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
return resolved_type;
}
-static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node) {
+// When you call analyze_expression, the node you pass might no longer be the child node
+// you thought it was due to implicit casting rewriting the AST.
+static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+ TypeTableEntry *expected_type, AstNode *node)
+{
+ return analyze_expression_pointer_only(g, import, context, expected_type, node, false);
+}
+
+static void analyze_fn_body(CodeGen *g, FnTableEntry *fn_table_entry) {
+ ImportTableEntry *import = fn_table_entry->import_entry;
+ AstNode *node = fn_table_entry->fn_def_node;
assert(node->type == NodeTypeFnDef);
AstNode *fn_proto_node = node->data.fn_def.fn_proto;
@@ -5277,7 +5368,6 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
BlockContext *context = node->data.fn_def.block_context;
- FnTableEntry *fn_table_entry = fn_proto_node->data.fn_proto.fn_table_entry;
TypeTableEntry *fn_type = fn_table_entry->type_entry;
AstNodeFnProto *fn_proto = &fn_proto_node->data.fn_proto;
for (int i = 0; i < fn_proto->params.length; i += 1) {
@@ -5302,7 +5392,8 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
add_node_error(g, param_decl_node, buf_sprintf("missing parameter name"));
}
- VariableTableEntry *var = add_local_var(g, param_decl_node, import, context, ¶m_decl->name, type, true);
+ VariableTableEntry *var = add_local_var(g, param_decl_node, import, context, ¶m_decl->name,
+ type, true);
var->src_arg_index = i;
param_decl_node->data.param_decl.variable = var;
@@ -5315,375 +5406,71 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
node->data.fn_def.implicit_return_type = block_return_type;
}
-static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
- switch (node->type) {
- case NodeTypeFnDef:
- analyze_top_level_fn_def(g, import, node);
- break;
- case NodeTypeStructDecl:
- {
- for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) {
- AstNode *fn_def_node = node->data.struct_decl.fns.at(i);
- analyze_top_level_fn_def(g, import, fn_def_node);
- }
- break;
- }
- case NodeTypeRootExportDecl:
- case NodeTypeImport:
- case NodeTypeCImport:
- case NodeTypeVariableDeclaration:
- case NodeTypeErrorValueDecl:
- case NodeTypeFnProto:
- case NodeTypeTypeDecl:
- // already took care of these
- break;
- case NodeTypeDirective:
- case NodeTypeParamDecl:
- case NodeTypeFnDecl:
- case NodeTypeReturnExpr:
- case NodeTypeDefer:
- case NodeTypeRoot:
- case NodeTypeBlock:
- case NodeTypeBinOpExpr:
- case NodeTypeUnwrapErrorExpr:
- case NodeTypeFnCallExpr:
- case NodeTypeArrayAccessExpr:
- case NodeTypeSliceExpr:
- case NodeTypeNumberLiteral:
- case NodeTypeStringLiteral:
- case NodeTypeCharLiteral:
- case NodeTypeBoolLiteral:
- case NodeTypeNullLiteral:
- case NodeTypeUndefinedLiteral:
- case NodeTypeSymbol:
- case NodeTypePrefixOpExpr:
- case NodeTypeIfBoolExpr:
- case NodeTypeIfVarExpr:
- case NodeTypeWhileExpr:
- case NodeTypeForExpr:
- case NodeTypeSwitchExpr:
- case NodeTypeSwitchProng:
- case NodeTypeSwitchRange:
- case NodeTypeLabel:
- case NodeTypeGoto:
- case NodeTypeBreak:
- case NodeTypeContinue:
- case NodeTypeAsmExpr:
- case NodeTypeFieldAccessExpr:
- case NodeTypeStructField:
- case NodeTypeStructValueField:
- case NodeTypeContainerInitExpr:
- case NodeTypeArrayType:
- case NodeTypeErrorType:
- case NodeTypeTypeLiteral:
- zig_unreachable();
+static void add_top_level_decl(CodeGen *g, ImportTableEntry *import, BlockContext *block_context,
+ AstNode *node, Buf *name)
+{
+ assert(import);
+
+ TopLevelDecl *tld = get_as_top_level_decl(node);
+ tld->import = import;
+ tld->name = name;
+
+ if (g->check_unused || g->is_test_build || tld->visib_mod == VisibModExport) {
+ g->export_queue.append(node);
}
-}
-static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *node,
- TopLevelDecl *decl_node)
-{
- switch (node->type) {
- case NodeTypeNumberLiteral:
- case NodeTypeStringLiteral:
- case NodeTypeCharLiteral:
- case NodeTypeBoolLiteral:
- case NodeTypeNullLiteral:
- case NodeTypeUndefinedLiteral:
- case NodeTypeGoto:
- case NodeTypeBreak:
- case NodeTypeContinue:
- case NodeTypeErrorValueDecl:
- case NodeTypeErrorType:
- case NodeTypeTypeLiteral:
- // no dependencies on other top level declarations
- break;
- case NodeTypeSymbol:
- {
- if (node->data.symbol_expr.override_type_entry) {
- break;
- }
- Buf *name = &node->data.symbol_expr.symbol;
- auto table_entry = g->primitive_type_table.maybe_get(name);
- if (!table_entry) {
- table_entry = import->type_table.maybe_get(name);
- }
- if (!table_entry || !type_is_complete(table_entry->value)) {
- decl_node->deps.put(name, node);
- }
- break;
- }
- case NodeTypeBinOpExpr:
- collect_expr_decl_deps(g, import, node->data.bin_op_expr.op1, decl_node);
- collect_expr_decl_deps(g, import, node->data.bin_op_expr.op2, decl_node);
- break;
- case NodeTypeUnwrapErrorExpr:
- collect_expr_decl_deps(g, import, node->data.unwrap_err_expr.op1, decl_node);
- collect_expr_decl_deps(g, import, node->data.unwrap_err_expr.op2, decl_node);
- break;
- case NodeTypeReturnExpr:
- collect_expr_decl_deps(g, import, node->data.return_expr.expr, decl_node);
- break;
- case NodeTypeDefer:
- collect_expr_decl_deps(g, import, node->data.defer.expr, decl_node);
- break;
- case NodeTypePrefixOpExpr:
- collect_expr_decl_deps(g, import, node->data.prefix_op_expr.primary_expr, decl_node);
- break;
- case NodeTypeFnCallExpr:
- if (!node->data.fn_call_expr.is_builtin) {
- collect_expr_decl_deps(g, import, node->data.fn_call_expr.fn_ref_expr, decl_node);
- }
- for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
- AstNode *arg_node = node->data.fn_call_expr.params.at(i);
- collect_expr_decl_deps(g, import, arg_node, decl_node);
- }
- break;
- case NodeTypeArrayAccessExpr:
- collect_expr_decl_deps(g, import, node->data.array_access_expr.array_ref_expr, decl_node);
- collect_expr_decl_deps(g, import, node->data.array_access_expr.subscript, decl_node);
- break;
- case NodeTypeSliceExpr:
- collect_expr_decl_deps(g, import, node->data.slice_expr.array_ref_expr, decl_node);
- collect_expr_decl_deps(g, import, node->data.slice_expr.start, decl_node);
- if (node->data.slice_expr.end) {
- collect_expr_decl_deps(g, import, node->data.slice_expr.end, decl_node);
- }
- break;
- case NodeTypeFieldAccessExpr:
- collect_expr_decl_deps(g, import, node->data.field_access_expr.struct_expr, decl_node);
- break;
- case NodeTypeIfBoolExpr:
- collect_expr_decl_deps(g, import, node->data.if_bool_expr.condition, decl_node);
- collect_expr_decl_deps(g, import, node->data.if_bool_expr.then_block, decl_node);
- if (node->data.if_bool_expr.else_node) {
- collect_expr_decl_deps(g, import, node->data.if_bool_expr.else_node, decl_node);
- }
- break;
- case NodeTypeIfVarExpr:
- if (node->data.if_var_expr.var_decl.type) {
- collect_expr_decl_deps(g, import, node->data.if_var_expr.var_decl.type, decl_node);
- }
- if (node->data.if_var_expr.var_decl.expr) {
- collect_expr_decl_deps(g, import, node->data.if_var_expr.var_decl.expr, decl_node);
- }
- collect_expr_decl_deps(g, import, node->data.if_var_expr.then_block, decl_node);
- if (node->data.if_bool_expr.else_node) {
- collect_expr_decl_deps(g, import, node->data.if_var_expr.else_node, decl_node);
- }
- break;
- case NodeTypeWhileExpr:
- collect_expr_decl_deps(g, import, node->data.while_expr.condition, decl_node);
- collect_expr_decl_deps(g, import, node->data.while_expr.body, decl_node);
- break;
- case NodeTypeForExpr:
- collect_expr_decl_deps(g, import, node->data.for_expr.array_expr, decl_node);
- collect_expr_decl_deps(g, import, node->data.for_expr.body, decl_node);
- break;
- case NodeTypeBlock:
- for (int i = 0; i < node->data.block.statements.length; i += 1) {
- AstNode *stmt = node->data.block.statements.at(i);
- collect_expr_decl_deps(g, import, stmt, decl_node);
- }
- break;
- case NodeTypeAsmExpr:
- for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) {
- AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
- if (asm_output->return_type) {
- collect_expr_decl_deps(g, import, asm_output->return_type, decl_node);
- } else {
- decl_node->deps.put(&asm_output->variable_name, node);
- }
- }
- for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
- AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
- collect_expr_decl_deps(g, import, asm_input->expr, decl_node);
- }
- break;
- case NodeTypeContainerInitExpr:
- collect_expr_decl_deps(g, import, node->data.container_init_expr.type, decl_node);
- for (int i = 0; i < node->data.container_init_expr.entries.length; i += 1) {
- AstNode *child_node = node->data.container_init_expr.entries.at(i);
- collect_expr_decl_deps(g, import, child_node, decl_node);
- }
- break;
- case NodeTypeStructValueField:
- collect_expr_decl_deps(g, import, node->data.struct_val_field.expr, decl_node);
- break;
- case NodeTypeArrayType:
- if (node->data.array_type.size) {
- collect_expr_decl_deps(g, import, node->data.array_type.size, decl_node);
- }
- collect_expr_decl_deps(g, import, node->data.array_type.child_type, decl_node);
- break;
- case NodeTypeSwitchExpr:
- collect_expr_decl_deps(g, import, node->data.switch_expr.expr, decl_node);
- for (int i = 0; i < node->data.switch_expr.prongs.length; i += 1) {
- AstNode *prong = node->data.switch_expr.prongs.at(i);
- collect_expr_decl_deps(g, import, prong, decl_node);
- }
- break;
- case NodeTypeSwitchProng:
- for (int i = 0; i < node->data.switch_prong.items.length; i += 1) {
- AstNode *child = node->data.switch_prong.items.at(i);
- collect_expr_decl_deps(g, import, child, decl_node);
- }
- collect_expr_decl_deps(g, import, node->data.switch_prong.expr, decl_node);
- break;
- case NodeTypeSwitchRange:
- collect_expr_decl_deps(g, import, node->data.switch_range.start, decl_node);
- collect_expr_decl_deps(g, import, node->data.switch_range.end, decl_node);
- break;
- case NodeTypeFnProto:
- // remember that fn proto node is used for function definitions as well
- // as types
- for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
- AstNode *param = node->data.fn_proto.params.at(i);
- collect_expr_decl_deps(g, import, param, decl_node);
- }
- if (node->data.fn_proto.directives) {
- for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) {
- AstNode *directive = node->data.fn_proto.directives->at(i);
- collect_expr_decl_deps(g, import, directive, decl_node);
- }
- }
- collect_expr_decl_deps(g, import, node->data.fn_proto.return_type, decl_node);
- break;
- case NodeTypeParamDecl:
- collect_expr_decl_deps(g, import, node->data.param_decl.type, decl_node);
- break;
- case NodeTypeTypeDecl:
- collect_expr_decl_deps(g, import, node->data.type_decl.child_type, decl_node);
- break;
- case NodeTypeDirective:
- collect_expr_decl_deps(g, import, node->data.directive.expr, decl_node);
- break;
- case NodeTypeVariableDeclaration:
- case NodeTypeRootExportDecl:
- case NodeTypeFnDef:
- case NodeTypeRoot:
- case NodeTypeFnDecl:
- case NodeTypeImport:
- case NodeTypeCImport:
- case NodeTypeLabel:
- case NodeTypeStructDecl:
- case NodeTypeStructField:
- zig_unreachable();
+ node->block_context = block_context;
+
+ auto entry = block_context->decl_table.maybe_get(name);
+ if (entry) {
+ AstNode *other_decl_node = entry->value;
+ ErrorMsg *msg = add_node_error(g, node, buf_sprintf("redefinition of '%s'", buf_ptr(name)));
+ add_error_note(g, msg, other_decl_node, buf_sprintf("previous definition is here"));
+ } else {
+ block_context->decl_table.put(name, node);
}
}
-static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *node) {
+static void scan_decls(CodeGen *g, ImportTableEntry *import, BlockContext *context, AstNode *node) {
switch (node->type) {
case NodeTypeRoot:
for (int i = 0; i < import->root->data.root.top_level_decls.length; i += 1) {
AstNode *child = import->root->data.root.top_level_decls.at(i);
- detect_top_level_decl_deps(g, import, child);
+ scan_decls(g, import, context, child);
}
break;
case NodeTypeStructDecl:
{
Buf *name = &node->data.struct_decl.name;
- auto table_entry = g->primitive_type_table.maybe_get(name);
- if (!table_entry) {
- table_entry = import->type_table.maybe_get(name);
- }
- if (table_entry) {
- node->data.struct_decl.type_entry = table_entry->value;
- add_node_error(g, node, buf_sprintf("redefinition of '%s'", buf_ptr(name)));
- } else {
- TypeTableEntry *entry;
- if (node->data.struct_decl.type_entry) {
- entry = node->data.struct_decl.type_entry;
- } else {
- entry = get_partial_container_type(g, import,
- node->data.struct_decl.kind, node, buf_ptr(name));
- }
-
- import->type_table.put(&entry->name, entry);
- node->data.struct_decl.type_entry = entry;
-
- bool is_pub = (node->data.struct_decl.visib_mod != VisibModPrivate);
- if (is_pub) {
- for (int i = 0; i < import->importers.length; i += 1) {
- ImporterInfo importer = import->importers.at(i);
- auto table_entry = importer.import->type_table.maybe_get(&entry->name);
- if (table_entry) {
- add_node_error(g, importer.source_node,
- buf_sprintf("import of type '%s' overrides existing definition",
- buf_ptr(&entry->name)));
- } else {
- importer.import->type_table.put(&entry->name, entry);
- }
- }
- }
- }
-
- // determine which other top level declarations this struct depends on.
- TopLevelDecl *decl_node = &node->data.struct_decl.top_level_decl;
- decl_node->deps.init(1);
- for (int i = 0; i < node->data.struct_decl.fields.length; i += 1) {
- AstNode *field_node = node->data.struct_decl.fields.at(i);
- AstNode *type_node = field_node->data.struct_field.type;
- collect_expr_decl_deps(g, import, type_node, decl_node);
- }
- decl_node->name = name;
- decl_node->import = import;
- if (decl_node->deps.size() > 0) {
- g->unresolved_top_level_decls.put(name, node);
- } else {
- resolve_top_level_decl(g, import, node);
- }
+ TypeTableEntry *container_type = get_partial_container_type(g, import,
+ node->data.struct_decl.kind, node, buf_ptr(name));
+ node->data.struct_decl.type_entry = container_type;
+ add_top_level_decl(g, import, context, node, name);
// handle the member function definitions independently
for (int i = 0; i < node->data.struct_decl.fns.length; i += 1) {
- AstNode *fn_def_node = node->data.struct_decl.fns.at(i);
- AstNode *fn_proto_node = fn_def_node->data.fn_def.fn_proto;
- fn_proto_node->data.fn_proto.struct_node = node;
- detect_top_level_decl_deps(g, import, fn_def_node);
+ AstNode *child_node = node->data.struct_decl.fns.at(i);
+ get_as_top_level_decl(child_node)->parent_decl = node;
+ BlockContext *child_context = get_container_block_context(container_type);
+ scan_decls(g, import, child_context, child_node);
}
break;
}
case NodeTypeFnDef:
node->data.fn_def.fn_proto->data.fn_proto.fn_def_node = node;
- detect_top_level_decl_deps(g, import, node->data.fn_def.fn_proto);
+ scan_decls(g, import, context, node->data.fn_def.fn_proto);
break;
case NodeTypeVariableDeclaration:
{
- // determine which other top level declarations this variable declaration depends on.
- TopLevelDecl *decl_node = &node->data.variable_declaration.top_level_decl;
- decl_node->deps.init(1);
- if (node->data.variable_declaration.type) {
- collect_expr_decl_deps(g, import, node->data.variable_declaration.type, decl_node);
- }
- if (node->data.variable_declaration.expr) {
- collect_expr_decl_deps(g, import, node->data.variable_declaration.expr, decl_node);
- }
Buf *name = &node->data.variable_declaration.symbol;
- decl_node->name = name;
- decl_node->import = import;
- if (decl_node->deps.size() > 0) {
- g->unresolved_top_level_decls.put(name, node);
- } else {
- resolve_top_level_decl(g, import, node);
- }
+ add_top_level_decl(g, import, context, node, name);
break;
}
case NodeTypeTypeDecl:
{
- // determine which other top level declarations this variable declaration depends on.
- TopLevelDecl *decl_node = &node->data.type_decl.top_level_decl;
- decl_node->deps.init(1);
- collect_expr_decl_deps(g, import, node, decl_node);
-
Buf *name = &node->data.type_decl.symbol;
- decl_node->name = name;
- decl_node->import = import;
- if (decl_node->deps.size() > 0) {
- g->unresolved_top_level_decls.put(name, node);
- } else {
- resolve_top_level_decl(g, import, node);
- }
+ add_top_level_decl(g, import, context, node, name);
break;
}
case NodeTypeFnProto:
@@ -5695,60 +5482,22 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
add_node_error(g, node, buf_sprintf("missing function name"));
break;
}
- Buf *qualified_name;
- AstNode *struct_node = node->data.fn_proto.struct_node;
- if (struct_node) {
- Buf *struct_name = &struct_node->data.struct_decl.name;
- qualified_name = buf_sprintf("%s.%s", buf_ptr(struct_name), buf_ptr(fn_name));
- } else {
- qualified_name = fn_name;
- }
-
-
- // determine which other top level declarations this function prototype depends on.
- TopLevelDecl *decl_node = &node->data.fn_proto.top_level_decl;
- decl_node->deps.init(1);
- collect_expr_decl_deps(g, import, node, decl_node);
-
- decl_node->name = qualified_name;
- decl_node->import = import;
- if (decl_node->deps.size() > 0) {
- if (g->unresolved_top_level_decls.maybe_get(qualified_name)) {
- node->data.fn_proto.skip = true;
- add_node_error(g, node, buf_sprintf("redefinition of '%s'", buf_ptr(fn_name)));
- } else {
- g->unresolved_top_level_decls.put(qualified_name, node);
- }
- } else {
- resolve_top_level_decl(g, import, node);
- }
+ add_top_level_decl(g, import, context, node, fn_name);
break;
}
- case NodeTypeRootExportDecl:
- resolve_top_level_decl(g, import, node);
- break;
- case NodeTypeImport:
- // already taken care of
- break;
- case NodeTypeCImport:
+ case NodeTypeUse:
{
- TopLevelDecl *decl_node = &node->data.c_import.top_level_decl;
- decl_node->deps.init(1);
- collect_expr_decl_deps(g, import, node->data.c_import.block, decl_node);
-
- decl_node->name = buf_sprintf("c_import_%" PRIu32, node->create_index);
- decl_node->import = import;
- if (decl_node->deps.size() > 0) {
- g->unresolved_top_level_decls.put(decl_node->name, node);
- } else {
- resolve_top_level_decl(g, import, node);
- }
+ TopLevelDecl *tld = get_as_top_level_decl(node);
+ tld->import = import;
+ node->block_context = context;
+ g->use_queue.append(node);
+ tld->import->use_decls.append(node);
break;
}
case NodeTypeErrorValueDecl:
// error value declarations do not depend on other top level decls
- resolve_top_level_decl(g, import, node);
+ preview_error_value_decl(g, node);
break;
case NodeTypeDirective:
case NodeTypeParamDecl:
@@ -5792,152 +5541,176 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
}
}
-static void recursive_resolve_decl(CodeGen *g, ImportTableEntry *import, AstNode *node) {
- auto it = get_resolved_top_level_decl(node)->deps.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
+static void add_symbols_from_import(CodeGen *g, AstNode *src_use_node, AstNode *dst_use_node) {
+ TopLevelDecl *tld = get_as_top_level_decl(dst_use_node);
+ AstNode *use_target_node = src_use_node->data.use.expr;
+ Expr *expr = get_resolved_expr(use_target_node);
- auto unresolved_entry = g->unresolved_top_level_decls.maybe_get(entry->key);
- if (!unresolved_entry) {
- continue;
- }
+ if (expr->type_entry->id == TypeTableEntryIdInvalid) {
+ return;
+ }
+
+ ConstExprValue *const_val = &expr->const_val;
+ assert(const_val->ok);
+
+ ImportTableEntry *target_import = const_val->data.x_import;
+ assert(target_import);
- AstNode *child_node = unresolved_entry->value;
+ if (target_import->any_imports_failed) {
+ tld->import->any_imports_failed = true;
+ }
- if (get_resolved_top_level_decl(child_node)->in_current_deps) {
- // dependency loop. we'll let the fact that it's not in the respective
- // table cause an error in resolve_top_level_decl.
+ for (int i = 0; i < target_import->root->data.root.top_level_decls.length; i += 1) {
+ AstNode *decl_node = target_import->root->data.root.top_level_decls.at(i);
+ if (decl_node->type == NodeTypeFnDef) {
+ decl_node = decl_node->data.fn_def.fn_proto;
+ }
+ TopLevelDecl *target_tld = get_as_top_level_decl(decl_node);
+ if (!target_tld->name) {
continue;
}
+ if (target_tld->visib_mod != VisibModPrivate) {
+ auto existing_entry = tld->import->block_context->decl_table.maybe_get(target_tld->name);
+ if (existing_entry) {
+ AstNode *existing_decl = existing_entry->value;
+ if (existing_decl != decl_node) {
+ ErrorMsg *msg = add_node_error(g, dst_use_node,
+ buf_sprintf("import of '%s' overrides existing definition",
+ buf_ptr(target_tld->name)));
+ add_error_note(g, msg, existing_decl, buf_sprintf("previous definition here"));
+ add_error_note(g, msg, decl_node, buf_sprintf("imported definition here"));
+ }
+ } else {
+ tld->import->block_context->decl_table.put(target_tld->name, decl_node);
+ }
+ }
+ }
- // set temporary flag
- TopLevelDecl *top_level_decl = get_resolved_top_level_decl(child_node);
- top_level_decl->in_current_deps = true;
+ for (int i = 0; i < target_import->use_decls.length; i += 1) {
+ AstNode *use_decl_node = target_import->use_decls.at(i);
+ TopLevelDecl *target_tld = get_as_top_level_decl(use_decl_node);
+ if (target_tld->visib_mod != VisibModPrivate) {
+ add_symbols_from_import(g, use_decl_node, dst_use_node);
+ }
+ }
- recursive_resolve_decl(g, top_level_decl->import, child_node);
+}
- // unset temporary flag
- top_level_decl->in_current_deps = false;
- }
+static void resolve_use_decl(CodeGen *g, AstNode *node) {
+ assert(node->type == NodeTypeUse);
+ add_symbols_from_import(g, node, node);
+}
- resolve_top_level_decl(g, import, node);
+static void preview_use_decl(CodeGen *g, AstNode *node) {
+ assert(node->type == NodeTypeUse);
+ TopLevelDecl *tld = get_as_top_level_decl(node);
+ TypeTableEntry *use_expr_type = analyze_expression(g, tld->import, tld->import->block_context,
+ g->builtin_types.entry_namespace, node->data.use.expr);
+ if (use_expr_type->id == TypeTableEntryIdInvalid) {
+ tld->import->any_imports_failed = true;
+ }
}
-static void resolve_top_level_declarations_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
- assert(node->type == NodeTypeRoot);
+ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package,
+ Buf *abs_full_path, Buf *src_dirname, Buf *src_basename, Buf *source_code)
+{
+ Buf *full_path = buf_alloc();
+ os_path_join(src_dirname, src_basename, full_path);
- while (g->unresolved_top_level_decls.size() > 0) {
- // for the sake of determinism, find the element with the lowest
- // insert index and resolve that one.
- AstNode *decl_node = nullptr;
- auto it = g->unresolved_top_level_decls.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
+ if (g->verbose) {
+ fprintf(stderr, "\nOriginal Source (%s):\n", buf_ptr(full_path));
+ fprintf(stderr, "----------------\n");
+ fprintf(stderr, "%s\n", buf_ptr(source_code));
- AstNode *this_node = entry->value;
- if (!decl_node || this_node->create_index < decl_node->create_index) {
- decl_node = this_node;
- }
+ fprintf(stderr, "\nTokens:\n");
+ fprintf(stderr, "---------\n");
+ }
- }
- // set temporary flag
- TopLevelDecl *top_level_decl = get_resolved_top_level_decl(decl_node);
- top_level_decl->in_current_deps = true;
+ Tokenization tokenization = {0};
+ tokenize(source_code, &tokenization);
- recursive_resolve_decl(g, top_level_decl->import, decl_node);
+ 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);
- // unset temporary flag
- top_level_decl->in_current_deps = false;
+ print_err_msg(err, g->err_color);
+ exit(1);
}
-}
-static void analyze_top_level_decls_root(CodeGen *g, ImportTableEntry *import, AstNode *node) {
- assert(node->type == NodeTypeRoot);
+ if (g->verbose) {
+ print_tokens(source_code, tokenization.tokens);
- for (int i = 0; i < node->data.root.top_level_decls.length; i += 1) {
- AstNode *child = node->data.root.top_level_decls.at(i);
- analyze_top_level_decl(g, import, child);
+ fprintf(stderr, "\nAST:\n");
+ fprintf(stderr, "------\n");
}
-}
-void semantic_analyze(CodeGen *g) {
- {
- auto it = g->import_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
+ ImportTableEntry *import_entry = allocate<ImportTableEntry>(1);
+ import_entry->package = package;
+ import_entry->source_code = source_code;
+ import_entry->line_offsets = tokenization.line_offsets;
+ import_entry->path = full_path;
- ImportTableEntry *import = entry->value;
+ 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);
+ }
- for (int i = 0; i < import->root->data.root.top_level_decls.length; i += 1) {
- AstNode *child = import->root->data.root.top_level_decls.at(i);
- if (child->type == NodeTypeImport) {
- if (child->data.import.directives) {
- for (int i = 0; i < child->data.import.directives->length; i += 1) {
- AstNode *directive_node = child->data.import.directives->at(i);
- Buf *name = &directive_node->data.directive.name;
- add_node_error(g, directive_node,
- buf_sprintf("invalid directive: '%s'", buf_ptr(name)));
- }
- }
+ import_entry->di_file = LLVMZigCreateFile(g->dbuilder, buf_ptr(src_basename), buf_ptr(src_dirname));
+ g->import_table.put(abs_full_path, import_entry);
+ g->import_queue.append(import_entry);
- ImportTableEntry *target_import = child->data.import.import;
- assert(target_import);
+ import_entry->block_context = new_block_context(import_entry->root, nullptr);
+ import_entry->block_context->di_scope = LLVMZigFileToScope(import_entry->di_file);
- target_import->importers.append({import, child});
- } else if (child->type == NodeTypeErrorValueDecl) {
- preview_error_value_decl(g, child);
- }
+
+ 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 == 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.top_level_decl.visib_mod == VisibModPrivate);
+
+ if (buf_eql_str(proto_name, "main") && !is_private) {
+ g->have_exported_main = true;
}
}
}
- {
- g->err_tag_type = get_smallest_unsigned_int_type(g, g->error_value_count);
-
- g->builtin_types.entry_pure_error->type_ref = g->err_tag_type->type_ref;
- g->builtin_types.entry_pure_error->di_type = g->err_tag_type->di_type;
- }
+ return import_entry;
+}
- {
- auto it = g->import_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
- ImportTableEntry *import = entry->value;
+void semantic_analyze(CodeGen *g) {
+ for (; g->import_queue_index < g->import_queue.length; g->import_queue_index += 1) {
+ ImportTableEntry *import = g->import_queue.at(g->import_queue_index);
+ scan_decls(g, import, import->block_context, import->root);
+ }
- detect_top_level_decl_deps(g, import, import->root);
- }
+ for (; g->use_queue_index < g->use_queue.length; g->use_queue_index += 1) {
+ AstNode *use_decl_node = g->use_queue.at(g->use_queue_index);
+ preview_use_decl(g, use_decl_node);
}
- {
- auto it = g->import_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
+ for (int i = 0; i < g->use_queue.length; i += 1) {
+ AstNode *use_decl_node = g->use_queue.at(i);
+ resolve_use_decl(g, use_decl_node);
+ }
- ImportTableEntry *import = entry->value;
- resolve_top_level_declarations_root(g, import, import->root);
- }
+ for (; g->export_queue_index < g->export_queue.length; g->export_queue_index += 1) {
+ AstNode *decl_node = g->export_queue.at(g->export_queue_index);
+ bool pointer_only = false;
+ resolve_top_level_decl(g, decl_node, pointer_only);
}
- {
- auto it = g->import_table.entry_iterator();
- for (;;) {
- auto *entry = it.next();
- if (!entry)
- break;
- ImportTableEntry *import = entry->value;
- analyze_top_level_decls_root(g, import, import->root);
- }
+ for (int i = 0; i < g->fn_defs.length; i += 1) {
+ FnTableEntry *fn_entry = g->fn_defs.at(i);
+ analyze_fn_body(g, fn_entry);
}
}
@@ -6012,13 +5785,11 @@ Expr *get_resolved_expr(AstNode *node) {
case NodeTypeSwitchProng:
case NodeTypeSwitchRange:
case NodeTypeRoot:
- case NodeTypeRootExportDecl:
case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeDirective:
- case NodeTypeImport:
- case NodeTypeCImport:
+ case NodeTypeUse:
case NodeTypeStructDecl:
case NodeTypeStructField:
case NodeTypeStructValueField:
@@ -6029,18 +5800,20 @@ Expr *get_resolved_expr(AstNode *node) {
zig_unreachable();
}
-TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
+static TopLevelDecl *get_as_top_level_decl(AstNode *node) {
switch (node->type) {
case NodeTypeVariableDeclaration:
return &node->data.variable_declaration.top_level_decl;
case NodeTypeFnProto:
return &node->data.fn_proto.top_level_decl;
+ case NodeTypeFnDef:
+ return &node->data.fn_def.fn_proto->data.fn_proto.top_level_decl;
case NodeTypeStructDecl:
return &node->data.struct_decl.top_level_decl;
case NodeTypeErrorValueDecl:
return &node->data.error_value_decl.top_level_decl;
- case NodeTypeCImport:
- return &node->data.c_import.top_level_decl;
+ case NodeTypeUse:
+ return &node->data.use.top_level_decl;
case NodeTypeTypeDecl:
return &node->data.type_decl.top_level_decl;
case NodeTypeNumberLiteral:
@@ -6063,8 +5836,6 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
case NodeTypeAsmExpr:
case NodeTypeContainerInitExpr:
case NodeTypeRoot:
- case NodeTypeRootExportDecl:
- case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
case NodeTypeBlock:
@@ -6072,7 +5843,6 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
case NodeTypeSymbol:
- case NodeTypeImport:
case NodeTypeBoolLiteral:
case NodeTypeNullLiteral:
case NodeTypeUndefinedLiteral:
@@ -6140,6 +5910,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdUndefLit:
+ case TypeTableEntryIdNamespace:
zig_unreachable();
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdVoid:
@@ -6257,6 +6028,7 @@ static TypeTableEntry *type_of_first_thing_in_memory(TypeTableEntry *type_entry)
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdVoid:
+ case TypeTableEntryIdNamespace:
zig_unreachable();
case TypeTableEntryIdArray:
return type_of_first_thing_in_memory(type_entry->data.array.child_type);
src/analyze.hpp
@@ -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
src/ast_render.cpp
@@ -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;
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;
src/codegen.hpp
@@ -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);
src/errmsg.cpp
@@ -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);
}
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);
src/parseh.cpp
@@ -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) {
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);
src/tokenizer.cpp
@@ -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";
src/tokenizer.hpp
@@ -19,9 +19,8 @@ enum TokenId {
TokenIdKeywordConst,
TokenIdKeywordExtern,
TokenIdKeywordPub,
+ TokenIdKeywordUse,
TokenIdKeywordExport,
- TokenIdKeywordImport,
- TokenIdKeywordCImport,
TokenIdKeywordTrue,
TokenIdKeywordFalse,
TokenIdKeywordIf,
std/bootstrap.zig
@@ -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;
}
std/index.zig
@@ -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");
std/std.zig โ std/io.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;
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,
}
}
},
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;
std/test_runner.zig
@@ -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();
}
}
std/test_runner_libc.zig
@@ -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;
}
std/test_runner_nolibc.zig
@@ -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();
}
test/run_tests.cpp
@@ -70,12 +70,20 @@ static TestCase *add_simple_case(const char *case_name, const char *source, cons
test_case->compiler_args.append("--strip");
test_case->compiler_args.append("--color");
test_case->compiler_args.append("on");
+ test_case->compiler_args.append("--check-unused");
test_cases.append(test_case);
return test_case;
}
+static TestCase *add_simple_case_libc(const char *case_name, const char *source, const char *output) {
+ TestCase *tc = add_simple_case(case_name, source, output);
+ tc->compiler_args.append("--library");
+ tc->compiler_args.append("c");
+ return tc;
+}
+
static TestCase *add_compile_fail_case(const char *case_name, const char *source, int count, ...) {
va_list ap;
va_start(ap, count);
@@ -93,11 +101,19 @@ static TestCase *add_compile_fail_case(const char *case_name, const char *source
test_case->compiler_args.append("build");
test_case->compiler_args.append(tmp_source_path);
+
+ test_case->compiler_args.append("--name");
+ test_case->compiler_args.append("test");
+
+ test_case->compiler_args.append("--export");
+ test_case->compiler_args.append("obj");
+
test_case->compiler_args.append("--output");
test_case->compiler_args.append(tmp_exe_path);
+
test_case->compiler_args.append("--release");
test_case->compiler_args.append("--strip");
- //test_case->compiler_args.append("--verbose");
+ test_case->compiler_args.append("--check-unused");
test_cases.append(test_case);
@@ -134,43 +150,18 @@ static TestCase *add_parseh_case(const char *case_name, const char *source, int
}
static void add_compiling_test_cases(void) {
- add_simple_case("hello world with libc", R"SOURCE(
-#link("c")
-export executable "test";
-
-c_import {
- @c_include("stdio.h");
-}
-
+ add_simple_case_libc("hello world with libc", R"SOURCE(
+const c = @c_import(@c_include("stdio.h"));
export fn main(argc: c_int, argv: &&u8) -> c_int {
- puts(c"Hello, world!");
+ c.puts(c"Hello, world!");
return 0;
}
)SOURCE", "Hello, world!" NL);
- add_simple_case("function call", R"SOURCE(
-import "std.zig";
-import "syscall.zig";
-
-fn empty_function_1() {}
-fn empty_function_2() { return; }
-
-pub fn main(args: [][]u8) -> %void {
- empty_function_1();
- empty_function_2();
- this_is_a_function();
-}
-
-fn this_is_a_function() -> unreachable {
- %%stdout.printf("OK\n");
- exit(0);
-}
- )SOURCE", "OK\n");
-
{
TestCase *tc = add_simple_case("multiple files with private function", R"SOURCE(
-import "std.zig";
-import "foo.zig";
+use @import("std").io;
+use @import("foo.zig");
pub fn main(args: [][]u8) -> %void {
private_function();
@@ -183,7 +174,7 @@ fn private_function() {
)SOURCE", "OK 1\nOK 2\n");
add_source_file(tc, "foo.zig", R"SOURCE(
-import "std.zig";
+use @import("std").io;
// purposefully conflicting function with main.zig
// but it's private so it should be OK
@@ -199,8 +190,8 @@ pub fn print_text() {
{
TestCase *tc = add_simple_case("import segregation", R"SOURCE(
-import "foo.zig";
-import "bar.zig";
+use @import("foo.zig");
+use @import("bar.zig");
pub fn main(args: [][]u8) -> %void {
foo_function();
@@ -209,15 +200,15 @@ pub fn main(args: [][]u8) -> %void {
)SOURCE", "OK\nOK\n");
add_source_file(tc, "foo.zig", R"SOURCE(
-import "std.zig";
+use @import("std").io;
pub fn foo_function() {
%%stdout.printf("OK\n");
}
)SOURCE");
add_source_file(tc, "bar.zig", R"SOURCE(
-import "other.zig";
-import "std.zig";
+use @import("other.zig");
+use @import("std").io;
pub fn bar_function() {
if (foo_function()) {
@@ -234,8 +225,35 @@ pub fn foo_function() -> bool {
)SOURCE");
}
+ {
+ TestCase *tc = add_simple_case("two files use import each other", R"SOURCE(
+use @import("a.zig");
+
+pub fn main(args: [][]u8) -> %void {
+ ok();
+}
+ )SOURCE", "OK\n");
+
+ add_source_file(tc, "a.zig", R"SOURCE(
+use @import("b.zig");
+const io = @import("std").io;
+
+pub const a_text = "OK\n";
+
+pub fn ok() {
+ %%io.stdout.printf(b_text);
+}
+ )SOURCE");
+
+ add_source_file(tc, "b.zig", R"SOURCE(
+use @import("a.zig");
+
+pub const b_text = a_text;
+ )SOURCE");
+ }
+
add_simple_case("params", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
fn add(a: i32, b: i32) -> i32 {
a + b
@@ -243,13 +261,13 @@ fn add(a: i32, b: i32) -> i32 {
pub fn main(args: [][]u8) -> %void {
if (add(22, 11) == 33) {
- %%stdout.printf("pass\n");
+ %%io.stdout.printf("pass\n");
}
}
)SOURCE", "pass\n");
add_simple_case("void parameters", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
void_fun(1, void{}, 2);
@@ -258,28 +276,28 @@ pub fn main(args: [][]u8) -> %void {
fn void_fun(a : i32, b : void, c : i32) {
const v = b;
const vv : void = if (a == 1) {v} else {};
- if (a + c == 3) { %%stdout.printf("OK\n"); }
+ if (a + c == 3) { %%io.stdout.printf("OK\n"); }
return vv;
}
)SOURCE", "OK\n");
add_simple_case("mutable local variables", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
var zero : i32 = 0;
- if (zero == 0) { %%stdout.printf("zero\n"); }
+ if (zero == 0) { %%io.stdout.printf("zero\n"); }
var i = i32(0);
while (i != 3) {
- %%stdout.printf("loop\n");
+ %%io.stdout.printf("loop\n");
i += 1;
}
}
)SOURCE", "zero\nloop\nloop\nloop\n");
add_simple_case("arrays", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
var array : [5]i32 = undefined;
@@ -299,11 +317,11 @@ pub fn main(args: [][]u8) -> %void {
}
if (accumulator == 15) {
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
if (get_array_len(array) != 5) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
}
fn get_array_len(a: []i32) -> isize {
@@ -313,144 +331,139 @@ fn get_array_len(a: []i32) -> isize {
add_simple_case("hello world without libc", R"SOURCE(
-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");
}
)SOURCE", "Hello, world!\n");
add_simple_case("short circuit", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
- if (true || { %%stdout.printf("BAD 1\n"); false }) {
- %%stdout.printf("OK 1\n");
+ if (true || { %%io.stdout.printf("BAD 1\n"); false }) {
+ %%io.stdout.printf("OK 1\n");
}
- if (false || { %%stdout.printf("OK 2\n"); false }) {
- %%stdout.printf("BAD 2\n");
+ if (false || { %%io.stdout.printf("OK 2\n"); false }) {
+ %%io.stdout.printf("BAD 2\n");
}
- if (true && { %%stdout.printf("OK 3\n"); false }) {
- %%stdout.printf("BAD 3\n");
+ if (true && { %%io.stdout.printf("OK 3\n"); false }) {
+ %%io.stdout.printf("BAD 3\n");
}
- if (false && { %%stdout.printf("BAD 4\n"); false }) {
+ if (false && { %%io.stdout.printf("BAD 4\n"); false }) {
} else {
- %%stdout.printf("OK 4\n");
+ %%io.stdout.printf("OK 4\n");
}
}
)SOURCE", "OK 1\nOK 2\nOK 3\nOK 4\n");
add_simple_case("modify operators", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
var i : i32 = 0;
- i += 5; if (i != 5) { %%stdout.printf("BAD +=\n"); }
- i -= 2; if (i != 3) { %%stdout.printf("BAD -=\n"); }
- i *= 20; if (i != 60) { %%stdout.printf("BAD *=\n"); }
- i /= 3; if (i != 20) { %%stdout.printf("BAD /=\n"); }
- i %= 11; if (i != 9) { %%stdout.printf("BAD %=\n"); }
- i <<= 1; if (i != 18) { %%stdout.printf("BAD <<=\n"); }
- i >>= 2; if (i != 4) { %%stdout.printf("BAD >>=\n"); }
+ i += 5; if (i != 5) { %%io.stdout.printf("BAD +=\n"); }
+ i -= 2; if (i != 3) { %%io.stdout.printf("BAD -=\n"); }
+ i *= 20; if (i != 60) { %%io.stdout.printf("BAD *=\n"); }
+ i /= 3; if (i != 20) { %%io.stdout.printf("BAD /=\n"); }
+ i %= 11; if (i != 9) { %%io.stdout.printf("BAD %=\n"); }
+ i <<= 1; if (i != 18) { %%io.stdout.printf("BAD <<=\n"); }
+ i >>= 2; if (i != 4) { %%io.stdout.printf("BAD >>=\n"); }
i = 6;
- i &= 5; if (i != 4) { %%stdout.printf("BAD &=\n"); }
- i ^= 6; if (i != 2) { %%stdout.printf("BAD ^=\n"); }
+ i &= 5; if (i != 4) { %%io.stdout.printf("BAD &=\n"); }
+ i ^= 6; if (i != 2) { %%io.stdout.printf("BAD ^=\n"); }
i = 6;
- i |= 3; if (i != 7) { %%stdout.printf("BAD |=\n"); }
+ i |= 3; if (i != 7) { %%io.stdout.printf("BAD |=\n"); }
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
- add_simple_case("number literals", R"SOURCE(
-#link("c")
-export executable "test";
-
-c_import {
- @c_include("stdio.h");
-}
+ add_simple_case_libc("number literals", R"SOURCE(
+const c = @c_import(@c_include("stdio.h"));
export fn main(argc: c_int, argv: &&u8) -> c_int {
- printf(c"\n");
+ c.printf(c"\n");
- printf(c"0: %llu\n",
+ c.printf(c"0: %llu\n",
u64(0));
- printf(c"320402575052271: %llu\n",
+ c.printf(c"320402575052271: %llu\n",
u64(320402575052271));
- printf(c"0x01236789abcdef: %llu\n",
+ c.printf(c"0x01236789abcdef: %llu\n",
u64(0x01236789abcdef));
- printf(c"0xffffffffffffffff: %llu\n",
+ c.printf(c"0xffffffffffffffff: %llu\n",
u64(0xffffffffffffffff));
- printf(c"0x000000ffffffffffffffff: %llu\n",
+ c.printf(c"0x000000ffffffffffffffff: %llu\n",
u64(0x000000ffffffffffffffff));
- printf(c"0o1777777777777777777777: %llu\n",
+ c.printf(c"0o1777777777777777777777: %llu\n",
u64(0o1777777777777777777777));
- printf(c"0o0000001777777777777777777777: %llu\n",
+ c.printf(c"0o0000001777777777777777777777: %llu\n",
u64(0o0000001777777777777777777777));
- printf(c"0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n",
+ c.printf(c"0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n",
u64(0b1111111111111111111111111111111111111111111111111111111111111111));
- printf(c"0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n",
+ c.printf(c"0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n",
u64(0b0000001111111111111111111111111111111111111111111111111111111111111111));
- printf(c"\n");
+ c.printf(c"\n");
- printf(c"0.0: %a\n",
+ c.printf(c"0.0: %a\n",
f64(0.0));
- printf(c"0e0: %a\n",
+ c.printf(c"0e0: %a\n",
f64(0e0));
- printf(c"0.0e0: %a\n",
+ c.printf(c"0.0e0: %a\n",
f64(0.0e0));
- printf(c"000000000000000000000000000000000000000000000000000000000.0e0: %a\n",
+ c.printf(c"000000000000000000000000000000000000000000000000000000000.0e0: %a\n",
f64(000000000000000000000000000000000000000000000000000000000.0e0));
- printf(c"0.000000000000000000000000000000000000000000000000000000000e0: %a\n",
+ c.printf(c"0.000000000000000000000000000000000000000000000000000000000e0: %a\n",
f64(0.000000000000000000000000000000000000000000000000000000000e0));
- printf(c"0.0e000000000000000000000000000000000000000000000000000000000: %a\n",
+ c.printf(c"0.0e000000000000000000000000000000000000000000000000000000000: %a\n",
f64(0.0e000000000000000000000000000000000000000000000000000000000));
- printf(c"1.0: %a\n",
+ c.printf(c"1.0: %a\n",
f64(1.0));
- printf(c"10.0: %a\n",
+ c.printf(c"10.0: %a\n",
f64(10.0));
- printf(c"10.5: %a\n",
+ c.printf(c"10.5: %a\n",
f64(10.5));
- printf(c"10.5e5: %a\n",
+ c.printf(c"10.5e5: %a\n",
f64(10.5e5));
- printf(c"10.5e+5: %a\n",
+ c.printf(c"10.5e+5: %a\n",
f64(10.5e+5));
- printf(c"50.0e-2: %a\n",
+ c.printf(c"50.0e-2: %a\n",
f64(50.0e-2));
- printf(c"50e-2: %a\n",
+ c.printf(c"50e-2: %a\n",
f64(50e-2));
- printf(c"\n");
+ c.printf(c"\n");
- printf(c"0x1.0: %a\n",
+ c.printf(c"0x1.0: %a\n",
f64(0x1.0));
- printf(c"0x10.0: %a\n",
+ c.printf(c"0x10.0: %a\n",
f64(0x10.0));
- printf(c"0x100.0: %a\n",
+ c.printf(c"0x100.0: %a\n",
f64(0x100.0));
- printf(c"0x103.0: %a\n",
+ c.printf(c"0x103.0: %a\n",
f64(0x103.0));
- printf(c"0x103.7: %a\n",
+ c.printf(c"0x103.7: %a\n",
f64(0x103.7));
- printf(c"0x103.70: %a\n",
+ c.printf(c"0x103.70: %a\n",
f64(0x103.70));
- printf(c"0x103.70p4: %a\n",
+ c.printf(c"0x103.70p4: %a\n",
f64(0x103.70p4));
- printf(c"0x103.70p5: %a\n",
+ c.printf(c"0x103.70p5: %a\n",
f64(0x103.70p5));
- printf(c"0x103.70p+5: %a\n",
+ c.printf(c"0x103.70p+5: %a\n",
f64(0x103.70p+5));
- printf(c"0x103.70p-5: %a\n",
+ c.printf(c"0x103.70p-5: %a\n",
f64(0x103.70p-5));
- printf(c"\n");
+ c.printf(c"\n");
- printf(c"0b10100.00010e0: %a\n",
+ c.printf(c"0b10100.00010e0: %a\n",
f64(0b10100.00010e0));
- printf(c"0o10700.00010e0: %a\n",
+ c.printf(c"0o10700.00010e0: %a\n",
f64(0o10700.00010e0));
return 0;
@@ -496,7 +509,7 @@ export fn main(argc: c_int, argv: &&u8) -> c_int {
)OUTPUT");
add_simple_case("structs", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
var foo : Foo = undefined;
@@ -506,12 +519,12 @@ pub fn main(args: [][]u8) -> %void {
test_foo(foo);
test_mutation(&foo);
if (foo.c != 100) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
test_point_to_self();
test_byval_assign();
test_initializer();
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
struct Foo {
a : i32,
@@ -520,7 +533,7 @@ struct Foo {
}
fn test_foo(foo : Foo) {
if (!foo.b) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
}
fn test_mutation(foo : &Foo) {
@@ -545,7 +558,7 @@ fn test_point_to_self() {
root.next = &node;
if (node.next.next.next.val.x != 1) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
}
fn test_byval_assign() {
@@ -554,38 +567,38 @@ fn test_byval_assign() {
foo1.a = 1234;
- if (foo2.a != 0) { %%stdout.printf("BAD\n"); }
+ if (foo2.a != 0) { %%io.stdout.printf("BAD\n"); }
foo2 = foo1;
- if (foo2.a != 1234) { %%stdout.printf("BAD - byval assignment failed\n"); }
+ if (foo2.a != 1234) { %%io.stdout.printf("BAD - byval assignment failed\n"); }
}
fn test_initializer() {
const val = Val { .x = 42 };
- if (val.x != 42) { %%stdout.printf("BAD\n"); }
+ if (val.x != 42) { %%io.stdout.printf("BAD\n"); }
}
)SOURCE", "OK\n");
add_simple_case("global variables", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
const g1 : i32 = 1233 + 1;
var g2 : i32 = 0;
pub fn main(args: [][]u8) -> %void {
- if (g2 != 0) { %%stdout.printf("BAD\n"); }
+ if (g2 != 0) { %%io.stdout.printf("BAD\n"); }
g2 = g1;
- if (g2 != 1234) { %%stdout.printf("BAD\n"); }
- %%stdout.printf("OK\n");
+ if (g2 != 1234) { %%io.stdout.printf("BAD\n"); }
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("while loop", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
var i : i32 = 0;
while (i < 4) {
- %%stdout.printf("loop\n");
+ %%io.stdout.printf("loop\n");
i += 1;
}
g();
@@ -601,11 +614,11 @@ fn f() -> i32 {
)SOURCE", "loop\nloop\nloop\nloop\n");
add_simple_case("continue and break", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
var i : i32 = 0;
while (true) {
- %%stdout.printf("loop\n");
+ %%io.stdout.printf("loop\n");
i += 1;
if (i < 4) {
continue;
@@ -616,11 +629,11 @@ pub fn main(args: [][]u8) -> %void {
)SOURCE", "loop\nloop\nloop\nloop\n");
add_simple_case("implicit cast after unreachable", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
const x = outer();
if (x == 1234) {
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
}
fn inner() -> i32 { 1234 }
@@ -630,18 +643,18 @@ fn outer() -> isize {
)SOURCE", "OK\n");
add_simple_case("@sizeof() and @typeof()", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
const x: u16 = 13;
const z: @typeof(x) = 19;
pub fn main(args: [][]u8) -> %void {
const y: @typeof(x) = 120;
- %%stdout.print_u64(@sizeof(@typeof(y)));
- %%stdout.printf("\n");
+ %%io.stdout.print_u64(@sizeof(@typeof(y)));
+ %%io.stdout.printf("\n");
}
)SOURCE", "2\n");
add_simple_case("member functions", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
struct Rand {
seed: u32,
pub fn get_seed(r: Rand) -> u32 {
@@ -651,14 +664,14 @@ struct Rand {
pub fn main(args: [][]u8) -> %void {
const r = Rand {.seed = 1234};
if (r.get_seed() != 1234) {
- %%stdout.printf("BAD seed\n");
+ %%io.stdout.printf("BAD seed\n");
}
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("pointer dereferencing", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
var x = i32(3);
@@ -667,93 +680,93 @@ pub fn main(args: [][]u8) -> %void {
*y += 1;
if (x != 4) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
if (*y != 4) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("constant expressions", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
const ARRAY_SIZE : i8 = 20;
pub fn main(args: [][]u8) -> %void {
var array : [ARRAY_SIZE]u8 = undefined;
- %%stdout.print_u64(@sizeof(@typeof(array)));
- %%stdout.printf("\n");
+ %%io.stdout.print_u64(@sizeof(@typeof(array)));
+ %%io.stdout.printf("\n");
}
)SOURCE", "20\n");
add_simple_case("@min_value() and @max_value()", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
- %%stdout.printf("max u8: ");
- %%stdout.print_u64(@max_value(u8));
- %%stdout.printf("\n");
+ %%io.stdout.printf("max u8: ");
+ %%io.stdout.print_u64(@max_value(u8));
+ %%io.stdout.printf("\n");
- %%stdout.printf("max u16: ");
- %%stdout.print_u64(@max_value(u16));
- %%stdout.printf("\n");
+ %%io.stdout.printf("max u16: ");
+ %%io.stdout.print_u64(@max_value(u16));
+ %%io.stdout.printf("\n");
- %%stdout.printf("max u32: ");
- %%stdout.print_u64(@max_value(u32));
- %%stdout.printf("\n");
+ %%io.stdout.printf("max u32: ");
+ %%io.stdout.print_u64(@max_value(u32));
+ %%io.stdout.printf("\n");
- %%stdout.printf("max u64: ");
- %%stdout.print_u64(@max_value(u64));
- %%stdout.printf("\n");
+ %%io.stdout.printf("max u64: ");
+ %%io.stdout.print_u64(@max_value(u64));
+ %%io.stdout.printf("\n");
- %%stdout.printf("max i8: ");
- %%stdout.print_i64(@max_value(i8));
- %%stdout.printf("\n");
+ %%io.stdout.printf("max i8: ");
+ %%io.stdout.print_i64(@max_value(i8));
+ %%io.stdout.printf("\n");
- %%stdout.printf("max i16: ");
- %%stdout.print_i64(@max_value(i16));
- %%stdout.printf("\n");
+ %%io.stdout.printf("max i16: ");
+ %%io.stdout.print_i64(@max_value(i16));
+ %%io.stdout.printf("\n");
- %%stdout.printf("max i32: ");
- %%stdout.print_i64(@max_value(i32));
- %%stdout.printf("\n");
+ %%io.stdout.printf("max i32: ");
+ %%io.stdout.print_i64(@max_value(i32));
+ %%io.stdout.printf("\n");
- %%stdout.printf("max i64: ");
- %%stdout.print_i64(@max_value(i64));
- %%stdout.printf("\n");
+ %%io.stdout.printf("max i64: ");
+ %%io.stdout.print_i64(@max_value(i64));
+ %%io.stdout.printf("\n");
- %%stdout.printf("min u8: ");
- %%stdout.print_u64(@min_value(u8));
- %%stdout.printf("\n");
+ %%io.stdout.printf("min u8: ");
+ %%io.stdout.print_u64(@min_value(u8));
+ %%io.stdout.printf("\n");
- %%stdout.printf("min u16: ");
- %%stdout.print_u64(@min_value(u16));
- %%stdout.printf("\n");
+ %%io.stdout.printf("min u16: ");
+ %%io.stdout.print_u64(@min_value(u16));
+ %%io.stdout.printf("\n");
- %%stdout.printf("min u32: ");
- %%stdout.print_u64(@min_value(u32));
- %%stdout.printf("\n");
+ %%io.stdout.printf("min u32: ");
+ %%io.stdout.print_u64(@min_value(u32));
+ %%io.stdout.printf("\n");
- %%stdout.printf("min u64: ");
- %%stdout.print_u64(@min_value(u64));
- %%stdout.printf("\n");
+ %%io.stdout.printf("min u64: ");
+ %%io.stdout.print_u64(@min_value(u64));
+ %%io.stdout.printf("\n");
- %%stdout.printf("min i8: ");
- %%stdout.print_i64(@min_value(i8));
- %%stdout.printf("\n");
+ %%io.stdout.printf("min i8: ");
+ %%io.stdout.print_i64(@min_value(i8));
+ %%io.stdout.printf("\n");
- %%stdout.printf("min i16: ");
- %%stdout.print_i64(@min_value(i16));
- %%stdout.printf("\n");
+ %%io.stdout.printf("min i16: ");
+ %%io.stdout.print_i64(@min_value(i16));
+ %%io.stdout.printf("\n");
- %%stdout.printf("min i32: ");
- %%stdout.print_i64(@min_value(i32));
- %%stdout.printf("\n");
+ %%io.stdout.printf("min i32: ");
+ %%io.stdout.print_i64(@min_value(i32));
+ %%io.stdout.printf("\n");
- %%stdout.printf("min i64: ");
- %%stdout.print_i64(@min_value(i64));
- %%stdout.printf("\n");
+ %%io.stdout.printf("min i64: ");
+ %%io.stdout.print_i64(@min_value(i64));
+ %%io.stdout.printf("\n");
}
)SOURCE",
"max u8: 255\n"
@@ -775,10 +788,10 @@ pub fn main(args: [][]u8) -> %void {
add_simple_case("else if expression", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
if (f(1) == 1) {
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
}
fn f(c: u8) -> u8 {
@@ -793,82 +806,82 @@ fn f(c: u8) -> u8 {
)SOURCE", "OK\n");
add_simple_case("overflow intrinsics", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
var result: u8 = undefined;
if (!@add_with_overflow(u8, 250, 100, &result)) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
if (@add_with_overflow(u8, 100, 150, &result)) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
if (result != 250) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("order-independent declarations", R"SOURCE(
-import "std.zig";
-const z = stdin_fileno;
+const io = @import("std").io;
+const z = io.stdin_fileno;
const x : @typeof(y) = 1234;
const y : u16 = 5678;
pub fn main(args: [][]u8) -> %void {
- var x : i32 = print_ok(x);
+ var x_local : i32 = print_ok(x);
}
fn print_ok(val: @typeof(x)) -> @typeof(foo) {
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
return 0;
}
const foo : i32 = 0;
)SOURCE", "OK\n");
add_simple_case("nested arrays", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
const array_of_strings = [][]u8 {"hello", "this", "is", "my", "thing"};
for (array_of_strings) |str| {
- %%stdout.printf(str);
- %%stdout.printf("\n");
+ %%io.stdout.printf(str);
+ %%io.stdout.printf("\n");
}
}
)SOURCE", "hello\nthis\nis\nmy\nthing\n");
add_simple_case("for loops", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
const array = []u8 {9, 8, 7, 6};
for (array) |item| {
- %%stdout.print_u64(item);
- %%stdout.printf("\n");
+ %%io.stdout.print_u64(item);
+ %%io.stdout.printf("\n");
}
for (array) |item, index| {
- %%stdout.print_i64(index);
- %%stdout.printf("\n");
+ %%io.stdout.print_i64(index);
+ %%io.stdout.printf("\n");
}
const unknown_size: []u8 = array;
for (unknown_size) |item| {
- %%stdout.print_u64(item);
- %%stdout.printf("\n");
+ %%io.stdout.print_u64(item);
+ %%io.stdout.printf("\n");
}
for (unknown_size) |item, index| {
- %%stdout.print_i64(index);
- %%stdout.printf("\n");
+ %%io.stdout.print_i64(index);
+ %%io.stdout.printf("\n");
}
}
)SOURCE", "9\n8\n7\n6\n0\n1\n2\n3\n9\n8\n7\n6\n0\n1\n2\n3\n");
add_simple_case("function pointers", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
const fns = []@typeof(fn1) { fn1, fn2, fn3, fn4, };
for (fns) |f| {
- %%stdout.print_u64(f());
- %%stdout.printf("\n");
+ %%io.stdout.print_u64(f());
+ %%io.stdout.printf("\n");
}
}
@@ -879,7 +892,7 @@ fn fn4() -> u32 {8}
)SOURCE", "5\n6\n7\n8\n");
add_simple_case("statically initialized struct", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
struct Foo {
x: i32,
y: bool,
@@ -888,38 +901,38 @@ var foo = Foo { .x = 13, .y = true, };
pub fn main(args: [][]u8) -> %void {
foo.x += 1;
if (foo.x != 14) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("statically initialized array literal", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
const x = []u8{1,2,3,4};
pub fn main(args: [][]u8) -> %void {
const y : [4]u8 = x;
if (y[3] != 4) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("return with implicit cast from while loop", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
while (true) {
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
return;
}
}
)SOURCE", "OK\n");
add_simple_case("return struct byval from function", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
struct Foo {
x: i32,
y: i32,
@@ -933,14 +946,14 @@ fn make_foo(x: i32, y: i32) -> Foo {
pub fn main(args: [][]u8) -> %void {
const foo = make_foo(1234, 5678);
if (foo.y != 5678) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("%% binary operator", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
error ItBroke;
fn g(x: bool) -> %isize {
if (x) {
@@ -953,24 +966,24 @@ pub fn main(args: [][]u8) -> %void {
const a = g(true) %% 3;
const b = g(false) %% 3;
if (a != 3) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
if (b != 10) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("string concatenation", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
- %%stdout.printf("OK" ++ " IT " ++ "WORKED\n");
+ %%io.stdout.printf("OK" ++ " IT " ++ "WORKED\n");
}
)SOURCE", "OK IT WORKED\n");
add_simple_case("constant struct with negation", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
struct Vertex {
x: f32,
y: f32,
@@ -985,30 +998,30 @@ const vertices = []Vertex {
};
pub fn main(args: [][]u8) -> %void {
if (vertices[0].x != -0.6) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("int to ptr cast", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
const x = isize(13);
const y = (&u8)(x);
const z = usize(y);
if (z != 13) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("pointer to void return type", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
const x = void{};
fn f() -> &void {
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
return &x;
}
pub fn main(args: [][]u8) -> %void {
@@ -1018,7 +1031,7 @@ pub fn main(args: [][]u8) -> %void {
)SOURCE", "OK\n");
add_simple_case("unwrap simple value from error", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
fn do() -> %isize {
13
}
@@ -1026,14 +1039,14 @@ fn do() -> %isize {
pub fn main(args: [][]u8) -> %void {
const i = %%do();
if (i != 13) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("store member function in variable", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
struct Foo {
x: i32,
fn member(foo: Foo) -> i32 { foo.x }
@@ -1043,14 +1056,14 @@ pub fn main(args: [][]u8) -> %void {
const member_fn = Foo.member;
const result = member_fn(instance);
if (result != 1234) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("call member function directly", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
struct Foo {
x: i32,
fn member(foo: Foo) -> i32 { foo.x }
@@ -1059,18 +1072,18 @@ pub fn main(args: [][]u8) -> %void {
const instance = Foo { .x = 1234, };
const result = Foo.member(instance);
if (result != 1234) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("call result of if else expression", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
fn a() -> []u8 { "a\n" }
fn b() -> []u8 { "b\n" }
fn f(x: bool) {
- %%stdout.printf((if (x) a else b)());
+ %%io.stdout.printf((if (x) a else b)());
}
pub fn main(args: [][]u8) -> %void {
f(true);
@@ -1079,15 +1092,10 @@ pub fn main(args: [][]u8) -> %void {
)SOURCE", "a\nb\n");
- add_simple_case("expose function pointer to C land", R"SOURCE(
-#link("c")
-export executable "test";
-
-c_import {
- @c_include("stdlib.h");
-}
+ add_simple_case_libc("expose function pointer to C land", R"SOURCE(
+const c = @c_import(@c_include("stdlib.h"));
-export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int {
+export fn compare_fn(a: ?&const c.c_void, b: ?&const c.c_void) -> c_int {
const a_int = (&i32)(a ?? unreachable{});
const b_int = (&i32)(b ?? unreachable{});
if (*a_int < *b_int) {
@@ -1102,11 +1110,11 @@ export fn compare_fn(a: ?&const c_void, b: ?&const c_void) -> c_int {
export fn main(args: c_int, argv: &&u8) -> c_int {
var array = []i32 { 1, 7, 3, 2, 0, 9, 4, 8, 6, 5 };
- qsort((&c_void)(&array[0]), c_ulong(array.len), @sizeof(i32), compare_fn);
+ c.qsort((&c.c_void)(&array[0]), c_ulong(array.len), @sizeof(i32), compare_fn);
for (array) |item, i| {
if (item != i) {
- abort();
+ c.abort();
}
}
@@ -1116,37 +1124,33 @@ export fn main(args: c_int, argv: &&u8) -> c_int {
- add_simple_case("casting between float and integer types", R"SOURCE(
-#link("c")
-export executable "test";
-c_import {
- @c_include("stdio.h");
-}
+ add_simple_case_libc("casting between float and integer types", R"SOURCE(
+const c = @c_import(@c_include("stdio.h"));
export fn main(argc: c_int, argv: &&u8) -> c_int {
const small: f32 = 3.25;
const x: f64 = small;
const y = i32(x);
const z = f64(y);
- printf(c"%.2f\n%d\n%.2f\n%.2f\n", x, y, z, f64(-0.4));
+ c.printf(c"%.2f\n%d\n%.2f\n%.2f\n", x, y, z, f64(-0.4));
return 0;
}
)SOURCE", "3.25\n3\n3.00\n-0.40\n");
add_simple_case("const expression eval handling of variables", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
var x = true;
while (x) {
x = false;
}
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("incomplete struct parameter top level decl", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
struct A {
b: B,
}
@@ -1159,7 +1163,7 @@ struct C {
x: i32,
fn d(c: C) {
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
}
@@ -1182,7 +1186,7 @@ pub fn main(args: [][]u8) -> %void {
add_simple_case("same named methods in incomplete struct", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
struct Foo {
field1: Bar,
@@ -1200,53 +1204,53 @@ pub fn main(args: [][]u8) -> %void {
const bar = Bar {.field2 = 13,};
const foo = Foo {.field1 = bar,};
if (!foo.method()) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
if (!bar.method()) {
- %%stdout.printf("BAD\n");
+ %%io.stdout.printf("BAD\n");
}
- %%stdout.printf("OK\n");
+ %%io.stdout.printf("OK\n");
}
)SOURCE", "OK\n");
add_simple_case("defer with only fallthrough", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
- %%stdout.printf("before\n");
- defer %%stdout.printf("defer1\n");
- defer %%stdout.printf("defer2\n");
- defer %%stdout.printf("defer3\n");
- %%stdout.printf("after\n");
+ %%io.stdout.printf("before\n");
+ defer %%io.stdout.printf("defer1\n");
+ defer %%io.stdout.printf("defer2\n");
+ defer %%io.stdout.printf("defer3\n");
+ %%io.stdout.printf("after\n");
}
)SOURCE", "before\nafter\ndefer3\ndefer2\ndefer1\n");
add_simple_case("defer with return", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
- %%stdout.printf("before\n");
- defer %%stdout.printf("defer1\n");
- defer %%stdout.printf("defer2\n");
+ %%io.stdout.printf("before\n");
+ defer %%io.stdout.printf("defer1\n");
+ defer %%io.stdout.printf("defer2\n");
if (args.len == 1) return;
- defer %%stdout.printf("defer3\n");
- %%stdout.printf("after\n");
+ defer %%io.stdout.printf("defer3\n");
+ %%io.stdout.printf("after\n");
}
)SOURCE", "before\ndefer2\ndefer1\n");
add_simple_case("%defer and it fails", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
do_test() %% return;
}
fn do_test() -> %void {
- %%stdout.printf("before\n");
- defer %%stdout.printf("defer1\n");
- %defer %%stdout.printf("deferErr\n");
+ %%io.stdout.printf("before\n");
+ defer %%io.stdout.printf("defer1\n");
+ %defer %%io.stdout.printf("deferErr\n");
%return its_gonna_fail();
- defer %%stdout.printf("defer3\n");
- %%stdout.printf("after\n");
+ defer %%io.stdout.printf("defer3\n");
+ %%io.stdout.printf("after\n");
}
error IToldYouItWouldFail;
fn its_gonna_fail() -> %void {
@@ -1256,17 +1260,17 @@ fn its_gonna_fail() -> %void {
add_simple_case("%defer and it passes", R"SOURCE(
-import "std.zig";
+const io = @import("std").io;
pub fn main(args: [][]u8) -> %void {
do_test() %% return;
}
fn do_test() -> %void {
- %%stdout.printf("before\n");
- defer %%stdout.printf("defer1\n");
- %defer %%stdout.printf("deferErr\n");
+ %%io.stdout.printf("before\n");
+ defer %%io.stdout.printf("defer1\n");
+ %defer %%io.stdout.printf("deferErr\n");
%return its_gonna_pass();
- defer %%stdout.printf("defer3\n");
- %%stdout.printf("after\n");
+ defer %%io.stdout.printf("defer3\n");
+ %%io.stdout.printf("after\n");
}
fn its_gonna_pass() -> %void { }
)SOURCE", "before\nafter\ndefer3\ndefer1\n");
@@ -1327,14 +1331,9 @@ fn a() {
fn b() {}
)SOURCE", 1, ".tmp_source.zig:4:5: error: unreachable code");
- add_compile_fail_case("bad version string", R"SOURCE(
-#version("aoeu")
-export executable "test";
- )SOURCE", 1, ".tmp_source.zig:2:1: error: invalid version string");
-
add_compile_fail_case("bad import", R"SOURCE(
-import "bogus-does-not-exist.zig";
- )SOURCE", 1, ".tmp_source.zig:2:1: error: unable to find 'bogus-does-not-exist.zig'");
+const bogus = @import("bogus-does-not-exist.zig");
+ )SOURCE", 1, ".tmp_source.zig:2:15: error: unable to find 'bogus-does-not-exist.zig'");
add_compile_fail_case("undeclared identifier", R"SOURCE(
fn a() {
@@ -1450,13 +1449,13 @@ fn f() {
add_compile_fail_case("direct struct loop", R"SOURCE(
struct A { a : A, }
- )SOURCE", 1, ".tmp_source.zig:2:1: error: struct has infinite size");
+ )SOURCE", 1, ".tmp_source.zig:2:1: error: 'A' depends on itself");
add_compile_fail_case("indirect struct loop", R"SOURCE(
struct A { b : B, }
struct B { c : C, }
struct C { a : A, }
- )SOURCE", 1, ".tmp_source.zig:4:1: error: struct has infinite size");
+ )SOURCE", 1, ".tmp_source.zig:2:1: error: 'A' depends on itself");
add_compile_fail_case("invalid struct field", R"SOURCE(
struct A { x : i32, }
@@ -1568,7 +1567,7 @@ fn f() -> @bogus(foo) {
add_compile_fail_case("top level decl dependency loop", R"SOURCE(
const a : @typeof(b) = 0;
const b : @typeof(a) = 0;
- )SOURCE", 1, ".tmp_source.zig:3:19: error: use of undeclared identifier 'a'");
+ )SOURCE", 1, ".tmp_source.zig:2:1: error: 'a' depends on itself");
add_compile_fail_case("noalias on non pointer param", R"SOURCE(
fn f(noalias x: i32) {}
@@ -1589,8 +1588,11 @@ struct Bar {}
fn f(Foo: i32) {
var Bar : i32 = undefined;
}
- )SOURCE", 2, ".tmp_source.zig:5:6: error: variable shadows type 'Foo'",
- ".tmp_source.zig:6:5: error: variable shadows type 'Bar'");
+ )SOURCE", 4,
+ ".tmp_source.zig:5:6: error: redefinition of 'Foo'",
+ ".tmp_source.zig:2:1: note: previous definition is here",
+ ".tmp_source.zig:6:5: error: redefinition of 'Bar'",
+ ".tmp_source.zig:3:1: note: previous definition is here");
add_compile_fail_case("multiple else prongs in a switch", R"SOURCE(
fn f(x: u32) {
@@ -1614,14 +1616,9 @@ fn f(s: []u8) -> []u8 {
)SOURCE", 1, ".tmp_source.zig:3:5: error: string concatenation requires constant expression");
add_compile_fail_case("c_import with bogus include", R"SOURCE(
-c_import {
- @c_include("bogus.h");
-}
- )SOURCE", 2, ".tmp_source.zig:2:1: error: C import failed",
- ".h:1:10: error: 'bogus.h' file not found");
-
- add_compile_fail_case("empty file", "",
- 1, ".tmp_source.zig:1:1: error: missing export declaration and output name not provided");
+const c = @c_import(@c_include("bogus.h"));
+ )SOURCE", 2, ".tmp_source.zig:2:11: error: C import failed",
+ ".h:1:10: note: 'bogus.h' file not found");
add_compile_fail_case("address of number literal", R"SOURCE(
const x = 3;
test/self_hosted.zig
@@ -1,4 +1,5 @@
-import "test_std.zig";
+// test std library
+const std = @import("std");
#attribute("test")
fn empty_function() {}
test/test_std.zig
@@ -1,1 +0,0 @@
-import "std.zig";
CMakeLists.txt
@@ -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"
)