Commit b28b7f63d1
Changed files (26)
doc
vim
syntax
example
arrays
cat
expressions
guess_number
hello_world
list
maybe_type
structs
test
doc/vim/syntax/zig.vim
@@ -15,8 +15,8 @@ syn keyword zigConditional if else switch
syn keyword zigRepeat while for
syn keyword zigConstant null
-syn keyword zigKeyword fn unreachable use void
-syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string
+syn keyword zigKeyword fn use
+syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 string void unreachable
syn keyword zigBoolean true false
doc/langref.md
@@ -34,13 +34,13 @@ Root : many(TopLevelDecl) token(EOF)
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | ContainerDecl | VariableDeclaration
-VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression))
+VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) UnwrapMaybeExpression option(token(Eq) Expression))
ContainerDecl : many(Directive) option(FnVisibleMod) (token(Struct) | token(Enum)) token(Symbol) token(LBrace) many(StructMember) token(RBrace)
StructMember: StructField | FnDecl
-StructField : token(Symbol) option(token(Colon) Type token(Comma))
+StructField : token(Symbol) option(token(Colon) Expression) token(Comma))
Use : many(Directive) token(Use) token(String) token(Semicolon)
@@ -48,7 +48,7 @@ RootExportDecl : many(Directive) token(Export) token(Symbol) token(String) token
ExternBlock : many(Directive) token(Extern) token(LBrace) many(FnDecl) token(RBrace)
-FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type)
+FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(Expression)
Directive : token(NumberSign) token(Symbol) token(LParen) token(String) token(RParen)
@@ -56,23 +56,11 @@ FnVisibleMod : token(Pub) | token(Export)
FnDecl : FnProto token(Semicolon)
-FnDef : FnProto Block
+FnDef : FnProto token(FatArrow) Block
ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)
-ParamDecl : token(Symbol) token(Colon) Type | token(Ellipsis)
-
-Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompilerFnExpr
-
-CompilerFnExpr : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen)
-
-CompilerFnType : token(NumberSign) token(Symbol) token(LParen) Type token(RParen)
-
-PointerType : token(Ampersand) option(token(Const)) option(token(NoAlias)) Type
-
-MaybeType : token(Question) Type
-
-ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) option(token(NoAlias)) Type
+ParamDecl : option(token(NoAlias)) token(Symbol) token(Colon) UnwrapMaybeExpression | token(Ellipsis)
Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)
@@ -80,11 +68,9 @@ Statement : Label | VariableDeclaration token(Semicolon) | NonBlockExpression to
Label: token(Symbol) token(Colon)
-VariableDeclaration : (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression))
-
Expression : BlockExpression | NonBlockExpression
-NonBlockExpression : ReturnExpression | AssignmentExpression | AsmExpression
+NonBlockExpression : ReturnExpression | AssignmentExpression
AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen)
@@ -92,13 +78,13 @@ AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput)
AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers)
-AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) Type) token(RParen)
+AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) Expression) token(RParen)
AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)
AsmClobbers: token(Colon) list(token(String), token(Comma))
-UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestion) BoolOrExpression | BoolOrExpression
+UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestionMark) BoolOrExpression | BoolOrExpression
AssignmentExpression : UnwrapMaybeExpression AssignmentOperator UnwrapMaybeExpression | UnwrapMaybeExpression
@@ -116,7 +102,7 @@ IfExpression : IfVarExpression | IfBoolExpression
IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else)
-IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(token(Colon) Type) Token(MaybeAssign) Expression token(RParen) Expression Option(Else)
+IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(token(Colon) Expression) Token(MaybeAssign) Expression token(RParen) Expression Option(Else)
Else : token(Else) Expression
@@ -144,11 +130,11 @@ MultiplyExpression : CastExpression MultiplyOperator MultiplyExpression | CastEx
MultiplyOperator : token(Star) | token(Slash) | token(Percent)
-CastExpression : CastExpression token(as) Type | PrefixOpExpression
+CastExpression : CastExpression token(as) PrimaryExpression | PrefixOpExpression
PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression
-SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
+SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ContainerInitExpression)
FieldAccessExpression : token(Dot) token(Symbol)
@@ -158,26 +144,30 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket)
SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const))
-PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const)))
+ContainerInitExpression : token(LBrace) ContainerInitBody token(RBrace)
+
+ContainerInitBody : list(StructLiteralField, token(Comma)) | list(Expression, token(Comma))
+
+StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
-PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType | (token(AtSign) token(Symbol) FnCallExpression)
+PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const))) | token(QuestionMark)
-StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace)
+PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | token(Symbol) | (token(AtSign) token(Symbol) FnCallExpression) | ArrayType | AsmExpression
-StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression
+ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) Expression
-Goto: token(Goto) token(Symbol)
+GotoExpression: token(Goto) token(Symbol)
GroupedExpression : token(LParen) Expression token(RParen)
-KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) | token(Null)
+KeywordLiteral : token(True) | token(False) | token(Null) | token(Break) | token(Continue)
```
## Operator Precedence
```
-x() x[] x.y
-!x -x ~x *x &x &const x
+x() x[] x{} x.y
+!x -x ~x *x &x
as
* / %
+ -
example/arrays/arrays.zig
@@ -1,36 +0,0 @@
-export executable "arrays";
-
-use "std.zig";
-
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
- var array : [5]u32;
-
- var i : u32 = 0;
- while (i < 5) {
- array[i] = i + 1;
- i = array[i];
- }
-
- i = 0;
- var accumulator : u32 = 0;
- while (i < 5) {
- accumulator += array[i];
-
- i += 1;
- }
-
- if (accumulator != 15) {
- print_str("BAD\n");
- }
-
- if (get_array_len(array) != 5) {
- print_str("BAD\n");
- }
-
- print_str("OK\n");
- return 0;
-}
-
-fn get_array_len(a: []u32) -> usize {
- a.len
-}
example/cat/main.zig
@@ -0,0 +1,7 @@
+export executable "cat";
+
+pub main(argv: [][]u8) -> i32 {
+
+
+ return 0;
+}
example/expressions/expressions.zig
@@ -1,52 +0,0 @@
-export executable "expressions";
-
-use "std.zig";
-
-fn other_exit() -> unreachable {
- if (true) { exit(0); }
- // the unreachable statement is the programmer assuring the compiler that this code is impossible to execute.
- unreachable;
-}
-
-export fn main(argc: isize, argv: &&u8, env: &&u8) -> unreachable {
- const a : i32 = 1;
- const b = 2 as i32;
- // const c : i32; // not yet support for const variables
- // const d; // parse error
- if (a + b == 3) {
- const no_conflict : i32 = 5;
- if (no_conflict == 5) { print_str("OK 1\n" as string); }
- }
-
- const c = {
- const no_conflict : i32 = 10;
- no_conflict
- };
- if (c == 10) { print_str("OK 2\n" as string); }
-
- void_fun(1, void, 2);
-
- test_mutable_vars();
-
- other_exit();
-}
-
-fn void_fun(a : i32, b : void, c : i32) -> void {
- const x = a + 1; // i32
- const y = c + 1; // i32
- const z = b; // void
- const w : void = z; // void
- if (x + y == 4) { return w; }
-}
-
-fn test_mutable_vars() {
- var i : i32 = 0;
-loop_start:
- if i == 3 {
- goto done;
- }
- print_str("loop\n" as string);
- i = i + 1;
- goto loop_start;
-done:
-}
example/guess_number/main.zig
@@ -3,12 +3,12 @@ export executable "guess_number";
use "std.zig";
use "rand.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
print_str("Welcome to the Guess Number Game in Zig.\n");
var seed : u32;
- const err = os_get_random_bytes(&seed as &u8, #sizeof(u32));
- if (err != #sizeof(u32)) {
+ const err = os_get_random_bytes(&seed as (&u8), @sizeof(u32));
+ if (err != @sizeof(u32)) {
// TODO full error message
fprint_str(stderr_fileno, "unable to get random bytes\n");
return 1;
example/hello_world/hello.zig
@@ -2,7 +2,7 @@ export executable "hello";
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
print_str("Hello, world!\n");
return 0;
}
example/hello_world/hello_libc.zig
@@ -2,11 +2,10 @@ export executable "hello";
#link("c")
extern {
- fn printf(__format: &const u8, ...) -> i32;
- fn exit(__status: i32) -> unreachable;
+ fn printf(__format: &const u8, ...) i32;
}
-export fn main(argc: i32, argv: &&u8, env: &&u8) -> i32 {
+export fn main(argc: i32, argv: &&u8, env: &&u8) i32 => {
printf(c"Hello, world!\n");
return 0;
}
example/list/list.zig
@@ -1,16 +1,16 @@
pub struct List#(T: type) {
items: ?&T,
- length: usize,
- capacity: usize,
+ length: isize,
+ capacity: isize,
- pub fn (l: &List) deinit() {
+ pub fn deinit(l: &List) {
free(l.items);
- l.items = None;
+ l.items = null;
}
pub fn append(l: &List, item: T) -> error {
const err = l.ensure_capacity(l.length + 1);
- if err != Error.None {
+ if err != error.None {
return err;
}
const raw_items = l.items ?? unreachable;
@@ -47,11 +47,11 @@ pub struct List#(T: type) {
better_capacity *= 2;
}
if better_capacity != l.capacity {
- const new_items = realloc(l.items, better_capacity) ?? { return Error.NoMem };
+ const new_items = realloc(l.items, better_capacity) ?? { return error.NoMem };
l.items = new_items;
l.capacity = better_capacity;
}
- Error.None
+ error.None
}
}
@@ -64,3 +64,41 @@ pub fn realloc#(T: type)(ptr: ?&T, new_count: usize) -> ?&T {
pub fn free#(T: type)(ptr: ?&T) {
}
+
+
+////////////////// alternate
+
+// previously proposed, but with : instead of ->
+// `:` means "parser should expect a type now"
+fn max#(T :type)(a :T, b :T) :T {
+ if (a > b) a else b
+}
+
+// andy's new idea
+// parameters can talk about @typeof() for previous parameters.
+// using :T here is equivalent to @child_type(@typeof(T))
+fn max(T :type, a :T, b :T) :T {
+ if (a > b) a else b
+}
+
+fn f() {
+ const x :i32 = 1234;
+ const y :i32 = 5678;
+ const z = max(@typeof(x), x, y);
+}
+
+// So, type-generic functions don't need any fancy syntax. type-generic
+// containers still do, though:
+
+pub struct List(T :type) {
+ items :?&T,
+ length :isize,
+ capacity :isize,
+}
+
+// Types are always marked with ':' so we don't need '#' to indicate type generic parameters.
+
+fn f() {
+ var list :List(:u8);
+}
+
example/maybe_type/main.zig
@@ -2,7 +2,7 @@ export executable "maybe_type";
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
const x : ?bool = true;
if (const y ?= x) {
@@ -25,7 +25,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
const final_x : ?i32 = 13;
- const num = final_x ?? unreachable;
+ const num = final_x ?? unreachable{};
if (num != 13) {
print_str("BAD\n");
example/multiple_files/foo.zig
@@ -2,10 +2,10 @@ use "std.zig";
// purposefully conflicting function with main.zig
// but it's private so it should be OK
-fn private_function() {
+fn private_function() => {
print_str("OK 1\n");
}
-pub fn print_text() {
+pub fn print_text() => {
private_function();
}
example/multiple_files/main.zig
@@ -3,12 +3,12 @@ export executable "test-multiple-files";
use "std.zig";
use "foo.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
private_function();
print_str("OK 2\n");
return 0;
}
-fn private_function() {
+fn private_function() => {
print_text();
}
example/structs/structs.zig
@@ -1,87 +0,0 @@
-export executable "structs";
-
-use "std.zig";
-
-pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
- var foo : Foo;
-
- foo.a = foo.a + 1;
-
- foo.b = foo.a == 1;
-
- test_foo(foo);
-
- modify_foo(&foo);
-
- if foo.c != 100 {
- print_str("BAD\n");
- }
-
- test_point_to_self();
-
- test_byval_assign();
-
- test_initializer();
-
- print_str("OK\n");
- return 0;
-}
-
-struct Foo {
- a : i32,
- b : bool,
- c : f32,
-}
-
-struct Node {
- val: Val,
- next: &Node,
-}
-
-struct Val {
- x: i32,
-}
-
-fn test_foo(foo : Foo) {
- if !foo.b {
- print_str("BAD\n");
- }
-}
-
-fn modify_foo(foo : &Foo) {
- foo.c = 100;
-}
-
-fn test_point_to_self() {
- var root : Node;
- root.val.x = 1;
-
- var node : Node;
- node.next = &root;
- node.val.x = 2;
-
- root.next = &node;
-
- if node.next.next.next.val.x != 1 {
- print_str("BAD\n");
- }
-}
-
-fn test_byval_assign() {
- var foo1 : Foo;
- var foo2 : Foo;
-
- foo1.a = 1234;
-
- if foo2.a != 0 { print_str("BAD\n"); }
-
- foo2 = foo1;
-
- if foo2.a != 1234 { print_str("BAD - byval assignment failed\n"); }
-
-}
-
-fn test_initializer() {
- const val = Val { .x = 42 };
- if val.x != 42 { print_str("BAD\n"); }
-}
src/all_types.hpp
@@ -100,7 +100,6 @@ enum NodeType {
NodeTypeFnDef,
NodeTypeFnDecl,
NodeTypeParamDecl,
- NodeTypeType,
NodeTypeBlock,
NodeTypeExternBlock,
NodeTypeDirective,
@@ -111,7 +110,6 @@ enum NodeType {
NodeTypeNumberLiteral,
NodeTypeStringLiteral,
NodeTypeCharLiteral,
- NodeTypeUnreachable,
NodeTypeSymbol,
NodeTypePrefixOpExpr,
NodeTypeFnCallExpr,
@@ -119,7 +117,6 @@ enum NodeType {
NodeTypeSliceExpr,
NodeTypeFieldAccessExpr,
NodeTypeUse,
- NodeTypeVoid,
NodeTypeBoolLiteral,
NodeTypeNullLiteral,
NodeTypeIfBoolExpr,
@@ -132,10 +129,9 @@ enum NodeType {
NodeTypeAsmExpr,
NodeTypeStructDecl,
NodeTypeStructField,
- NodeTypeStructValueExpr,
+ NodeTypeContainerInitExpr,
NodeTypeStructValueField,
- NodeTypeCompilerFnExpr,
- NodeTypeCompilerFnType,
+ NodeTypeArrayType,
};
struct AstNodeRoot {
@@ -185,30 +181,10 @@ struct AstNodeFnDecl {
struct AstNodeParamDecl {
Buf name;
AstNode *type;
-
- // populated by semantic analyzer
- VariableTableEntry *variable;
-};
-
-enum AstNodeTypeType {
- AstNodeTypeTypePrimitive,
- AstNodeTypeTypePointer,
- AstNodeTypeTypeArray,
- AstNodeTypeTypeMaybe,
- AstNodeTypeTypeCompilerExpr,
-};
-
-struct AstNodeType {
- AstNodeTypeType type;
- Buf primitive_name;
- AstNode *child_type;
- AstNode *array_size; // can be null
- bool is_const;
bool is_noalias;
- AstNode *compiler_expr;
// populated by semantic analyzer
- TypeTableEntry *entry;
+ VariableTableEntry *variable;
};
struct AstNodeBlock {
@@ -295,6 +271,7 @@ struct AstNodeFnCallExpr {
// populated by semantic analyzer:
BuiltinFnEntry *builtin_fn;
Expr resolved_expr;
+ NumLitCodeGen resolved_num_lit;
};
struct AstNodeArrayAccessExpr {
@@ -360,6 +337,7 @@ enum PrefixOp {
PrefixOpAddressOf,
PrefixOpConstAddressOf,
PrefixOpDereference,
+ PrefixOpMaybe,
};
struct AstNodePrefixOpExpr {
@@ -537,30 +515,19 @@ struct AstNodeStructValueField {
TypeStructField *type_struct_field;
};
-struct AstNodeStructValueExpr {
- AstNode *type;
- ZigList<AstNode *> fields;
-
- // populated by semantic analyzer
- StructValExprCodeGen codegen;
- Expr resolved_expr;
-};
-
-struct AstNodeCompilerFnExpr {
- Buf name;
- AstNode *expr;
-
- // populated by semantic analyzer
- Expr resolved_expr;
+enum ContainerInitKind {
+ ContainerInitKindStruct,
+ ContainerInitKindArray,
};
-struct AstNodeCompilerFnType {
- Buf name;
+struct AstNodeContainerInitExpr {
AstNode *type;
+ ZigList<AstNode *> entries;
+ ContainerInitKind kind;
// populated by semantic analyzer
+ StructValExprCodeGen resolved_struct_val_expr;
Expr resolved_expr;
- NumLitCodeGen resolved_num_lit;
};
struct AstNodeNullLiteral {
@@ -569,16 +536,6 @@ struct AstNodeNullLiteral {
Expr resolved_expr;
};
-struct AstNodeVoidExpr {
- // populated by semantic analyzer
- Expr resolved_expr;
-};
-
-struct AstNodeUnreachableExpr {
- // populated by semantic analyzer
- Expr resolved_expr;
-};
-
struct AstNodeSymbolExpr {
Buf symbol;
@@ -603,6 +560,15 @@ struct AstNodeContinueExpr {
Expr resolved_expr;
};
+struct AstNodeArrayType {
+ AstNode *size;
+ AstNode *child_type;
+ bool is_const;
+
+ // populated by semantic analyzer
+ Expr resolved_expr;
+};
+
struct AstNode {
enum NodeType type;
int line;
@@ -615,7 +581,6 @@ struct AstNode {
AstNodeFnDef fn_def;
AstNodeFnDecl fn_decl;
AstNodeFnProto fn_proto;
- AstNodeType type;
AstNodeParamDecl param_decl;
AstNodeBlock block;
AstNodeReturnExpr return_expr;
@@ -641,17 +606,14 @@ struct AstNode {
AstNodeStringLiteral string_literal;
AstNodeCharLiteral char_literal;
AstNodeNumberLiteral number_literal;
- AstNodeStructValueExpr struct_val_expr;
+ AstNodeContainerInitExpr container_init_expr;
AstNodeStructValueField struct_val_field;
- AstNodeCompilerFnExpr compiler_fn_expr;
- AstNodeCompilerFnType compiler_fn_type;
AstNodeNullLiteral null_literal;
- AstNodeVoidExpr void_expr;
- AstNodeUnreachableExpr unreachable_expr;
AstNodeSymbolExpr symbol_expr;
AstNodeBoolLiteral bool_literal;
AstNodeBreakExpr break_expr;
AstNodeContinueExpr continue_expr;
+ AstNodeArrayType array_type;
} data;
};
@@ -670,7 +632,6 @@ struct AsmToken {
struct TypeTableEntryPointer {
TypeTableEntry *child_type;
bool is_const;
- bool is_noalias;
};
struct TypeTableEntryInt {
@@ -770,8 +731,8 @@ struct TypeTableEntry {
} data;
// use these fields to make sure we don't duplicate type table entries for the same type
- TypeTableEntry *pointer_parent[2][2]; // 0 - const. 1 - noalias
- TypeTableEntry *unknown_size_array_parent[2][2]; // 0 - const. 1 - noalias
+ TypeTableEntry *pointer_parent[2];
+ TypeTableEntry *unknown_size_array_parent[2];
HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
TypeTableEntry *maybe_parent;
TypeTableEntry *meta_parent;
@@ -830,6 +791,11 @@ enum BuiltinFnId {
BuiltinFnIdArithmeticWithOverflow,
BuiltinFnIdMemcpy,
BuiltinFnIdMemset,
+ BuiltinFnIdSizeof,
+ BuiltinFnIdMaxValue,
+ BuiltinFnIdMinValue,
+ BuiltinFnIdValueCount,
+ BuiltinFnIdTypeof,
};
struct BuiltinFnEntry {
src/analyze.cpp
@@ -15,10 +15,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
TypeTableEntry *expected_type, AstNode *node);
static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context,
AstNode *node, AstNodeNumberLiteral *out_number_literal);
-static void collect_type_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *type_node, TopLevelDecl *decl_node);
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);
+static TypeTableEntry *unwrapped_node_type(AstNode *node);
static AstNode *first_executing_node(AstNode *node) {
switch (node->type) {
@@ -40,7 +40,6 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
- case NodeTypeType:
case NodeTypeBlock:
case NodeTypeExternBlock:
case NodeTypeDirective:
@@ -49,11 +48,9 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeNumberLiteral:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
- case NodeTypeUnreachable:
case NodeTypeSymbol:
case NodeTypePrefixOpExpr:
case NodeTypeUse:
- case NodeTypeVoid:
case NodeTypeBoolLiteral:
case NodeTypeNullLiteral:
case NodeTypeIfBoolExpr:
@@ -65,11 +62,10 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeAsmExpr:
case NodeTypeStructDecl:
case NodeTypeStructField:
- case NodeTypeStructValueExpr:
case NodeTypeStructValueField:
case NodeTypeWhileExpr:
- case NodeTypeCompilerFnExpr:
- case NodeTypeCompilerFnType:
+ case NodeTypeContainerInitExpr:
+ case NodeTypeArrayType:
return node;
}
zig_panic("unreachable");
@@ -188,8 +184,9 @@ static TypeTableEntry *get_meta_type(CodeGen *g, TypeTableEntry *child_type) {
}
}
-TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_noalias) {
- TypeTableEntry **parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)][(is_noalias ? 1 : 0)];
+TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
+ assert(child_type->id != TypeTableEntryIdInvalid);
+ TypeTableEntry **parent_pointer = &child_type->pointer_parent[(is_const ? 1 : 0)];
if (*parent_pointer) {
return *parent_pointer;
} else {
@@ -197,9 +194,8 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
entry->type_ref = LLVMPointerType(child_type->type_ref, 0);
const char *const_str = is_const ? "const " : "";
- const char *noalias_str = is_noalias ? "noalias " : "";
buf_resize(&entry->name, 0);
- buf_appendf(&entry->name, "&%s%s%s", const_str, noalias_str, buf_ptr(&child_type->name));
+ buf_appendf(&entry->name, "&%s%s", const_str, buf_ptr(&child_type->name));
entry->size_in_bits = g->pointer_size_bytes * 8;
entry->align_in_bits = g->pointer_size_bytes * 8;
@@ -208,14 +204,13 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name));
entry->data.pointer.child_type = child_type;
entry->data.pointer.is_const = is_const;
- entry->data.pointer.is_noalias = is_noalias;
*parent_pointer = entry;
return entry;
}
}
-static TypeTableEntry *get_maybe_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *child_type) {
+static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
if (child_type->maybe_parent) {
TypeTableEntry *entry = child_type->maybe_parent;
return entry;
@@ -293,9 +288,10 @@ static TypeTableEntry *get_array_type(CodeGen *g, ImportTableEntry *import,
}
static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry *import,
- TypeTableEntry *child_type, bool is_const, bool is_noalias)
+ TypeTableEntry *child_type, bool is_const)
{
- TypeTableEntry **parent_pointer = &child_type->unknown_size_array_parent[(is_const ? 1 : 0)][(is_noalias ? 1 : 0)];
+ assert(child_type->id != TypeTableEntryIdInvalid);
+ TypeTableEntry **parent_pointer = &child_type->unknown_size_array_parent[(is_const ? 1 : 0)];
if (*parent_pointer) {
return *parent_pointer;
} else {
@@ -305,7 +301,7 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry
buf_appendf(&entry->name, "[]%s", buf_ptr(&child_type->name));
entry->type_ref = LLVMStructCreateNamed(LLVMGetGlobalContext(), buf_ptr(&entry->name));
- TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const, is_noalias);
+ TypeTableEntry *pointer_type = get_pointer_to_type(g, child_type, is_const);
unsigned element_count = 2;
LLVMTypeRef element_types[] = {
@@ -343,6 +339,25 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, ImportTableEntry
}
}
+// like analyze expression, but expects a type. creates an error if resulting type is
+// not a meta type. unwraps it if it is.
+static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+ AstNode *node)
+{
+ TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, node);
+ if (type_entry->id == TypeTableEntryIdInvalid) {
+ return type_entry;
+ } else if (type_entry->id == TypeTableEntryIdMetaType) {
+ return type_entry->data.meta_type.child_type;
+ } else {
+ add_node_error(g, first_executing_node(node),
+ buf_sprintf("expected type, found expression"));
+ get_resolved_expr(node)->type_entry = g->builtin_types.entry_invalid;
+ return g->builtin_types.entry_invalid;
+ }
+}
+
+
static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context,
AstNode *node, AstNodeNumberLiteral *out_number_literal)
{
@@ -436,6 +451,40 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context,
zig_unreachable();
}
+static TypeTableEntry *eval_const_expr_fn_call(CodeGen *g, BlockContext *context,
+ AstNode *node, AstNodeNumberLiteral *out_number_literal)
+{
+ if (!node->data.fn_call_expr.is_builtin) {
+ return g->builtin_types.entry_invalid;
+ }
+
+ switch (node->data.fn_call_expr.builtin_fn->id) {
+ case BuiltinFnIdInvalid:
+ zig_unreachable();
+ case BuiltinFnIdArithmeticWithOverflow:
+ case BuiltinFnIdMemcpy:
+ case BuiltinFnIdMemset:
+ return g->builtin_types.entry_invalid;
+ case BuiltinFnIdSizeof:
+ {
+ AstNode *type_node = node->data.fn_call_expr.params.at(0);
+ TypeTableEntry *target_type = unwrapped_node_type(type_node);
+ out_number_literal->overflow = false;
+ out_number_literal->data.x_uint = target_type->size_in_bits / 8;
+ out_number_literal->kind = get_number_literal_kind_unsigned(out_number_literal->data.x_uint);
+ return get_resolved_expr(node)->type_entry;
+ }
+ case BuiltinFnIdMaxValue:
+ case BuiltinFnIdMinValue:
+ zig_panic("TODO eval_const_expr_fn_call max/min value");
+ case BuiltinFnIdValueCount:
+ zig_panic("TODO eval_const_expr_fn_call value_count");
+ case BuiltinFnIdTypeof:
+ return get_resolved_expr(node)->type_entry;
+ }
+ zig_unreachable();
+}
+
static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context,
AstNode *node, AstNodeNumberLiteral *out_number_literal)
{
@@ -450,175 +499,25 @@ static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context,
return get_resolved_expr(node)->type_entry;
case NodeTypeBinOpExpr:
return eval_const_expr_bin_op(g, context, node, out_number_literal);
- case NodeTypeCompilerFnType:
- {
- Buf *name = &node->data.compiler_fn_type.name;
- TypeTableEntry *expr_type = get_resolved_expr(node)->type_entry;
- if (buf_eql_str(name, "sizeof")) {
- TypeTableEntry *target_type = node->data.compiler_fn_type.type->data.type.entry;
- out_number_literal->overflow = false;
- out_number_literal->data.x_uint = target_type->size_in_bits / 8;
- out_number_literal->kind = get_number_literal_kind_unsigned(out_number_literal->data.x_uint);
-
- return expr_type;
- } else if (buf_eql_str(name, "max_value")) {
- zig_panic("TODO eval_const_expr max_value");
- } else if (buf_eql_str(name, "min_value")) {
- zig_panic("TODO eval_const_expr min_value");
- } else if (buf_eql_str(name, "value_count")) {
- zig_panic("TODO eval_const_expr value_count");
- } else {
- return g->builtin_types.entry_invalid;
- }
- break;
- }
case NodeTypeSymbol:
{
VariableTableEntry *var = find_variable(context, &node->data.symbol_expr.symbol);
assert(var);
AstNode *decl_node = var->decl_node;
AstNode *expr_node = decl_node->data.variable_declaration.expr;
- BlockContext *next_context = get_resolved_expr(expr_node)->block_context;
- return eval_const_expr(g, next_context, expr_node, out_number_literal);
- }
- default:
- return g->builtin_types.entry_invalid;
- }
-}
-
-static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry *import,
- BlockContext *context, bool noalias_allowed)
-{
- assert(node->type == NodeTypeType);
- switch (node->data.type.type) {
- case AstNodeTypeTypePrimitive:
- {
- Buf *name = &node->data.type.primitive_name;
- auto table_entry = import->block_context->type_table.maybe_get(name);
- if (!table_entry) {
- table_entry = g->primitive_type_table.maybe_get(name);
- }
- if (table_entry) {
- node->data.type.entry = table_entry->value;
- } else {
- add_node_error(g, node,
- buf_sprintf("invalid type name: '%s'", buf_ptr(name)));
- node->data.type.entry = g->builtin_types.entry_invalid;
- }
- return node->data.type.entry;
- }
- case AstNodeTypeTypePointer:
- {
- bool use_noalias = false;
- if (node->data.type.is_noalias) {
- if (!noalias_allowed) {
- add_node_error(g, node,
- buf_create_from_str("invalid noalias qualifier"));
- } else {
- use_noalias = true;
- }
- }
-
- resolve_type(g, node->data.type.child_type, import, context, false);
- TypeTableEntry *child_type = node->data.type.child_type->data.type.entry;
- assert(child_type);
- if (child_type->id == TypeTableEntryIdUnreachable) {
- add_node_error(g, node,
- buf_create_from_str("pointer to unreachable not allowed"));
- node->data.type.entry = g->builtin_types.entry_invalid;
- return node->data.type.entry;
- } else if (child_type->id == TypeTableEntryIdInvalid) {
- node->data.type.entry = child_type;
- return child_type;
- } else {
- node->data.type.entry = get_pointer_to_type(g, child_type, node->data.type.is_const, use_noalias);
- return node->data.type.entry;
- }
- }
- case AstNodeTypeTypeArray:
- {
- AstNode *size_node = node->data.type.array_size;
-
- bool use_noalias = false;
- if (node->data.type.is_noalias) {
- if (!noalias_allowed || size_node) {
- add_node_error(g, node,
- buf_create_from_str("invalid noalias qualifier"));
- } else {
- use_noalias = true;
- }
- }
-
- TypeTableEntry *child_type = resolve_type(g, node->data.type.child_type, import, context, false);
- if (child_type->id == TypeTableEntryIdUnreachable) {
- add_node_error(g, node,
- buf_create_from_str("array of unreachable not allowed"));
- node->data.type.entry = g->builtin_types.entry_invalid;
- return node->data.type.entry;
- }
-
- if (size_node) {
- TypeTableEntry *size_type = analyze_expression(g, import, context,
- g->builtin_types.entry_usize, size_node);
- if (size_type->id == TypeTableEntryIdInvalid) {
- node->data.type.entry = g->builtin_types.entry_invalid;
- return node->data.type.entry;
- }
-
- AstNodeNumberLiteral number_literal;
- TypeTableEntry *resolved_type = eval_const_expr(g, context, size_node, &number_literal);
-
- if (resolved_type->id == TypeTableEntryIdInt) {
- if (resolved_type->data.integral.is_signed) {
- add_node_error(g, size_node,
- buf_create_from_str("array size must be unsigned integer"));
- node->data.type.entry = g->builtin_types.entry_invalid;
- } else {
- node->data.type.entry = get_array_type(g, import, child_type, number_literal.data.x_uint);
- }
- } else {
- add_node_error(g, size_node,
- buf_create_from_str("unable to resolve constant expression"));
- node->data.type.entry = g->builtin_types.entry_invalid;
- }
- return node->data.type.entry;
- } else {
- node->data.type.entry = get_unknown_size_array_type(g, import, child_type,
- node->data.type.is_const, use_noalias);
- return node->data.type.entry;
- }
-
- }
- case AstNodeTypeTypeMaybe:
- {
- resolve_type(g, node->data.type.child_type, import, context, false);
- TypeTableEntry *child_type = node->data.type.child_type->data.type.entry;
- assert(child_type);
- if (child_type->id == TypeTableEntryIdUnreachable) {
- add_node_error(g, node,
- buf_create_from_str("maybe unreachable type not allowed"));
- } else if (child_type->id == TypeTableEntryIdInvalid) {
- return child_type;
- }
- node->data.type.entry = get_maybe_type(g, import, child_type);
- return node->data.type.entry;
- }
- case AstNodeTypeTypeCompilerExpr:
- {
- AstNode *compiler_expr_node = node->data.type.compiler_expr;
- Buf *fn_name = &compiler_expr_node->data.compiler_fn_expr.name;
- if (buf_eql_str(fn_name, "typeof")) {
- node->data.type.entry = analyze_expression(g, import, context, nullptr,
- compiler_expr_node->data.compiler_fn_expr.expr);
+ if (expr_node) {
+ BlockContext *next_context = get_resolved_expr(expr_node)->block_context;
+ return eval_const_expr(g, next_context, expr_node, out_number_literal);
} else {
- add_node_error(g, node,
- buf_sprintf("invalid compiler function: '%s'", buf_ptr(fn_name)));
- node->data.type.entry = g->builtin_types.entry_invalid;
+ // can't eval it
+ return g->builtin_types.entry_invalid;
}
- return node->data.type.entry;
}
+ case NodeTypeFnCallExpr:
+ return eval_const_expr_fn_call(g, context, node, out_number_literal);
+ default:
+ return g->builtin_types.entry_invalid;
}
- zig_unreachable();
}
static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,
@@ -654,8 +553,9 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
AstNode *child = node->data.fn_proto.params.at(i);
assert(child->type == NodeTypeParamDecl);
- TypeTableEntry *type_entry = resolve_type(g, child->data.param_decl.type,
- import, import->block_context, true);
+ TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context,
+ child->data.param_decl.type);
+
if (type_entry->id == TypeTableEntryIdUnreachable) {
add_node_error(g, child->data.param_decl.type,
buf_sprintf("parameter of type 'unreachable' not allowed"));
@@ -667,7 +567,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
}
}
- resolve_type(g, node->data.fn_proto.return_type, import, import->block_context, true);
+ analyze_type_expr(g, import, import->block_context, node->data.fn_proto.return_type);
}
static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) {
@@ -729,8 +629,8 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
TypeEnumField *type_enum_field = &enum_type->data.enumeration.fields[i];
type_enum_field->name = &field_node->data.struct_field.name;
- type_enum_field->type_entry = resolve_type(g, field_node->data.struct_field.type,
- import, import->block_context, false);
+ type_enum_field->type_entry = analyze_type_expr(g, import, import->block_context,
+ field_node->data.struct_field.type);
type_enum_field->value = i;
di_enumerators[i] = LLVMZigCreateDebugEnumerator(g->dbuilder, buf_ptr(type_enum_field->name), i);
@@ -815,7 +715,7 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
biggest_align_in_bits,
tag_type_entry->size_in_bits, 0, union_di_type);
- // create debug type for root struct
+ // create debug type for root struct
LLVMZigDIType *di_root_members[] = {
tag_member_di_type,
union_member_di_type,
@@ -893,8 +793,8 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
type_struct_field->name = &field_node->data.struct_field.name;
- type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type,
- import, import->block_context, false);
+ type_struct_field->type_entry = analyze_type_expr(g, import, import->block_context,
+ field_node->data.struct_field.type);
type_struct_field->src_index = i;
type_struct_field->gen_index = -1;
@@ -1144,7 +1044,6 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeFnDef:
case NodeTypeDirective:
case NodeTypeParamDecl:
- case NodeTypeType:
case NodeTypeFnDecl:
case NodeTypeReturnExpr:
case NodeTypeRoot:
@@ -1156,8 +1055,6 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeNumberLiteral:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
- case NodeTypeUnreachable:
- case NodeTypeVoid:
case NodeTypeBoolLiteral:
case NodeTypeNullLiteral:
case NodeTypeSymbol:
@@ -1173,10 +1070,9 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypeStructField:
- case NodeTypeStructValueExpr:
case NodeTypeStructValueField:
- case NodeTypeCompilerFnExpr:
- case NodeTypeCompilerFnType:
+ case NodeTypeContainerInitExpr:
+ case NodeTypeArrayType:
zig_unreachable();
}
}
@@ -1186,13 +1082,22 @@ static FnTableEntry *get_context_fn_entry(BlockContext *context) {
return context->fn_entry;
}
+static TypeTableEntry *unwrapped_node_type(AstNode *node) {
+ TypeTableEntry *meta_type_entry = get_resolved_expr(node)->type_entry;
+ if (meta_type_entry->id == TypeTableEntryIdInvalid) {
+ return meta_type_entry;
+ } else {
+ assert(meta_type_entry->id == TypeTableEntryIdMetaType);
+ return meta_type_entry->data.meta_type.child_type;
+ }
+}
+
static TypeTableEntry *get_return_type(BlockContext *context) {
FnTableEntry *fn_entry = get_context_fn_entry(context);
AstNode *fn_proto_node = fn_entry->proto_node;
assert(fn_proto_node->type == NodeTypeFnProto);
AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
- assert(return_type_node->type == NodeTypeType);
- return return_type_node->data.type.entry;
+ return unwrapped_node_type(return_type_node);
}
static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, TypeTableEntry *other_type) {
@@ -1553,6 +1458,114 @@ static TypeTableEntry *analyze_enum_value_expr(CodeGen *g, ImportTableEntry *imp
return enum_type;
}
+static TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name, int *index) {
+ assert(type_entry->id == TypeTableEntryIdStruct);
+ for (int i = 0; i < type_entry->data.structure.field_count; i += 1) {
+ TypeStructField *field = &type_entry->data.structure.fields[i];
+ if (buf_eql_buf(field->name, name)) {
+ *index = i;
+ return field;
+ }
+ }
+ return nullptr;
+}
+
+static TypeTableEntry *analyze_container_init_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+ AstNode *node)
+{
+ assert(node->type == NodeTypeContainerInitExpr);
+
+ AstNodeContainerInitExpr *container_init_expr = &node->data.container_init_expr;
+
+ ContainerInitKind kind = container_init_expr->kind;
+
+ TypeTableEntry *container_type = analyze_type_expr(g, import, context, container_init_expr->type);
+
+ if (container_type->id == TypeTableEntryIdInvalid) {
+ return container_type;
+ } else if (container_type->id == TypeTableEntryIdStruct) {
+ switch (kind) {
+ case ContainerInitKindStruct:
+ {
+ StructValExprCodeGen *codegen = &container_init_expr->resolved_struct_val_expr;
+ codegen->type_entry = container_type;
+ codegen->source_node = node;
+ context->struct_val_expr_alloca_list.append(codegen);
+
+
+ int expr_field_count = container_init_expr->entries.length;
+ int actual_field_count = container_type->data.structure.field_count;
+
+ int *field_use_counts = allocate<int>(actual_field_count);
+ for (int i = 0; i < expr_field_count; i += 1) {
+ AstNode *val_field_node = container_init_expr->entries.at(i);
+ assert(val_field_node->type == NodeTypeStructValueField);
+
+ int field_index;
+ TypeStructField *type_field = find_struct_type_field(container_type,
+ &val_field_node->data.struct_val_field.name, &field_index);
+
+ if (!type_field) {
+ add_node_error(g, val_field_node,
+ buf_sprintf("no member named '%s' in '%s'",
+ buf_ptr(&val_field_node->data.struct_val_field.name), buf_ptr(&container_type->name)));
+ continue;
+ }
+
+ field_use_counts[field_index] += 1;
+ if (field_use_counts[field_index] > 1) {
+ add_node_error(g, val_field_node, buf_sprintf("duplicate field"));
+ continue;
+ }
+
+ val_field_node->data.struct_val_field.type_struct_field = type_field;
+
+ analyze_expression(g, import, context, type_field->type_entry,
+ val_field_node->data.struct_val_field.expr);
+ }
+
+ for (int i = 0; i < actual_field_count; i += 1) {
+ if (field_use_counts[i] == 0) {
+ add_node_error(g, node,
+ buf_sprintf("missing field: '%s'", buf_ptr(container_type->data.structure.fields[i].name)));
+ }
+ }
+ break;
+ }
+ case ContainerInitKindArray:
+ add_node_error(g, node,
+ buf_sprintf("struct '%s' does not support array initialization syntax",
+ buf_ptr(&container_type->name)));
+ break;
+ }
+ return container_type;
+ } else if (container_type->id == TypeTableEntryIdArray) {
+ zig_panic("TODO array container init");
+ return container_type;
+ } else if (container_type->id == TypeTableEntryIdEnum) {
+ zig_panic("TODO enum container init");
+ return container_type;
+ } else if (container_type->id == TypeTableEntryIdVoid) {
+ if (container_init_expr->entries.length != 0) {
+ add_node_error(g, node, buf_sprintf("void expression expects no arguments"));
+ return g->builtin_types.entry_invalid;
+ } else {
+ return container_type;
+ }
+ } else if (container_type->id == TypeTableEntryIdUnreachable) {
+ if (container_init_expr->entries.length != 0) {
+ add_node_error(g, node, buf_sprintf("unreachable expression expects no arguments"));
+ return g->builtin_types.entry_invalid;
+ } else {
+ return container_type;
+ }
+ } else {
+ add_node_error(g, node,
+ buf_sprintf("type '%s' does not support initialization syntax", buf_ptr(&container_type->name)));
+ return g->builtin_types.entry_invalid;
+ }
+}
+
static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node)
{
@@ -1585,7 +1598,7 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
return_type = g->builtin_types.entry_usize;
} else if (buf_eql_str(name, "ptr")) {
// TODO determine whether the pointer should be const
- return_type = get_pointer_to_type(g, struct_type->data.array.child_type, false, false);
+ return_type = get_pointer_to_type(g, struct_type->data.array.child_type, false);
} else {
add_node_error(g, node,
buf_sprintf("no member named '%s' in '%s'", buf_ptr(name),
@@ -1623,16 +1636,16 @@ static TypeTableEntry *analyze_slice_expr(CodeGen *g, ImportTableEntry *import,
return_type = g->builtin_types.entry_invalid;
} else if (array_type->id == TypeTableEntryIdArray) {
return_type = get_unknown_size_array_type(g, import, array_type->data.array.child_type,
- node->data.slice_expr.is_const, false);
+ node->data.slice_expr.is_const);
} else if (array_type->id == TypeTableEntryIdPointer) {
return_type = get_unknown_size_array_type(g, import, array_type->data.pointer.child_type,
- node->data.slice_expr.is_const, false);
+ node->data.slice_expr.is_const);
} else if (array_type->id == TypeTableEntryIdStruct &&
array_type->data.structure.is_unknown_size_array)
{
return_type = get_unknown_size_array_type(g, import,
array_type->data.structure.fields[0].type_entry->data.pointer.child_type,
- node->data.slice_expr.is_const, false);
+ node->data.slice_expr.is_const);
} else {
add_node_error(g, node,
buf_sprintf("slice of non-array type '%s'", buf_ptr(&array_type->name)));
@@ -1687,19 +1700,24 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
TypeTableEntry *expected_type, AstNode *node)
{
Buf *variable_name = &node->data.symbol_expr.symbol;
+
+ auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name);
+ if (primitive_table_entry) {
+ return get_meta_type(g, primitive_table_entry->value);
+ }
+
VariableTableEntry *var = find_variable(context, variable_name);
if (var) {
return var->type;
- } else {
- TypeTableEntry *container_type = find_container(context, variable_name);
- if (container_type) {
- return get_meta_type(g, container_type);
- } else {
- add_node_error(g, node,
- buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
- return g->builtin_types.entry_invalid;
- }
}
+
+ TypeTableEntry *container_type = find_container(context, variable_name);
+ if (container_type) {
+ return get_meta_type(g, container_type);
+ }
+
+ add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
+ return g->builtin_types.entry_invalid;
}
static TypeTableEntry *analyze_variable_name(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@@ -1768,7 +1786,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
{
assert(node->type == NodeTypeCastExpr);
- TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type, import, context, false);
+ TypeTableEntry *wanted_type = analyze_type_expr(g, import, context, node->data.cast_expr.type);
TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr);
if (wanted_type->id == TypeTableEntryIdInvalid ||
@@ -1833,23 +1851,22 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc
TypeTableEntry *expected_rhs_type = nullptr;
if (lhs_node->type == NodeTypeSymbol) {
Buf *name = &lhs_node->data.symbol_expr.symbol;
- VariableTableEntry *var = find_variable(block_context, name);
- if (var) {
- if (purpose == LValPurposeAssign && var->is_const) {
- add_node_error(g, lhs_node,
- buf_sprintf("cannot assign to constant"));
- expected_rhs_type = g->builtin_types.entry_invalid;
- } else if (purpose == LValPurposeAddressOf && var->is_const && !is_ptr_const) {
+ if (purpose == LValPurposeAddressOf) {
+ expected_rhs_type = analyze_symbol_expr(g, import, block_context, nullptr, lhs_node);
+ } else {
+ VariableTableEntry *var = find_variable(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;
+ }
+ } else {
add_node_error(g, lhs_node,
- buf_sprintf("must use &const to get address of constant"));
+ buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name)));
expected_rhs_type = g->builtin_types.entry_invalid;
- } else {
- expected_rhs_type = var->type;
}
- } else {
- add_node_error(g, lhs_node,
- buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name)));
- expected_rhs_type = g->builtin_types.entry_invalid;
}
} else if (lhs_node->type == NodeTypeArrayAccessExpr) {
expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node);
@@ -1873,13 +1890,19 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc
}
} else {
if (purpose == LValPurposeAssign) {
- add_node_error(g, lhs_node,
- buf_sprintf("invalid assignment target"));
+ add_node_error(g, lhs_node, buf_sprintf("invalid assignment target"));
+ expected_rhs_type = g->builtin_types.entry_invalid;
} else if (purpose == LValPurposeAddressOf) {
- add_node_error(g, lhs_node,
- buf_sprintf("invalid addressof target"));
+ TypeTableEntry *type_entry = analyze_expression(g, import, block_context, nullptr, lhs_node);
+ if (type_entry->id == TypeTableEntryIdInvalid) {
+ expected_rhs_type = g->builtin_types.entry_invalid;
+ } else if (type_entry->id == TypeTableEntryIdMetaType) {
+ expected_rhs_type = type_entry;
+ } else {
+ add_node_error(g, lhs_node, buf_sprintf("invalid addressof target"));
+ expected_rhs_type = g->builtin_types.entry_invalid;
+ }
}
- expected_rhs_type = g->builtin_types.entry_invalid;
}
assert(expected_rhs_type);
return expected_rhs_type;
@@ -1988,7 +2011,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
{
TypeTableEntry *explicit_type = nullptr;
if (variable_declaration->type != nullptr) {
- explicit_type = resolve_type(g, variable_declaration->type, import, context, false);
+ explicit_type = analyze_type_expr(g, import, context, variable_declaration->type);
if (explicit_type->id == TypeTableEntryIdUnreachable) {
add_node_error(g, variable_declaration->type,
buf_sprintf("variable of type 'unreachable' not allowed"));
@@ -2109,78 +2132,46 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry
}
}
-static TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name, int *index) {
- assert(type_entry->id == TypeTableEntryIdStruct);
- for (int i = 0; i < type_entry->data.structure.field_count; i += 1) {
- TypeStructField *field = &type_entry->data.structure.fields[i];
- if (buf_eql_buf(field->name, name)) {
- *index = i;
- return field;
- }
- }
- return nullptr;
-}
-
-static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
- assert(node->type == NodeTypeStructValueExpr);
-
- AstNodeStructValueExpr *struct_val_expr = &node->data.struct_val_expr;
+ AstNode *size_node = node->data.array_type.size;
- TypeTableEntry *type_entry = resolve_type(g, struct_val_expr->type, import, context, false);
+ TypeTableEntry *child_type = analyze_type_expr(g, import, context, node->data.array_type.child_type);
- if (type_entry->id == TypeTableEntryIdInvalid) {
+ if (child_type->id == TypeTableEntryIdUnreachable) {
+ add_node_error(g, node, buf_create_from_str("array of unreachable not allowed"));
return g->builtin_types.entry_invalid;
- } else if (type_entry->id != TypeTableEntryIdStruct) {
- add_node_error(g, node,
- buf_sprintf("type '%s' is not a struct", buf_ptr(&type_entry->name)));
+ } else if (child_type->id == TypeTableEntryIdInvalid) {
return g->builtin_types.entry_invalid;
}
- node->data.struct_val_expr.codegen.type_entry = type_entry;
- node->data.struct_val_expr.codegen.source_node = node;
- context->struct_val_expr_alloca_list.append(&node->data.struct_val_expr.codegen);
-
- int expr_field_count = struct_val_expr->fields.length;
- int actual_field_count = type_entry->data.structure.field_count;
-
- int *field_use_counts = allocate<int>(actual_field_count);
- for (int i = 0; i < expr_field_count; i += 1) {
- AstNode *val_field_node = struct_val_expr->fields.at(i);
- assert(val_field_node->type == NodeTypeStructValueField);
-
- int field_index;
- TypeStructField *type_field = find_struct_type_field(type_entry,
- &val_field_node->data.struct_val_field.name, &field_index);
-
- if (!type_field) {
- add_node_error(g, val_field_node,
- buf_sprintf("no member named '%s' in '%s'",
- buf_ptr(&val_field_node->data.struct_val_field.name), buf_ptr(&type_entry->name)));
- continue;
- }
-
- field_use_counts[field_index] += 1;
- if (field_use_counts[field_index] > 1) {
- add_node_error(g, val_field_node, buf_sprintf("duplicate field"));
- continue;
+ if (size_node) {
+ TypeTableEntry *size_type = analyze_expression(g, import, context,
+ g->builtin_types.entry_usize, size_node);
+ if (size_type->id == TypeTableEntryIdInvalid) {
+ return g->builtin_types.entry_invalid;
}
- val_field_node->data.struct_val_field.type_struct_field = type_field;
-
- analyze_expression(g, import, context, type_field->type_entry,
- val_field_node->data.struct_val_field.expr);
- }
+ AstNodeNumberLiteral number_literal;
+ TypeTableEntry *resolved_type = eval_const_expr(g, context, size_node, &number_literal);
- for (int i = 0; i < actual_field_count; i += 1) {
- if (field_use_counts[i] == 0) {
- add_node_error(g, node,
- buf_sprintf("missing field: '%s'", buf_ptr(type_entry->data.structure.fields[i].name)));
+ if (resolved_type->id == TypeTableEntryIdInt) {
+ if (resolved_type->data.integral.is_signed) {
+ add_node_error(g, size_node,
+ buf_create_from_str("array size must be unsigned integer"));
+ return g->builtin_types.entry_invalid;
+ } else {
+ return get_meta_type(g, get_array_type(g, import, child_type, number_literal.data.x_uint));
+ }
+ } else {
+ add_node_error(g, size_node,
+ buf_create_from_str("unable to resolve constant expression"));
+ return g->builtin_types.entry_invalid;
}
+ } else {
+ return get_meta_type(g, get_unknown_size_array_type(g, import, child_type, node->data.array_type.is_const));
}
-
- return type_entry;
}
static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
@@ -2293,9 +2284,14 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import,
node->data.if_var_expr.then_block, node->data.if_var_expr.else_node, node);
}
-static TypeTableEntry *analyze_min_max_value(CodeGen *g, AstNode *node, TypeTableEntry *type_entry,
- const char *err_format)
+static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+ AstNode *node, const char *err_format)
{
+ assert(node->type == NodeTypeFnCallExpr);
+ assert(node->data.fn_call_expr.params.length == 1);
+
+ AstNode *type_node = node->data.fn_call_expr.params.at(0);
+ TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
if (type_entry->id == TypeTableEntryIdInt ||
type_entry->id == TypeTableEntryIdFloat ||
type_entry->id == TypeTableEntryIdBool ||
@@ -2309,54 +2305,6 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, AstNode *node, TypeTabl
}
}
-static TypeTableEntry *analyze_compiler_fn_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
- TypeTableEntry *expected_type, AstNode *node)
-{
- assert(node->type == NodeTypeCompilerFnType);
-
- Buf *name = &node->data.compiler_fn_type.name;
- TypeTableEntry *type_entry = resolve_type(g, node->data.compiler_fn_type.type, import, context, false);
-
- if (buf_eql_str(name, "sizeof")) {
- if (type_entry->id == TypeTableEntryIdInvalid) {
- return type_entry;
- } else if (type_entry->id == TypeTableEntryIdUnreachable) {
- add_node_error(g, node,
- buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));
- return g->builtin_types.entry_invalid;
- } else {
- uint64_t size_in_bytes = type_entry->size_in_bits / 8;
-
- TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, size_in_bytes);
- TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type);
- return resolved_type ? resolved_type : num_lit_type;
- }
- } else if (buf_eql_str(name, "min_value")) {
- return analyze_min_max_value(g, node, type_entry, "no min value available for type '%s'");
- } else if (buf_eql_str(name, "max_value")) {
- return analyze_min_max_value(g, node, type_entry, "no max value available for type '%s'");
- } else if (buf_eql_str(name, "value_count")) {
- if (type_entry->id == TypeTableEntryIdInvalid) {
- return type_entry;
- } else if (type_entry->id == TypeTableEntryIdEnum) {
- uint64_t value_count = type_entry->data.enumeration.field_count;
-
- TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, value_count);
- TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type);
- return resolved_type ? resolved_type : num_lit_type;
-
- } else {
- add_node_error(g, node,
- buf_sprintf("no value count available for type '%s'", buf_ptr(&type_entry->name)));
- return g->builtin_types.entry_invalid;
- }
- } else {
- add_node_error(g, node,
- buf_sprintf("invalid compiler function: '%s'", buf_ptr(name)));
- return g->builtin_types.entry_invalid;
- }
-}
-
static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
@@ -2445,6 +2393,62 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
return builtin_fn->return_type;
}
+ case BuiltinFnIdSizeof:
+ {
+ AstNode *type_node = node->data.fn_call_expr.params.at(0);
+ TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
+ if (type_entry->id == TypeTableEntryIdInvalid) {
+ return g->builtin_types.entry_invalid;
+ } else if (type_entry->id == TypeTableEntryIdUnreachable) {
+ add_node_error(g, first_executing_node(type_node),
+ buf_sprintf("no size available for type '%s'", buf_ptr(&type_entry->name)));
+ return g->builtin_types.entry_invalid;
+ } else {
+ uint64_t size_in_bytes = type_entry->size_in_bits / 8;
+
+ TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, size_in_bytes);
+ TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type);
+ return resolved_type ? resolved_type : num_lit_type;
+ }
+ }
+ case BuiltinFnIdMaxValue:
+ return analyze_min_max_value(g, import, context, node, "no max value available for type '%s'");
+ case BuiltinFnIdMinValue:
+ return analyze_min_max_value(g, import, context, node, "no min value available for type '%s'");
+ case BuiltinFnIdValueCount:
+ {
+ AstNode *type_node = node->data.fn_call_expr.params.at(0);
+ TypeTableEntry *type_entry = analyze_type_expr(g, import, context, type_node);
+
+ if (type_entry->id == TypeTableEntryIdInvalid) {
+ return type_entry;
+ } else if (type_entry->id == TypeTableEntryIdEnum) {
+ uint64_t value_count = type_entry->data.enumeration.field_count;
+
+ TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, value_count);
+ TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type);
+ return resolved_type ? resolved_type : num_lit_type;
+
+ } else {
+ add_node_error(g, node,
+ buf_sprintf("no value count available for type '%s'", buf_ptr(&type_entry->name)));
+ return g->builtin_types.entry_invalid;
+ }
+ }
+ case BuiltinFnIdTypeof:
+ {
+ AstNode *expr_node = node->data.fn_call_expr.params.at(0);
+ TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node);
+
+ if (type_entry->id == TypeTableEntryIdInvalid) {
+ return g->builtin_types.entry_invalid;
+ } else if (type_entry->id == TypeTableEntryIdMetaType) {
+ add_node_error(g, node, buf_sprintf("expected expression, got type"));
+ } else {
+ return get_meta_type(g, type_entry);
+ }
+ }
+
}
zig_unreachable();
} else {
@@ -2560,15 +2564,127 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
AstNode *param_decl_node = fn_proto->params.at(fn_proto_i);
assert(param_decl_node->type == NodeTypeParamDecl);
AstNode *param_type_node = param_decl_node->data.param_decl.type;
- assert(param_type_node->type == NodeTypeType);
- if (param_type_node->data.type.entry) {
- expected_param_type = param_type_node->data.type.entry;
+ TypeTableEntry *param_type_entry = get_resolved_expr(param_type_node)->type_entry;
+ if (param_type_entry) {
+ expected_param_type = unwrapped_node_type(param_type_node);
}
}
analyze_expression(g, import, context, expected_param_type, child);
}
- return fn_proto->return_type->data.type.entry;
+ return unwrapped_node_type(fn_proto->return_type);
+ }
+}
+
+static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
+ TypeTableEntry *expected_type, AstNode *node)
+{
+ switch (node->data.prefix_op_expr.prefix_op) {
+ case PrefixOpInvalid:
+ zig_unreachable();
+ case PrefixOpBoolNot:
+ analyze_expression(g, import, context, g->builtin_types.entry_bool,
+ node->data.prefix_op_expr.primary_expr);
+ return g->builtin_types.entry_bool;
+ case PrefixOpBinNot:
+ {
+ AstNode *operand_node = node->data.prefix_op_expr.primary_expr;
+ TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type,
+ operand_node);
+ if (expr_type->id == TypeTableEntryIdInvalid) {
+ return expr_type;
+ } else if (expr_type->id == TypeTableEntryIdInt ||
+ (expr_type->id == TypeTableEntryIdNumberLiteral &&
+ !is_num_lit_float(expr_type->data.num_lit.kind)))
+ {
+ return expr_type;
+ } else {
+ add_node_error(g, operand_node, buf_sprintf("invalid binary not type: '%s'",
+ buf_ptr(&expr_type->name)));
+ return g->builtin_types.entry_invalid;
+ }
+ }
+ case PrefixOpNegation:
+ {
+ AstNode *operand_node = node->data.prefix_op_expr.primary_expr;
+ TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type,
+ operand_node);
+ if (expr_type->id == TypeTableEntryIdInvalid) {
+ return expr_type;
+ } else if (expr_type->id == TypeTableEntryIdInt &&
+ expr_type->data.integral.is_signed)
+ {
+ return expr_type;
+ } else if (expr_type->id == TypeTableEntryIdFloat) {
+ return expr_type;
+ } else if (expr_type->id == TypeTableEntryIdNumberLiteral) {
+ return expr_type;
+ } else {
+ add_node_error(g, operand_node, buf_sprintf("invalid negation type: '%s'",
+ buf_ptr(&expr_type->name)));
+ return g->builtin_types.entry_invalid;
+ }
+ }
+ case PrefixOpAddressOf:
+ case PrefixOpConstAddressOf:
+ {
+ bool is_const = (node->data.prefix_op_expr.prefix_op == PrefixOpConstAddressOf);
+
+ TypeTableEntry *child_type = analyze_lvalue(g, import, context,
+ node->data.prefix_op_expr.primary_expr, LValPurposeAddressOf, is_const);
+
+ if (child_type->id == TypeTableEntryIdInvalid) {
+ return g->builtin_types.entry_invalid;
+ } else if (child_type->id == TypeTableEntryIdMetaType) {
+ TypeTableEntry *meta_child_type = child_type->data.meta_type.child_type;
+ if (meta_child_type->id == TypeTableEntryIdUnreachable) {
+ add_node_error(g, node,
+ buf_create_from_str("pointer to unreachable not allowed"));
+ } else {
+ return get_meta_type(g, get_pointer_to_type(g, meta_child_type, is_const));
+ }
+ } else {
+ return get_pointer_to_type(g, child_type, is_const);
+ }
+ }
+ case PrefixOpDereference:
+ {
+ TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr,
+ node->data.prefix_op_expr.primary_expr);
+ 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, node->data.prefix_op_expr.primary_expr,
+ buf_sprintf("indirection requires pointer operand ('%s' invalid)",
+ buf_ptr(&type_entry->name)));
+ return g->builtin_types.entry_invalid;
+ }
+ }
+ case PrefixOpMaybe:
+ {
+ TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr,
+ node->data.prefix_op_expr.primary_expr);
+
+ if (type_entry->id == TypeTableEntryIdInvalid) {
+ return type_entry;
+ } else if (type_entry->id == TypeTableEntryIdMetaType) {
+ TypeTableEntry *child_type = type_entry->data.meta_type.child_type;
+ if (child_type->id == TypeTableEntryIdUnreachable) {
+ add_node_error(g, node, buf_create_from_str("maybe unreachable type not allowed"));
+ return g->builtin_types.entry_invalid;
+ } else {
+ return get_meta_type(g, get_maybe_type(g, child_type));
+ }
+ } else if (type_entry->id == TypeTableEntryIdUnreachable) {
+ add_node_error(g, node->data.prefix_op_expr.primary_expr,
+ buf_sprintf("unable to wrap unreachable in maybe type"));
+ return g->builtin_types.entry_invalid;
+ } else {
+ return get_maybe_type(g, type_entry);
+ }
+ }
}
}
@@ -2593,9 +2709,10 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
continue;
}
if (return_type->id == TypeTableEntryIdUnreachable) {
- if (child->type == NodeTypeVoid) {
+ if (is_node_void_expr(child)) {
// {unreachable;void;void} is allowed.
// ignore void statements once we enter unreachable land.
+ analyze_expression(g, import, context, g->builtin_types.entry_void, child);
continue;
}
add_node_error(g, first_executing_node(child), buf_sprintf("unreachable code"));
@@ -2604,6 +2721,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
bool is_last = (i == node->data.block.statements.length - 1);
TypeTableEntry *passed_expected_type = is_last ? expected_type : nullptr;
return_type = analyze_expression(g, import, child_context, passed_expected_type, child);
+ if (!is_last && return_type->id == TypeTableEntryIdMetaType) {
+ add_node_error(g, child, buf_sprintf("expected expression, found type"));
+ }
}
break;
}
@@ -2664,7 +2784,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
if (asm_output->return_type) {
node->data.asm_expr.return_count += 1;
- return_type = resolve_type(g, asm_output->return_type, import, context, false);
+ return_type = analyze_type_expr(g, import, context, asm_output->return_type);
if (node->data.asm_expr.return_count > 1) {
add_node_error(g, node,
buf_sprintf("inline assembly allows up to one output value"));
@@ -2699,6 +2819,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeFieldAccessExpr:
return_type = analyze_field_access_expr(g, import, context, node);
break;
+ case NodeTypeContainerInitExpr:
+ return_type = analyze_container_init_expr(g, import, context, node);
+ break;
case NodeTypeNumberLiteral:
return_type = analyze_number_literal_expr(g, import, context, expected_type, node);
break;
@@ -2713,14 +2836,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeCharLiteral:
return_type = g->builtin_types.entry_u8;
break;
- case NodeTypeUnreachable:
- return_type = g->builtin_types.entry_unreachable;
- break;
-
- case NodeTypeVoid:
- return_type = g->builtin_types.entry_void;
- break;
-
case NodeTypeBoolLiteral:
return_type = g->builtin_types.entry_bool;
break;
@@ -2730,96 +2845,13 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
break;
case NodeTypeSymbol:
- {
- return_type = analyze_symbol_expr(g, import, context, expected_type, node);
- break;
- }
+ return_type = analyze_symbol_expr(g, import, context, expected_type, node);
+ break;
case NodeTypeCastExpr:
return_type = analyze_cast_expr(g, import, context, expected_type, node);
break;
case NodeTypePrefixOpExpr:
- switch (node->data.prefix_op_expr.prefix_op) {
- case PrefixOpInvalid:
- zig_unreachable();
- case PrefixOpBoolNot:
- analyze_expression(g, import, context, g->builtin_types.entry_bool,
- node->data.prefix_op_expr.primary_expr);
- return_type = g->builtin_types.entry_bool;
- break;
- case PrefixOpBinNot:
- {
- AstNode *operand_node = node->data.prefix_op_expr.primary_expr;
- TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type,
- operand_node);
- if (expr_type->id == TypeTableEntryIdInvalid) {
- return_type = expr_type;
- } else if (expr_type->id == TypeTableEntryIdInt ||
- (expr_type->id == TypeTableEntryIdNumberLiteral &&
- !is_num_lit_float(expr_type->data.num_lit.kind)))
- {
- return_type = expr_type;
- } else {
- add_node_error(g, operand_node, buf_sprintf("invalid binary not type: '%s'",
- buf_ptr(&expr_type->name)));
- return_type = g->builtin_types.entry_invalid;
- }
- break;
- }
- case PrefixOpNegation:
- {
- AstNode *operand_node = node->data.prefix_op_expr.primary_expr;
- TypeTableEntry *expr_type = analyze_expression(g, import, context, expected_type,
- operand_node);
- if (expr_type->id == TypeTableEntryIdInvalid) {
- return_type = expr_type;
- } else if (expr_type->id == TypeTableEntryIdInt &&
- expr_type->data.integral.is_signed)
- {
- return_type = expr_type;
- } else if (expr_type->id == TypeTableEntryIdFloat) {
- return_type = expr_type;
- } else if (expr_type->id == TypeTableEntryIdNumberLiteral) {
- return_type = expr_type;
- } else {
- add_node_error(g, operand_node, buf_sprintf("invalid negation type: '%s'",
- buf_ptr(&expr_type->name)));
- return_type = g->builtin_types.entry_invalid;
- }
- break;
- }
- case PrefixOpAddressOf:
- case PrefixOpConstAddressOf:
- {
- bool is_const = (node->data.prefix_op_expr.prefix_op == PrefixOpConstAddressOf);
-
- TypeTableEntry *child_type = analyze_lvalue(g, import, context,
- node->data.prefix_op_expr.primary_expr, LValPurposeAddressOf, is_const);
-
- if (child_type->id == TypeTableEntryIdInvalid) {
- return_type = g->builtin_types.entry_invalid;
- break;
- }
-
- return_type = get_pointer_to_type(g, child_type, is_const, false);
- break;
- }
- case PrefixOpDereference:
- {
- TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr,
- node->data.prefix_op_expr.primary_expr);
- if (type_entry->id == TypeTableEntryIdInvalid) {
- return_type = type_entry;
- } else if (type_entry->id == TypeTableEntryIdPointer) {
- return_type = type_entry->data.pointer.child_type;
- } else {
- add_node_error(g, node->data.prefix_op_expr.primary_expr,
- buf_sprintf("indirection requires pointer operand ('%s' invalid)",
- buf_ptr(&type_entry->name)));
- return_type = g->builtin_types.entry_invalid;
- }
- break;
- }
- }
+ return_type = analyze_prefix_op_expr(g, import, context, expected_type, node);
break;
case NodeTypeIfBoolExpr:
return_type = analyze_if_bool_expr(g, import, context, expected_type, node);
@@ -2830,17 +2862,13 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeWhileExpr:
return_type = analyze_while_expr(g, import, context, expected_type, node);
break;
- case NodeTypeStructValueExpr:
- return_type = analyze_struct_val_expr(g, import, context, expected_type, node);
- break;
- case NodeTypeCompilerFnType:
- return_type = analyze_compiler_fn_type(g, import, context, expected_type, node);
+ case NodeTypeArrayType:
+ return_type = analyze_array_type(g, import, context, expected_type, node);
break;
case NodeTypeDirective:
case NodeTypeFnDecl:
case NodeTypeFnProto:
case NodeTypeParamDecl:
- case NodeTypeType:
case NodeTypeRoot:
case NodeTypeRootExportDecl:
case NodeTypeExternBlock:
@@ -2850,7 +2878,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeStructDecl:
case NodeTypeStructField:
case NodeTypeStructValueField:
- case NodeTypeCompilerFnExpr:
zig_unreachable();
}
assert(return_type);
@@ -2885,8 +2912,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
// define local variables for parameters
AstNodeParamDecl *param_decl = ¶m_decl_node->data.param_decl;
- assert(param_decl->type->type == NodeTypeType);
- TypeTableEntry *type = param_decl->type->data.type.entry;
+ TypeTableEntry *type = unwrapped_node_type(param_decl->type);
if (is_exported && type->id == TypeTableEntryIdStruct) {
add_node_error(g, param_decl_node,
@@ -2918,7 +2944,7 @@ static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNo
}
}
- TypeTableEntry *expected_type = fn_proto->return_type->data.type.entry;
+ TypeTableEntry *expected_type = unwrapped_node_type(fn_proto->return_type);
TypeTableEntry *block_return_type = analyze_expression(g, import, context, expected_type, node->data.fn_def.body);
node->data.fn_def.implicit_return_type = block_return_type;
@@ -2963,7 +2989,6 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeDirective:
case NodeTypeParamDecl:
case NodeTypeFnProto:
- case NodeTypeType:
case NodeTypeFnDecl:
case NodeTypeReturnExpr:
case NodeTypeRoot:
@@ -2975,8 +3000,6 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeNumberLiteral:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
- case NodeTypeUnreachable:
- case NodeTypeVoid:
case NodeTypeBoolLiteral:
case NodeTypeNullLiteral:
case NodeTypeSymbol:
@@ -2992,177 +3015,150 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypeStructField:
- case NodeTypeStructValueExpr:
case NodeTypeStructValueField:
- case NodeTypeCompilerFnExpr:
- case NodeTypeCompilerFnType:
+ case NodeTypeContainerInitExpr:
+ case NodeTypeArrayType:
zig_unreachable();
}
}
-static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *expr_node,
+static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *node,
TopLevelDecl *decl_node)
{
- switch (expr_node->type) {
+ switch (node->type) {
case NodeTypeNumberLiteral:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
- case NodeTypeVoid:
case NodeTypeBoolLiteral:
case NodeTypeNullLiteral:
- case NodeTypeUnreachable:
case NodeTypeGoto:
case NodeTypeBreak:
case NodeTypeContinue:
// no dependencies on other top level declarations
break;
case NodeTypeSymbol:
- decl_node->deps.put(&expr_node->data.symbol_expr.symbol, expr_node);
- break;
+ {
+ Buf *name = &node->data.symbol_expr.symbol;
+ auto table_entry = g->primitive_type_table.maybe_get(name);
+ if (!table_entry) {
+ table_entry = import->block_context->type_table.maybe_get(name);
+ }
+ if (!table_entry) {
+ decl_node->deps.put(name, node);
+ }
+ break;
+ }
case NodeTypeBinOpExpr:
- collect_expr_decl_deps(g, import, expr_node->data.bin_op_expr.op1, decl_node);
- collect_expr_decl_deps(g, import, expr_node->data.bin_op_expr.op2, decl_node);
+ 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 NodeTypeReturnExpr:
- collect_expr_decl_deps(g, import, expr_node->data.return_expr.expr, decl_node);
+ collect_expr_decl_deps(g, import, node->data.return_expr.expr, decl_node);
break;
case NodeTypeCastExpr:
- collect_expr_decl_deps(g, import, expr_node->data.cast_expr.expr, decl_node);
- collect_type_decl_deps(g, import, expr_node->data.cast_expr.type, decl_node);
+ collect_expr_decl_deps(g, import, node->data.cast_expr.expr, decl_node);
+ collect_expr_decl_deps(g, import, node->data.cast_expr.type, decl_node);
break;
case NodeTypePrefixOpExpr:
- collect_expr_decl_deps(g, import, expr_node->data.prefix_op_expr.primary_expr, decl_node);
+ collect_expr_decl_deps(g, import, node->data.prefix_op_expr.primary_expr, decl_node);
break;
case NodeTypeFnCallExpr:
- collect_expr_decl_deps(g, import, expr_node->data.fn_call_expr.fn_ref_expr, decl_node);
- for (int i = 0; i < expr_node->data.fn_call_expr.params.length; i += 1) {
- AstNode *arg_node = expr_node->data.fn_call_expr.params.at(i);
+ 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, expr_node->data.array_access_expr.array_ref_expr, decl_node);
- collect_expr_decl_deps(g, import, expr_node->data.array_access_expr.subscript, decl_node);
+ 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, expr_node->data.slice_expr.array_ref_expr, decl_node);
- collect_expr_decl_deps(g, import, expr_node->data.slice_expr.start, decl_node);
- if (expr_node->data.slice_expr.end) {
- collect_expr_decl_deps(g, import, expr_node->data.slice_expr.end, decl_node);
+ 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, expr_node->data.field_access_expr.struct_expr, decl_node);
+ collect_expr_decl_deps(g, import, node->data.field_access_expr.struct_expr, decl_node);
break;
case NodeTypeIfBoolExpr:
- collect_expr_decl_deps(g, import, expr_node->data.if_bool_expr.condition, decl_node);
- collect_expr_decl_deps(g, import, expr_node->data.if_bool_expr.then_block, decl_node);
- if (expr_node->data.if_bool_expr.else_node) {
- collect_expr_decl_deps(g, import, expr_node->data.if_bool_expr.else_node, decl_node);
+ 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 (expr_node->data.if_var_expr.var_decl.type) {
- collect_type_decl_deps(g, import, expr_node->data.if_var_expr.var_decl.type, decl_node);
+ 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 (expr_node->data.if_var_expr.var_decl.expr) {
- collect_expr_decl_deps(g, import, expr_node->data.if_var_expr.var_decl.expr, 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, expr_node->data.if_var_expr.then_block, decl_node);
- if (expr_node->data.if_bool_expr.else_node) {
- collect_expr_decl_deps(g, import, expr_node->data.if_var_expr.else_node, 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, expr_node->data.while_expr.condition, decl_node);
- collect_expr_decl_deps(g, import, expr_node->data.while_expr.body, decl_node);
+ 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 NodeTypeBlock:
- for (int i = 0; i < expr_node->data.block.statements.length; i += 1) {
- AstNode *stmt = expr_node->data.block.statements.at(i);
+ 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 < expr_node->data.asm_expr.output_list.length; i += 1) {
- AsmOutput *asm_output = expr_node->data.asm_expr.output_list.at(i);
+ 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_type_decl_deps(g, import, asm_output->return_type, decl_node);
+ collect_expr_decl_deps(g, import, asm_output->return_type, decl_node);
} else {
- decl_node->deps.put(&asm_output->variable_name, expr_node);
+ decl_node->deps.put(&asm_output->variable_name, node);
}
}
- for (int i = 0; i < expr_node->data.asm_expr.input_list.length; i += 1) {
- AsmInput *asm_input = expr_node->data.asm_expr.input_list.at(i);
+ 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 NodeTypeStructValueExpr:
- collect_type_decl_deps(g, import, expr_node->data.struct_val_expr.type, decl_node);
- for (int i = 0; i < expr_node->data.struct_val_expr.fields.length; i += 1) {
- AstNode *field_node = expr_node->data.struct_val_expr.fields.at(i);
- assert(field_node->type == NodeTypeStructValueField);
- collect_expr_decl_deps(g, import, field_node->data.struct_val_field.expr, decl_node);
+ 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 NodeTypeCompilerFnExpr:
- collect_expr_decl_deps(g, import, expr_node->data.compiler_fn_expr.expr, decl_node);
+ case NodeTypeStructValueField:
+ collect_expr_decl_deps(g, import, node->data.struct_val_field.expr, decl_node);
break;
- case NodeTypeCompilerFnType:
- collect_type_decl_deps(g, import, expr_node->data.compiler_fn_type.type, decl_node);
+ 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 NodeTypeRoot:
- case NodeTypeRootExportDecl:
+ case NodeTypeVariableDeclaration:
case NodeTypeFnProto:
+ case NodeTypeExternBlock:
+ case NodeTypeRootExportDecl:
case NodeTypeFnDef:
+ case NodeTypeRoot:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
- case NodeTypeType:
- case NodeTypeExternBlock:
case NodeTypeDirective:
- case NodeTypeVariableDeclaration:
case NodeTypeUse:
case NodeTypeLabel:
case NodeTypeStructDecl:
case NodeTypeStructField:
- case NodeTypeStructValueField:
zig_unreachable();
}
}
-static void collect_type_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode *type_node, TopLevelDecl *decl_node) {
- assert(type_node->type == NodeTypeType);
- switch (type_node->data.type.type) {
- case AstNodeTypeTypePrimitive:
- {
- Buf *name = &type_node->data.type.primitive_name;
- auto table_entry = g->primitive_type_table.maybe_get(name);
- if (!table_entry) {
- table_entry = import->block_context->type_table.maybe_get(name);
- }
- if (!table_entry) {
- decl_node->deps.put(name, type_node);
- }
- break;
- }
- case AstNodeTypeTypePointer:
- collect_type_decl_deps(g, import, type_node->data.type.child_type, decl_node);
- break;
- case AstNodeTypeTypeArray:
- collect_type_decl_deps(g, import, type_node->data.type.child_type, decl_node);
- if (type_node->data.type.array_size) {
- collect_expr_decl_deps(g, import, type_node->data.type.array_size, decl_node);
- }
- break;
- case AstNodeTypeTypeMaybe:
- collect_type_decl_deps(g, import, type_node->data.type.child_type, decl_node);
- break;
- case AstNodeTypeTypeCompilerExpr:
- collect_expr_decl_deps(g, import, type_node->data.type.compiler_expr, decl_node);
- break;
- }
-}
-
static TypeTableEntryId container_to_type(ContainerKind kind) {
switch (kind) {
case ContainerKindStruct:
@@ -3231,7 +3227,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
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_type_decl_deps(g, import, type_node, decl_node);
+ collect_expr_decl_deps(g, import, type_node, decl_node);
}
decl_node->name = name;
decl_node->import = import;
@@ -3271,7 +3267,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
TopLevelDecl *decl_node = &node->data.variable_declaration.top_level_decl;
decl_node->deps.init(1);
if (node->data.variable_declaration.type) {
- collect_type_decl_deps(g, import, node->data.variable_declaration.type, decl_node);
+ 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);
@@ -3294,8 +3290,9 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
AstNode *param_node = node->data.fn_proto.params.at(i);
assert(param_node->type == NodeTypeParamDecl);
- collect_type_decl_deps(g, import, param_node->data.param_decl.type, decl_node);
+ collect_expr_decl_deps(g, import, param_node->data.param_decl.type, decl_node);
}
+ collect_expr_decl_deps(g, import, node->data.fn_proto.return_type, decl_node);
Buf *name = &node->data.fn_proto.name;
decl_node->name = name;
@@ -3315,7 +3312,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
break;
case NodeTypeDirective:
case NodeTypeParamDecl:
- case NodeTypeType:
case NodeTypeFnDecl:
case NodeTypeReturnExpr:
case NodeTypeRoot:
@@ -3327,8 +3323,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
case NodeTypeNumberLiteral:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
- case NodeTypeUnreachable:
- case NodeTypeVoid:
case NodeTypeBoolLiteral:
case NodeTypeNullLiteral:
case NodeTypeSymbol:
@@ -3344,10 +3338,9 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
case NodeTypeAsmExpr:
case NodeTypeFieldAccessExpr:
case NodeTypeStructField:
- case NodeTypeStructValueExpr:
+ case NodeTypeContainerInitExpr:
case NodeTypeStructValueField:
- case NodeTypeCompilerFnExpr:
- case NodeTypeCompilerFnType:
+ case NodeTypeArrayType:
zig_unreachable();
}
}
@@ -3526,18 +3519,14 @@ Expr *get_resolved_expr(AstNode *node) {
return &node->data.while_expr.resolved_expr;
case NodeTypeAsmExpr:
return &node->data.asm_expr.resolved_expr;
- case NodeTypeStructValueExpr:
- return &node->data.struct_val_expr.resolved_expr;
+ case NodeTypeContainerInitExpr:
+ return &node->data.container_init_expr.resolved_expr;
case NodeTypeNumberLiteral:
return &node->data.number_literal.resolved_expr;
case NodeTypeStringLiteral:
return &node->data.string_literal.resolved_expr;
case NodeTypeBlock:
return &node->data.block.resolved_expr;
- case NodeTypeVoid:
- return &node->data.void_expr.resolved_expr;
- case NodeTypeUnreachable:
- return &node->data.unreachable_expr.resolved_expr;
case NodeTypeSymbol:
return &node->data.symbol_expr.resolved_expr;
case NodeTypeVariableDeclaration:
@@ -3554,19 +3543,16 @@ Expr *get_resolved_expr(AstNode *node) {
return &node->data.break_expr.resolved_expr;
case NodeTypeContinue:
return &node->data.continue_expr.resolved_expr;
- case NodeTypeCompilerFnExpr:
- return &node->data.compiler_fn_expr.resolved_expr;
- case NodeTypeCompilerFnType:
- return &node->data.compiler_fn_type.resolved_expr;
case NodeTypeLabel:
return &node->data.label.resolved_expr;
+ case NodeTypeArrayType:
+ return &node->data.array_type.resolved_expr;
case NodeTypeRoot:
case NodeTypeRootExportDecl:
case NodeTypeFnProto:
case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
- case NodeTypeType:
case NodeTypeExternBlock:
case NodeTypeDirective:
case NodeTypeUse:
@@ -3581,13 +3567,12 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
switch (node->type) {
case NodeTypeNumberLiteral:
return &node->data.number_literal.codegen;
- case NodeTypeCompilerFnType:
- return &node->data.compiler_fn_type.resolved_num_lit;
+ case NodeTypeFnCallExpr:
+ return &node->data.fn_call_expr.resolved_num_lit;
case NodeTypeReturnExpr:
case NodeTypeBinOpExpr:
case NodeTypeCastExpr:
case NodeTypePrefixOpExpr:
- case NodeTypeFnCallExpr:
case NodeTypeArrayAccessExpr:
case NodeTypeSliceExpr:
case NodeTypeFieldAccessExpr:
@@ -3595,24 +3580,21 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
case NodeTypeIfVarExpr:
case NodeTypeWhileExpr:
case NodeTypeAsmExpr:
- case NodeTypeStructValueExpr:
+ case NodeTypeContainerInitExpr:
case NodeTypeRoot:
case NodeTypeRootExportDecl:
case NodeTypeFnProto:
case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
- case NodeTypeType:
case NodeTypeBlock:
case NodeTypeExternBlock:
case NodeTypeDirective:
case NodeTypeVariableDeclaration:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
- case NodeTypeUnreachable:
case NodeTypeSymbol:
case NodeTypeUse:
- case NodeTypeVoid:
case NodeTypeBoolLiteral:
case NodeTypeNullLiteral:
case NodeTypeLabel:
@@ -3622,7 +3604,7 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
case NodeTypeStructDecl:
case NodeTypeStructField:
case NodeTypeStructValueField:
- case NodeTypeCompilerFnExpr:
+ case NodeTypeArrayType:
zig_unreachable();
}
}
@@ -3648,22 +3630,19 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
case NodeTypeIfVarExpr:
case NodeTypeWhileExpr:
case NodeTypeAsmExpr:
- case NodeTypeStructValueExpr:
+ case NodeTypeContainerInitExpr:
case NodeTypeRoot:
case NodeTypeRootExportDecl:
case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
- case NodeTypeType:
case NodeTypeBlock:
case NodeTypeExternBlock:
case NodeTypeDirective:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
- case NodeTypeUnreachable:
case NodeTypeSymbol:
case NodeTypeUse:
- case NodeTypeVoid:
case NodeTypeBoolLiteral:
case NodeTypeNullLiteral:
case NodeTypeLabel:
@@ -3672,8 +3651,23 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
case NodeTypeContinue:
case NodeTypeStructField:
case NodeTypeStructValueField:
- case NodeTypeCompilerFnExpr:
- case NodeTypeCompilerFnType:
+ case NodeTypeArrayType:
zig_unreachable();
}
}
+
+bool is_node_void_expr(AstNode *node) {
+ if (node->type == NodeTypeContainerInitExpr &&
+ node->data.container_init_expr.kind == ContainerInitKindArray)
+ {
+ AstNode *type_node = node->data.container_init_expr.type;
+ if (type_node->type == NodeTypeSymbol &&
+ buf_eql_str(&type_node->data.symbol_expr.symbol, "void"))
+ {
+ return true;
+ }
+ }
+
+ return false;
+}
+
src/analyze.hpp
@@ -13,12 +13,13 @@
void semantic_analyze(CodeGen *g);
void add_node_error(CodeGen *g, AstNode *node, Buf *msg);
TypeTableEntry *new_type_table_entry(TypeTableEntryId id);
-TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const, bool is_noalias);
+TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const);
VariableTableEntry *find_variable(BlockContext *context, Buf *name);
TypeTableEntry *find_container(BlockContext *context, Buf *name);
BlockContext *new_block_context(AstNode *node, BlockContext *parent);
Expr *get_resolved_expr(AstNode *node);
NumLitCodeGen *get_resolved_num_lit(AstNode *node);
TopLevelDecl *get_resolved_top_level_decl(AstNode *node);
+bool is_node_void_expr(AstNode *node);
#endif
src/codegen.cpp
@@ -72,35 +72,35 @@ static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType b
LLVMValueRef target_ref, LLVMValueRef value,
TypeTableEntry *op1_type, TypeTableEntry *op2_type);
-
-static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {
- assert(type_node->type == NodeTypeType);
- return type_node->data.type.entry;
+static TypeTableEntry *get_type_for_type_node(AstNode *node) {
+ TypeTableEntry *meta_type_entry = get_resolved_expr(node)->type_entry;
+ assert(meta_type_entry->id == TypeTableEntryIdMetaType);
+ return meta_type_entry->data.meta_type.child_type;
}
static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) {
- TypeTableEntry *type_entry = get_type_for_type_node(g, type_node);
+ TypeTableEntry *type_entry = get_type_for_type_node(type_node);
if (type_entry->id == TypeTableEntryIdStruct || type_entry->id == TypeTableEntryIdArray) {
- return get_pointer_to_type(g, type_entry, true, true);
+ return get_pointer_to_type(g, type_entry, true);
} else {
return type_entry;
}
}
static LLVMZigDIType *to_llvm_debug_type(CodeGen *g, AstNode *type_node) {
- TypeTableEntry *type_entry = get_type_for_type_node(g, type_node);
+ TypeTableEntry *type_entry = get_type_for_type_node(type_node);
return type_entry->di_type;
}
static bool type_is_unreachable(CodeGen *g, AstNode *type_node) {
- return get_type_for_type_node(g, type_node)->id == TypeTableEntryIdUnreachable;
+ return get_type_for_type_node(type_node)->id == TypeTableEntryIdUnreachable;
}
static bool is_param_decl_type_void(CodeGen *g, AstNode *param_decl_node) {
assert(param_decl_node->type == NodeTypeParamDecl);
- return get_type_for_type_node(g, param_decl_node->data.param_decl.type)->id == TypeTableEntryIdVoid;
+ return get_type_for_type_node(param_decl_node->data.param_decl.type)->id == TypeTableEntryIdVoid;
}
static int count_non_void_params(CodeGen *g, ZigList<AstNode *> *params) {
@@ -146,6 +146,32 @@ static TypeTableEntry *get_expr_type(AstNode *node) {
return expr->type_entry;
}
+static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node,
+ NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node)
+{
+ TypeTableEntry *type_entry = codegen_num_lit->resolved_type;
+ assert(type_entry);
+
+ // override the expression type for number literals
+ get_resolved_expr(source_node)->type_entry = type_entry;
+
+ if (type_entry->id == TypeTableEntryIdInt) {
+ // here the union has int64_t and uint64_t and we purposefully read
+ // the uint64_t value in either case, because we want the twos
+ // complement representation
+
+ return LLVMConstInt(type_entry->type_ref,
+ num_lit_node->data.x_uint,
+ type_entry->data.integral.is_signed);
+ } else if (type_entry->id == TypeTableEntryIdFloat) {
+
+ return LLVMConstReal(type_entry->type_ref,
+ num_lit_node->data.x_float);
+ } else {
+ zig_panic("bad number literal type");
+ }
+}
+
static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeFnCallExpr);
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
@@ -154,6 +180,7 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
switch (builtin_fn->id) {
case BuiltinFnIdInvalid:
+ case BuiltinFnIdTypeof:
zig_unreachable();
case BuiltinFnIdArithmeticWithOverflow:
{
@@ -238,6 +265,74 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
LLVMBuildCall(g->builder, builtin_fn->fn_val, params, 5, "");
return nullptr;
}
+ case BuiltinFnIdSizeof:
+ {
+ assert(node->data.fn_call_expr.params.length == 1);
+ AstNode *type_node = node->data.fn_call_expr.params.at(0);
+ TypeTableEntry *type_entry = get_type_for_type_node(type_node);
+
+ NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
+ AstNodeNumberLiteral num_lit_node;
+ num_lit_node.kind = NumLitU64; // this field isn't even read
+ num_lit_node.overflow = false;
+ num_lit_node.data.x_uint = type_entry->size_in_bits / 8;
+ return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
+ }
+ case BuiltinFnIdMinValue:
+ {
+ assert(node->data.fn_call_expr.params.length == 1);
+ AstNode *type_node = node->data.fn_call_expr.params.at(0);
+ TypeTableEntry *type_entry = get_type_for_type_node(type_node);
+
+
+ if (type_entry->id == TypeTableEntryIdInt) {
+ if (type_entry->data.integral.is_signed) {
+ return LLVMConstInt(type_entry->type_ref, 1ULL << (type_entry->size_in_bits - 1), false);
+ } else {
+ return LLVMConstNull(type_entry->type_ref);
+ }
+ } else if (type_entry->id == TypeTableEntryIdFloat) {
+ zig_panic("TODO codegen min_value float");
+ } else {
+ zig_unreachable();
+ }
+ }
+ case BuiltinFnIdMaxValue:
+ {
+ assert(node->data.fn_call_expr.params.length == 1);
+ AstNode *type_node = node->data.fn_call_expr.params.at(0);
+ TypeTableEntry *type_entry = get_type_for_type_node(type_node);
+
+
+ if (type_entry->id == TypeTableEntryIdInt) {
+ if (type_entry->data.integral.is_signed) {
+ return LLVMConstInt(type_entry->type_ref, (1ULL << (type_entry->size_in_bits - 1)) - 1, false);
+ } else {
+ return LLVMConstAllOnes(type_entry->type_ref);
+ }
+ } else if (type_entry->id == TypeTableEntryIdFloat) {
+ zig_panic("TODO codegen max_value float");
+ } else {
+ zig_unreachable();
+ }
+ }
+ case BuiltinFnIdValueCount:
+ {
+ assert(node->data.fn_call_expr.params.length == 1);
+ AstNode *type_node = node->data.fn_call_expr.params.at(0);
+ TypeTableEntry *type_entry = get_type_for_type_node(type_node);
+
+ if (type_entry->id == TypeTableEntryIdEnum) {
+ NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
+ AstNodeNumberLiteral num_lit_node;
+ num_lit_node.kind = NumLitU64; // field ignored
+ num_lit_node.overflow = false;
+ num_lit_node.data.x_uint = type_entry->data.enumeration.field_count;
+ return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
+ } else {
+ zig_unreachable();
+ }
+ }
}
zig_unreachable();
}
@@ -692,6 +787,10 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
add_debug_source_node(g, node);
return LLVMBuildLoad(g->builder, expr, "");
}
+ case PrefixOpMaybe:
+ {
+ zig_panic("TODO codegen PrefixOpMaybe");
+ }
}
zig_unreachable();
}
@@ -1484,35 +1583,46 @@ static LLVMValueRef gen_null_literal(CodeGen *g, AstNode *node) {
return tmp_struct_ptr;
}
-static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) {
- assert(node->type == NodeTypeStructValueExpr);
+static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) {
+ assert(node->type == NodeTypeContainerInitExpr);
TypeTableEntry *type_entry = get_expr_type(node);
- assert(type_entry->id == TypeTableEntryIdStruct);
+ if (type_entry->id == TypeTableEntryIdStruct) {
+ assert(node->data.container_init_expr.kind == ContainerInitKindStruct);
- int field_count = type_entry->data.structure.field_count;
- assert(field_count == node->data.struct_val_expr.fields.length);
+ int field_count = type_entry->data.structure.field_count;
+ assert(field_count == node->data.container_init_expr.entries.length);
- StructValExprCodeGen *struct_val_expr_node = &node->data.struct_val_expr.codegen;
- LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr;
+ StructValExprCodeGen *struct_val_expr_node = &node->data.container_init_expr.resolved_struct_val_expr;
+ LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr;
- for (int i = 0; i < field_count; i += 1) {
- AstNode *field_node = node->data.struct_val_expr.fields.at(i);
- assert(field_node->type == NodeTypeStructValueField);
- TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field;
- if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) {
- continue;
+ for (int i = 0; i < field_count; i += 1) {
+ AstNode *field_node = node->data.container_init_expr.entries.at(i);
+ assert(field_node->type == NodeTypeStructValueField);
+ TypeStructField *type_struct_field = field_node->data.struct_val_field.type_struct_field;
+ if (type_struct_field->type_entry->id == TypeTableEntryIdVoid) {
+ continue;
+ }
+ assert(buf_eql_buf(type_struct_field->name, &field_node->data.struct_val_field.name));
+
+ add_debug_source_node(g, field_node);
+ LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, "");
+ LLVMValueRef value = gen_expr(g, field_node->data.struct_val_field.expr);
+ LLVMBuildStore(g->builder, value, field_ptr);
}
- assert(buf_eql_buf(type_struct_field->name, &field_node->data.struct_val_field.name));
- add_debug_source_node(g, field_node);
- LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, type_struct_field->gen_index, "");
- LLVMValueRef value = gen_expr(g, field_node->data.struct_val_field.expr);
- LLVMBuildStore(g->builder, value, field_ptr);
+ return tmp_struct_ptr;
+ } else if (type_entry->id == TypeTableEntryIdUnreachable) {
+ assert(node->data.container_init_expr.entries.length == 0);
+ add_debug_source_node(g, node);
+ return LLVMBuildUnreachable(g->builder);
+ } else if (type_entry->id == TypeTableEntryIdVoid) {
+ assert(node->data.container_init_expr.entries.length == 0);
+ return nullptr;
+ } else {
+ zig_unreachable();
}
-
- return tmp_struct_ptr;
}
static LLVMValueRef gen_while_expr(CodeGen *g, AstNode *node) {
@@ -1659,93 +1769,39 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
get_resolved_expr(node)->block_context, false, &init_val);
}
-static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node,
- NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node)
-{
- TypeTableEntry *type_entry = codegen_num_lit->resolved_type;
- assert(type_entry);
-
- // override the expression type for number literals
- get_resolved_expr(source_node)->type_entry = type_entry;
-
- if (type_entry->id == TypeTableEntryIdInt) {
- // here the union has int64_t and uint64_t and we purposefully read
- // the uint64_t value in either case, because we want the twos
- // complement representation
+static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
+ assert(node->type == NodeTypeNumberLiteral);
- return LLVMConstInt(type_entry->type_ref,
- num_lit_node->data.x_uint,
- type_entry->data.integral.is_signed);
- } else if (type_entry->id == TypeTableEntryIdFloat) {
+ NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
+ assert(codegen_num_lit);
- return LLVMConstReal(type_entry->type_ref,
- num_lit_node->data.x_float);
- } else {
- zig_panic("bad number literal type");
- }
+ return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal);
}
-static LLVMValueRef gen_compiler_fn_type(CodeGen *g, AstNode *node) {
- assert(node->type == NodeTypeCompilerFnType);
-
- Buf *name = &node->data.compiler_fn_type.name;
- TypeTableEntry *type_entry = get_type_for_type_node(g, node->data.compiler_fn_type.type);
- if (buf_eql_str(name, "sizeof")) {
- NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
- AstNodeNumberLiteral num_lit_node;
- num_lit_node.kind = type_entry->data.num_lit.kind;
- num_lit_node.overflow = false;
- num_lit_node.data.x_uint = type_entry->size_in_bits / 8;
- return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
- } else if (buf_eql_str(name, "min_value")) {
- if (type_entry->id == TypeTableEntryIdInt) {
- if (type_entry->data.integral.is_signed) {
- return LLVMConstInt(type_entry->type_ref, 1ULL << (type_entry->size_in_bits - 1), false);
- } else {
- return LLVMConstNull(type_entry->type_ref);
- }
- } else if (type_entry->id == TypeTableEntryIdFloat) {
- zig_panic("TODO codegen min_value float");
- } else {
- zig_unreachable();
- }
- } else if (buf_eql_str(name, "max_value")) {
- if (type_entry->id == TypeTableEntryIdInt) {
- if (type_entry->data.integral.is_signed) {
- return LLVMConstInt(type_entry->type_ref, (1ULL << (type_entry->size_in_bits - 1)) - 1, false);
- } else {
- return LLVMConstAllOnes(type_entry->type_ref);
- }
- } else if (type_entry->id == TypeTableEntryIdFloat) {
- zig_panic("TODO codegen max_value float");
- } else {
- zig_unreachable();
- }
- } else if (buf_eql_str(name, "value_count")) {
- if (type_entry->id == TypeTableEntryIdEnum) {
- NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
- AstNodeNumberLiteral num_lit_node;
- num_lit_node.kind = type_entry->data.num_lit.kind;
- num_lit_node.overflow = false;
- num_lit_node.data.x_uint = type_entry->data.enumeration.field_count;
- return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
+static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
+ VariableTableEntry *variable = find_variable(
+ get_resolved_expr(node)->block_context,
+ &node->data.symbol_expr.symbol);
+ assert(variable);
+ if (variable->type->id == TypeTableEntryIdVoid) {
+ return nullptr;
+ } else if (variable->is_ptr) {
+ assert(variable->value_ref);
+ if (variable->type->id == TypeTableEntryIdArray) {
+ return variable->value_ref;
+ } else if (variable->type->id == TypeTableEntryIdStruct ||
+ variable->type->id == TypeTableEntryIdMaybe)
+ {
+ return variable->value_ref;
} else {
- zig_unreachable();
+ add_debug_source_node(g, node);
+ return LLVMBuildLoad(g->builder, variable->value_ref, "");
}
} else {
- zig_unreachable();
+ return variable->value_ref;
}
}
-static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
- assert(node->type == NodeTypeNumberLiteral);
-
- NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
- assert(codegen_num_lit);
-
- return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal);
-}
-
static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
switch (node->type) {
case NodeTypeBinOpExpr:
@@ -1766,11 +1822,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
return gen_slice_expr(g, node);
case NodeTypeFieldAccessExpr:
return gen_field_access_expr(g, node, false);
- case NodeTypeUnreachable:
- add_debug_source_node(g, node);
- return LLVMBuildUnreachable(g->builder);
- case NodeTypeVoid:
- return nullptr;
case NodeTypeBoolLiteral:
if (node->data.bool_literal.value)
return LLVMConstAllOnes(LLVMInt1Type());
@@ -1802,29 +1853,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
case NodeTypeCharLiteral:
return LLVMConstInt(LLVMInt8Type(), node->data.char_literal.value, false);
case NodeTypeSymbol:
- {
- VariableTableEntry *variable = find_variable(
- get_resolved_expr(node)->block_context,
- &node->data.symbol_expr.symbol);
- assert(variable);
- if (variable->type->id == TypeTableEntryIdVoid) {
- return nullptr;
- } else if (variable->is_ptr) {
- assert(variable->value_ref);
- if (variable->type->id == TypeTableEntryIdArray) {
- return variable->value_ref;
- } else if (variable->type->id == TypeTableEntryIdStruct ||
- variable->type->id == TypeTableEntryIdMaybe)
- {
- return variable->value_ref;
- } else {
- add_debug_source_node(g, node);
- return LLVMBuildLoad(g->builder, variable->value_ref, "");
- }
- } else {
- return variable->value_ref;
- }
- }
+ return gen_symbol(g, node);
case NodeTypeBlock:
return gen_block(g, node, nullptr);
case NodeTypeGoto:
@@ -1846,24 +1875,21 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
LLVMPositionBuilderAtEnd(g->builder, basic_block);
return nullptr;
}
- case NodeTypeStructValueExpr:
- return gen_struct_val_expr(g, node);
- case NodeTypeCompilerFnType:
- return gen_compiler_fn_type(g, node);
+ case NodeTypeContainerInitExpr:
+ return gen_container_init_expr(g, node);
case NodeTypeRoot:
case NodeTypeRootExportDecl:
case NodeTypeFnProto:
case NodeTypeFnDef:
case NodeTypeFnDecl:
case NodeTypeParamDecl:
- case NodeTypeType:
case NodeTypeExternBlock:
case NodeTypeDirective:
case NodeTypeUse:
case NodeTypeStructDecl:
case NodeTypeStructField:
case NodeTypeStructValueField:
- case NodeTypeCompilerFnExpr:
+ case NodeTypeArrayType:
zig_unreachable();
}
zig_unreachable();
@@ -1872,7 +1898,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
LLVMValueRef val = gen_expr_no_cast(g, node);
- if (node->type == NodeTypeVoid) {
+ if (is_node_void_expr(node)) {
return val;
}
@@ -1966,7 +1992,7 @@ static void do_code_gen(CodeGen *g) {
assert(proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &proto_node->data.fn_proto;
- LLVMTypeRef ret_type = get_type_for_type_node(g, fn_proto->return_type)->type_ref;
+ LLVMTypeRef ret_type = get_type_for_type_node(fn_proto->return_type)->type_ref;
int param_count = count_non_void_params(g, &fn_proto->params);
LLVMTypeRef *param_types = allocate<LLVMTypeRef>(param_count);
int gen_param_index = 0;
@@ -2009,7 +2035,7 @@ static void do_code_gen(CodeGen *g) {
TypeTableEntry *param_type = fn_proto_type_from_type_node(g, type_node);
LLVMValueRef argument_val = LLVMGetParam(fn, gen_param_index);
if (param_type->id == TypeTableEntryIdPointer &&
- param_type->data.pointer.is_noalias)
+ false) // TODO test if parameter is noalias
{
LLVMAddAttribute(argument_val, LLVMNoAliasAttribute);
} else if (param_type->id == TypeTableEntryIdPointer &&
@@ -2267,7 +2293,7 @@ static void define_builtin_types(CodeGen *g) {
g->builtin_types.entry_u64 = entry;
g->primitive_type_table.put(&entry->name, entry);
}
- g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true, false);
+ g->builtin_types.entry_c_string_literal = get_pointer_to_type(g, g->builtin_types.entry_u8, true);
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->type_ref = LLVMInt8Type();
@@ -2413,7 +2439,7 @@ static void define_builtin_fns_int(CodeGen *g, TypeTableEntry *type_entry) {
builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
builtin_fn->param_types[0] = type_entry;
builtin_fn->param_types[1] = type_entry;
- builtin_fn->param_types[2] = get_pointer_to_type(g, type_entry, false, false);
+ builtin_fn->param_types[2] = get_pointer_to_type(g, type_entry, false);
const char *signed_str = type_entry->data.integral.is_signed ?
@@ -2437,6 +2463,23 @@ static void define_builtin_fns_int(CodeGen *g, TypeTableEntry *type_entry) {
}
}
+static BuiltinFnEntry *create_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name) {
+ BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
+ buf_init_from_str(&builtin_fn->name, name);
+ builtin_fn->id = id;
+ g->builtin_fn_table.put(&builtin_fn->name, builtin_fn);
+ return builtin_fn;
+}
+
+static BuiltinFnEntry *create_one_arg_builtin_fn(CodeGen *g, BuiltinFnId id, const char *name) {
+ BuiltinFnEntry *builtin_fn = create_builtin_fn(g, id, name);
+ builtin_fn->return_type = nullptr; // manually determined later
+ builtin_fn->param_count = 1;
+ builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
+ builtin_fn->param_types[0] = nullptr; // manually checked later
+ return builtin_fn;
+}
+
static void define_builtin_fns(CodeGen *g) {
define_builtin_fns_int(g, g->builtin_types.entry_u8);
define_builtin_fns_int(g, g->builtin_types.entry_u16);
@@ -2447,9 +2490,7 @@ static void define_builtin_fns(CodeGen *g) {
define_builtin_fns_int(g, g->builtin_types.entry_i32);
define_builtin_fns_int(g, g->builtin_types.entry_i64);
{
- BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
- buf_init_from_str(&builtin_fn->name, "memcpy");
- builtin_fn->id = BuiltinFnIdMemcpy;
+ BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemcpy, "memcpy");
builtin_fn->return_type = g->builtin_types.entry_void;
builtin_fn->param_count = 3;
builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
@@ -2470,12 +2511,9 @@ static void define_builtin_fns(CodeGen *g) {
assert(LLVMGetIntrinsicID(builtin_fn->fn_val));
g->memcpy_fn_val = builtin_fn->fn_val;
- g->builtin_fn_table.put(&builtin_fn->name, builtin_fn);
}
{
- BuiltinFnEntry *builtin_fn = allocate<BuiltinFnEntry>(1);
- buf_init_from_str(&builtin_fn->name, "memset");
- builtin_fn->id = BuiltinFnIdMemset;
+ BuiltinFnEntry *builtin_fn = create_builtin_fn(g, BuiltinFnIdMemset, "memset");
builtin_fn->return_type = g->builtin_types.entry_void;
builtin_fn->param_count = 3;
builtin_fn->param_types = allocate<TypeTableEntry *>(builtin_fn->param_count);
@@ -2496,8 +2534,12 @@ static void define_builtin_fns(CodeGen *g) {
assert(LLVMGetIntrinsicID(builtin_fn->fn_val));
g->memset_fn_val = builtin_fn->fn_val;
- g->builtin_fn_table.put(&builtin_fn->name, builtin_fn);
}
+ create_one_arg_builtin_fn(g, BuiltinFnIdSizeof, "sizeof");
+ create_one_arg_builtin_fn(g, BuiltinFnIdMaxValue, "max_value");
+ create_one_arg_builtin_fn(g, BuiltinFnIdMinValue, "min_value");
+ create_one_arg_builtin_fn(g, BuiltinFnIdValueCount, "value_count");
+ create_one_arg_builtin_fn(g, BuiltinFnIdTypeof, "typeof");
}
@@ -2780,9 +2822,8 @@ void codegen_add_root_code(CodeGen *g, Buf *src_dir, Buf *src_basename, Buf *sou
}
static void to_c_type(CodeGen *g, AstNode *type_node, Buf *out_buf) {
- assert(type_node->type == NodeTypeType);
-
- TypeTableEntry *type_entry = type_node->data.type.entry;
+ zig_panic("TODO this function needs some love");
+ TypeTableEntry *type_entry = get_resolved_expr(type_node)->type_entry;
assert(type_entry);
if (type_entry == g->builtin_types.entry_u8) {
src/parser.cpp
@@ -62,6 +62,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
case PrefixOpAddressOf: return "&";
case PrefixOpConstAddressOf: return "&const";
case PrefixOpDereference: return "*";
+ case PrefixOpMaybe: return "?";
}
zig_unreachable();
}
@@ -80,8 +81,6 @@ const char *node_type_str(NodeType node_type) {
return "FnProto";
case NodeTypeParamDecl:
return "ParamDecl";
- case NodeTypeType:
- return "Type";
case NodeTypeBlock:
return "Block";
case NodeTypeBinOpExpr:
@@ -108,16 +107,12 @@ const char *node_type_str(NodeType node_type) {
return "StringLiteral";
case NodeTypeCharLiteral:
return "CharLiteral";
- case NodeTypeUnreachable:
- return "Unreachable";
case NodeTypeSymbol:
return "Symbol";
case NodeTypePrefixOpExpr:
return "PrefixOpExpr";
case NodeTypeUse:
return "Use";
- case NodeTypeVoid:
- return "Void";
case NodeTypeBoolLiteral:
return "BoolLiteral";
case NodeTypeNullLiteral:
@@ -144,14 +139,12 @@ const char *node_type_str(NodeType node_type) {
return "StructDecl";
case NodeTypeStructField:
return "StructField";
- case NodeTypeStructValueExpr:
- return "StructValueExpr";
case NodeTypeStructValueField:
return "StructValueField";
- case NodeTypeCompilerFnExpr:
- return "CompilerFnExpr";
- case NodeTypeCompilerFnType:
- return "CompilerFnType";
+ case NodeTypeContainerInitExpr:
+ return "ContainerInitExpr";
+ case NodeTypeArrayType:
+ return "ArrayType";
}
zig_unreachable();
}
@@ -214,47 +207,6 @@ void ast_print(AstNode *node, int indent) {
break;
}
- case NodeTypeType:
- switch (node->data.type.type) {
- case AstNodeTypeTypePrimitive:
- {
- Buf *name_buf = &node->data.type.primitive_name;
- fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf));
- break;
- }
- case AstNodeTypeTypePointer:
- {
- const char *const_or_mut_str = node->data.type.is_const ? "const " : "";
- const char *noalias_or_not_str = node->data.type.is_noalias ? "noalias " : "";
- fprintf(stderr, "%s%s PointerType\n", const_or_mut_str, noalias_or_not_str);
-
- ast_print(node->data.type.child_type, indent + 2);
- break;
- }
- case AstNodeTypeTypeArray:
- {
- const char *const_or_mut_str = node->data.type.is_const ? "const " : "";
- const char *noalias_or_not_str = node->data.type.is_noalias ? "noalias " : "";
- fprintf(stderr, "%s%s ArrayType\n", const_or_mut_str, noalias_or_not_str);
- if (node->data.type.array_size)
- ast_print(node->data.type.array_size, indent + 2);
- ast_print(node->data.type.child_type, indent + 2);
- break;
- }
- case AstNodeTypeTypeMaybe:
- {
- fprintf(stderr, "MaybeType\n");
- ast_print(node->data.type.child_type, indent + 2);
- break;
- }
- case AstNodeTypeTypeCompilerExpr:
- {
- fprintf(stderr, "CompilerExprType\n");
- ast_print(node->data.type.compiler_expr, indent + 2);
- break;
- }
- }
- break;
case NodeTypeReturnExpr:
fprintf(stderr, "%s\n", node_type_str(node->type));
if (node->data.return_expr.expr)
@@ -348,18 +300,12 @@ void ast_print(AstNode *node, int indent) {
fprintf(stderr, "%s '%c'\n", node_type_str(node->type), node->data.char_literal.value);
break;
}
- case NodeTypeUnreachable:
- fprintf(stderr, "Unreachable\n");
- break;
case NodeTypeSymbol:
fprintf(stderr, "Symbol %s\n", buf_ptr(&node->data.symbol_expr.symbol));
break;
case NodeTypeUse:
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.use.path));
break;
- case NodeTypeVoid:
- fprintf(stderr, "%s\n", node_type_str(node->type));
- break;
case NodeTypeBoolLiteral:
fprintf(stderr, "%s '%s'\n", node_type_str(node->type),
node->data.bool_literal.value ? "true" : "false");
@@ -431,24 +377,28 @@ void ast_print(AstNode *node, int indent) {
ast_print(node->data.struct_field.type, indent + 2);
}
break;
- case NodeTypeStructValueExpr:
- fprintf(stderr, "%s\n", node_type_str(node->type));
- ast_print(node->data.struct_val_expr.type, indent + 2);
- for (int i = 0; i < node->data.struct_val_expr.fields.length; i += 1) {
- AstNode *child = node->data.struct_val_expr.fields.at(i);
- ast_print(child, indent + 2);
- }
- break;
case NodeTypeStructValueField:
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_val_field.name));
ast_print(node->data.struct_val_field.expr, indent + 2);
break;
- case NodeTypeCompilerFnExpr:
- fprintf(stderr, "%s\n", node_type_str(node->type));
- break;
- case NodeTypeCompilerFnType:
+ case NodeTypeContainerInitExpr:
fprintf(stderr, "%s\n", node_type_str(node->type));
+ ast_print(node->data.container_init_expr.type, indent + 2);
+ for (int i = 0; i < node->data.container_init_expr.entries.length; i += 1) {
+ AstNode *child = node->data.container_init_expr.entries.at(i);
+ ast_print(child, indent + 2);
+ }
break;
+ case NodeTypeArrayType:
+ {
+ const char *const_str = node->data.array_type.is_const ? "const" : "var";
+ fprintf(stderr, "%s %s\n", node_type_str(node->type), const_str);
+ if (node->data.array_type.size) {
+ ast_print(node->data.array_type.size, indent + 2);
+ }
+ ast_print(node->data.array_type.child_type, indent + 2);
+ break;
+ }
}
}
@@ -539,9 +489,8 @@ static AstNode *ast_create_node_with_node(ParseContext *pc, NodeType type, AstNo
}
static AstNode *ast_create_void_type_node(ParseContext *pc, Token *token) {
- AstNode *node = ast_create_node(pc, NodeTypeType, token);
- node->data.type.type = AstNodeTypeTypePrimitive;
- buf_init_from_str(&node->data.type.primitive_name, "void");
+ AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
+ buf_init_from_str(&node->data.symbol_expr.symbol, "void");
return node;
}
@@ -961,7 +910,7 @@ static AstNode *ast_parse_expression(ParseContext *pc, int *token_index, bool ma
static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandatory);
static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory);
static AstNode *ast_parse_block_expr(ParseContext *pc, int *token_index, bool mandatory);
-static AstNode *ast_parse_type(ParseContext *pc, int *token_index);
+static AstNode *ast_parse_unwrap_maybe_expr(ParseContext *pc, int *token_index, bool mandatory);
static void ast_expect_token(ParseContext *pc, Token *token, TokenId token_id) {
if (token->id != token_id) {
@@ -1022,172 +971,42 @@ static void ast_parse_directives(ParseContext *pc, int *token_index,
zig_unreachable();
}
-static void ast_parse_type_assume_amp(ParseContext *pc, int *token_index, AstNode *node) {
- node->data.type.type = AstNodeTypeTypePointer;
- Token *first_type_token = &pc->tokens->at(*token_index);
- if (first_type_token->id == TokenIdKeywordConst) {
- node->data.type.is_const = true;
- *token_index += 1;
- first_type_token = &pc->tokens->at(*token_index);
- if (first_type_token->id == TokenIdKeywordNoAlias) {
- node->data.type.is_noalias = true;
- *token_index += 1;
- }
- } else if (first_type_token->id == TokenIdKeywordNoAlias) {
- node->data.type.is_noalias = true;
- *token_index += 1;
- }
-
- node->data.type.child_type = ast_parse_type(pc, token_index);
-}
-
/*
-CompilerFnType : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen)
+ParamDecl : option(token(NoAlias)) token(Symbol) token(Colon) UnwrapMaybeExpression | token(Ellipsis)
*/
-static AstNode *ast_parse_compiler_fn_type(ParseContext *pc, int *token_index, bool mandatory) {
- Token *token = &pc->tokens->at(*token_index);
+static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
+ Token *first_token = &pc->tokens->at(*token_index);
- if (token->id == TokenIdNumberSign) {
+ if (first_token->id == TokenIdEllipsis) {
*token_index += 1;
- } else if (mandatory) {
- ast_invalid_token_error(pc, token);
- } else {
return nullptr;
}
- Token *name_symbol = ast_eat_token(pc, token_index, TokenIdSymbol);
- ast_eat_token(pc, token_index, TokenIdLParen);
-
- AstNode *node = ast_create_node(pc, NodeTypeCompilerFnType, token);
- ast_buf_from_token(pc, name_symbol, &node->data.compiler_fn_type.name);
- node->data.compiler_fn_type.type = ast_parse_type(pc, token_index);
-
- ast_eat_token(pc, token_index, TokenIdRParen);
- return node;
-}
+ AstNode *node = ast_create_node(pc, NodeTypeParamDecl, first_token);
+ Token *name_token;
-/*
-CompilerFnExpr : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen)
-*/
-static AstNode *ast_parse_compiler_fn_call(ParseContext *pc, int *token_index, bool mandatory) {
- Token *token = &pc->tokens->at(*token_index);
-
- if (token->id == TokenIdNumberSign) {
+ if (first_token->id == TokenIdKeywordNoAlias) {
+ node->data.param_decl.is_noalias = true;
+ *token_index += 1;
+ name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
+ } else if (first_token->id == TokenIdSymbol) {
+ name_token = first_token;
*token_index += 1;
- } else if (mandatory) {
- ast_invalid_token_error(pc, token);
} else {
- return nullptr;
+ ast_invalid_token_error(pc, first_token);
}
- Token *name_symbol = ast_eat_token(pc, token_index, TokenIdSymbol);
- ast_eat_token(pc, token_index, TokenIdLParen);
-
- AstNode *node = ast_create_node(pc, NodeTypeCompilerFnExpr, token);
- ast_buf_from_token(pc, name_symbol, &node->data.compiler_fn_expr.name);
- node->data.compiler_fn_expr.expr = ast_parse_expression(pc, token_index, true);
-
- ast_eat_token(pc, token_index, TokenIdRParen);
- return node;
-}
-
-/*
-Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompilerFnExpr
-PointerType : token(Ampersand) option(token(Const)) option(token(NoAlias)) Type
-ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) option(token(NoAlias)) Type
-*/
-static AstNode *ast_parse_type(ParseContext *pc, int *token_index) {
- Token *token = &pc->tokens->at(*token_index);
- AstNode *node = ast_create_node(pc, NodeTypeType, token);
-
- AstNode *compiler_fn_expr = ast_parse_compiler_fn_call(pc, token_index, false);
- if (compiler_fn_expr) {
- node->data.type.type = AstNodeTypeTypeCompilerExpr;
- node->data.type.compiler_expr = compiler_fn_expr;
- return node;
- }
+ ast_buf_from_token(pc, name_token, &node->data.param_decl.name);
+ Token *colon = &pc->tokens->at(*token_index);
*token_index += 1;
+ ast_expect_token(pc, colon, TokenIdColon);
- if (token->id == TokenIdKeywordUnreachable) {
- node->data.type.type = AstNodeTypeTypePrimitive;
- buf_init_from_str(&node->data.type.primitive_name, "unreachable");
- } else if (token->id == TokenIdKeywordVoid) {
- node->data.type.type = AstNodeTypeTypePrimitive;
- buf_init_from_str(&node->data.type.primitive_name, "void");
- } else if (token->id == TokenIdSymbol) {
- node->data.type.type = AstNodeTypeTypePrimitive;
- ast_buf_from_token(pc, token, &node->data.type.primitive_name);
- } else if (token->id == TokenIdAmpersand) {
- ast_parse_type_assume_amp(pc, token_index, node);
- } else if (token->id == TokenIdMaybe) {
- node->data.type.type = AstNodeTypeTypeMaybe;
- node->data.type.child_type = ast_parse_type(pc, token_index);
- } else if (token->id == TokenIdBoolAnd) {
- // Pretend that we got 2 ampersand tokens
- node->data.type.type = AstNodeTypeTypePointer;
-
- node->data.type.child_type = ast_create_node_no_line_info(pc, NodeTypeType);
- node->data.type.child_type->line = token->start_line;
- node->data.type.child_type->column = token->start_column + 1;
-
- ast_parse_type_assume_amp(pc, token_index, node->data.type.child_type);
- } else if (token->id == TokenIdLBracket) {
- node->data.type.type = AstNodeTypeTypeArray;
-
- node->data.type.array_size = ast_parse_expression(pc, token_index, false);
-
- ast_eat_token(pc, token_index, TokenIdRBracket);
-
- Token *const_tok = &pc->tokens->at(*token_index);
- if (const_tok->id == TokenIdKeywordConst) {
- *token_index += 1;
- node->data.type.is_const = true;
-
- Token *next_tok = &pc->tokens->at(*token_index);
- if (next_tok->id == TokenIdKeywordNoAlias) {
- *token_index += 1;
- node->data.type.is_noalias = true;
- }
- } else if (const_tok->id == TokenIdKeywordNoAlias) {
- *token_index += 1;
- node->data.type.is_noalias = true;
- }
-
- node->data.type.child_type = ast_parse_type(pc, token_index);
- } else {
- ast_invalid_token_error(pc, token);
- }
+ node->data.param_decl.type = ast_parse_unwrap_maybe_expr(pc, token_index, true);
return node;
}
-/*
-ParamDecl : token(Symbol) token(Colon) Type | token(Ellipsis)
-*/
-static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
- Token *param_name = &pc->tokens->at(*token_index);
- *token_index += 1;
-
- if (param_name->id == TokenIdSymbol) {
- AstNode *node = ast_create_node(pc, NodeTypeParamDecl, param_name);
-
- ast_buf_from_token(pc, param_name, &node->data.param_decl.name);
-
- Token *colon = &pc->tokens->at(*token_index);
- *token_index += 1;
- ast_expect_token(pc, colon, TokenIdColon);
-
- node->data.param_decl.type = ast_parse_type(pc, token_index);
-
- return node;
- } else if (param_name->id == TokenIdEllipsis) {
- return nullptr;
- } else {
- ast_invalid_token_error(pc, param_name);
- }
-}
-
static void ast_parse_param_decl_list(ParseContext *pc, int *token_index,
ZigList<AstNode *> *params, bool *is_var_args)
@@ -1274,52 +1093,222 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool
}
/*
-StructValueExpression : token(Symbol) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace)
-StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression
+ArrayType : token(LBracket) option(Expression) token(RBracket) option(token(Const)) Expression
*/
-static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) {
- Token *first_token = &pc->tokens->at(*token_index);
- AstNode *node = ast_create_node(pc, NodeTypeStructValueExpr, first_token);
+static AstNode *ast_parse_array_type_expr(ParseContext *pc, int *token_index, bool mandatory) {
+ Token *l_bracket = &pc->tokens->at(*token_index);
+ if (l_bracket->id != TokenIdLBracket) {
+ if (mandatory) {
+ ast_invalid_token_error(pc, l_bracket);
+ } else {
+ return nullptr;
+ }
+ }
- node->data.struct_val_expr.type = ast_parse_type(pc, token_index);
+ *token_index += 1;
- ast_eat_token(pc, token_index, TokenIdLBrace);
+ AstNode *node = ast_create_node(pc, NodeTypeArrayType, l_bracket);
+ node->data.array_type.size = ast_parse_expression(pc, token_index, false);
+
+ ast_eat_token(pc, token_index, TokenIdRBracket);
+
+ Token *const_tok = &pc->tokens->at(*token_index);
+ if (const_tok->id == TokenIdKeywordConst) {
+ *token_index += 1;
+ node->data.array_type.is_const = true;
+ }
+
+ node->data.array_type.child_type = ast_parse_expression(pc, token_index, true);
+
+ return node;
+}
+
+/*
+AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)
+*/
+static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode *node) {
+ ast_eat_token(pc, token_index, TokenIdLBracket);
+ Token *alias = ast_eat_token(pc, token_index, TokenIdSymbol);
+ ast_eat_token(pc, token_index, TokenIdRBracket);
+
+ Token *constraint = ast_eat_token(pc, token_index, TokenIdStringLiteral);
+
+ ast_eat_token(pc, token_index, TokenIdLParen);
+ AstNode *expr_node = ast_parse_expression(pc, token_index, true);
+ ast_eat_token(pc, token_index, TokenIdRParen);
+
+ AsmInput *asm_input = allocate<AsmInput>(1);
+ ast_buf_from_token(pc, alias, &asm_input->asm_symbolic_name);
+ parse_string_literal(pc, constraint, &asm_input->constraint, nullptr, nullptr);
+ asm_input->expr = expr_node;
+ node->data.asm_expr.input_list.append(asm_input);
+}
+
+/*
+AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) Expression) token(RParen)
+*/
+static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNode *node) {
+ ast_eat_token(pc, token_index, TokenIdLBracket);
+ Token *alias = ast_eat_token(pc, token_index, TokenIdSymbol);
+ ast_eat_token(pc, token_index, TokenIdRBracket);
+
+ Token *constraint = ast_eat_token(pc, token_index, TokenIdStringLiteral);
+
+ AsmOutput *asm_output = allocate<AsmOutput>(1);
+
+ ast_eat_token(pc, token_index, TokenIdLParen);
+
+ Token *token = &pc->tokens->at(*token_index);
+ *token_index += 1;
+ if (token->id == TokenIdSymbol) {
+ ast_buf_from_token(pc, token, &asm_output->variable_name);
+ } else if (token->id == TokenIdArrow) {
+ asm_output->return_type = ast_parse_expression(pc, token_index, true);
+ } else {
+ ast_invalid_token_error(pc, token);
+ }
+
+ ast_eat_token(pc, token_index, TokenIdRParen);
+
+ ast_buf_from_token(pc, alias, &asm_output->asm_symbolic_name);
+ parse_string_literal(pc, constraint, &asm_output->constraint, nullptr, nullptr);
+ node->data.asm_expr.output_list.append(asm_output);
+}
+
+/*
+AsmClobbers: token(Colon) list(token(String), token(Comma))
+*/
+static void ast_parse_asm_clobbers(ParseContext *pc, int *token_index, AstNode *node) {
+ Token *colon_tok = &pc->tokens->at(*token_index);
+
+ if (colon_tok->id != TokenIdColon)
+ return;
+
+ *token_index += 1;
for (;;) {
- Token *token = &pc->tokens->at(*token_index);
+ Token *string_tok = &pc->tokens->at(*token_index);
+ ast_expect_token(pc, string_tok, TokenIdStringLiteral);
*token_index += 1;
- if (token->id == TokenIdRBrace) {
- return node;
- } else if (token->id == TokenIdDot) {
- Token *field_name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
- ast_eat_token(pc, token_index, TokenIdEq);
+ Buf *clobber_buf = buf_alloc();
+ parse_string_literal(pc, string_tok, clobber_buf, nullptr, nullptr);
+ node->data.asm_expr.clobber_list.append(clobber_buf);
+
+ Token *comma = &pc->tokens->at(*token_index);
+
+ if (comma->id == TokenIdComma) {
+ *token_index += 1;
+ continue;
+ } else {
+ break;
+ }
+ }
+}
- AstNode *field_node = ast_create_node(pc, NodeTypeStructValueField, token);
+/*
+AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers)
+*/
+static void ast_parse_asm_input(ParseContext *pc, int *token_index, AstNode *node) {
+ Token *colon_tok = &pc->tokens->at(*token_index);
- ast_buf_from_token(pc, field_name_tok, &field_node->data.struct_val_field.name);
- field_node->data.struct_val_field.expr = ast_parse_expression(pc, token_index, true);
+ if (colon_tok->id != TokenIdColon)
+ return;
- node->data.struct_val_expr.fields.append(field_node);
+ *token_index += 1;
- Token *comma_tok = &pc->tokens->at(*token_index);
- if (comma_tok->id == TokenIdComma) {
- *token_index += 1;
- } else if (comma_tok->id != TokenIdRBrace) {
- ast_invalid_token_error(pc, comma_tok);
- } else {
- *token_index += 1;
- return node;
- }
+ for (;;) {
+ ast_parse_asm_input_item(pc, token_index, node);
+
+ Token *comma = &pc->tokens->at(*token_index);
+
+ if (comma->id == TokenIdComma) {
+ *token_index += 1;
+ continue;
} else {
- ast_invalid_token_error(pc, token);
+ break;
}
}
+
+ ast_parse_asm_clobbers(pc, token_index, node);
}
/*
-PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType | (token(AtSign) token(Symbol) FnCallExpression)
-KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False) | token(Null)
+AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput)
+*/
+static void ast_parse_asm_output(ParseContext *pc, int *token_index, AstNode *node) {
+ Token *colon_tok = &pc->tokens->at(*token_index);
+
+ if (colon_tok->id != TokenIdColon)
+ return;
+
+ *token_index += 1;
+
+ for (;;) {
+ ast_parse_asm_output_item(pc, token_index, node);
+
+ Token *comma = &pc->tokens->at(*token_index);
+
+ if (comma->id == TokenIdComma) {
+ *token_index += 1;
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ ast_parse_asm_input(pc, token_index, node);
+}
+
+/*
+AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen)
+*/
+static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mandatory) {
+ Token *asm_token = &pc->tokens->at(*token_index);
+
+ if (asm_token->id != TokenIdKeywordAsm) {
+ if (mandatory) {
+ ast_invalid_token_error(pc, asm_token);
+ } else {
+ return nullptr;
+ }
+ }
+
+ AstNode *node = ast_create_node(pc, NodeTypeAsmExpr, asm_token);
+
+ *token_index += 1;
+ Token *lparen_tok = &pc->tokens->at(*token_index);
+
+ if (lparen_tok->id == TokenIdKeywordVolatile) {
+ node->data.asm_expr.is_volatile = true;
+
+ *token_index += 1;
+ lparen_tok = &pc->tokens->at(*token_index);
+ }
+
+ ast_expect_token(pc, lparen_tok, TokenIdLParen);
+ *token_index += 1;
+
+ Token *template_tok = &pc->tokens->at(*token_index);
+ ast_expect_token(pc, template_tok, TokenIdStringLiteral);
+ *token_index += 1;
+
+ parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template, nullptr,
+ &node->data.asm_expr.offset_map);
+ parse_asm_template(pc, node);
+
+ ast_parse_asm_output(pc, token_index, node);
+
+ Token *rparen_tok = &pc->tokens->at(*token_index);
+ ast_expect_token(pc, rparen_tok, TokenIdRParen);
+ *token_index += 1;
+
+ return node;
+}
+
+/*
+PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | token(Symbol) | (token(AtSign) token(Symbol) FnCallExpression) | ArrayType | AsmExpression
+KeywordLiteral : token(True) | token(False) | token(Null) | token(Break) | token(Continue)
*/
static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
@@ -1339,14 +1328,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
node->data.char_literal.value = parse_char_literal(pc, token);
*token_index += 1;
return node;
- } else if (token->id == TokenIdKeywordUnreachable) {
- AstNode *node = ast_create_node(pc, NodeTypeUnreachable, token);
- *token_index += 1;
- return node;
- } else if (token->id == TokenIdKeywordVoid) {
- AstNode *node = ast_create_node(pc, NodeTypeVoid, token);
- *token_index += 1;
- return node;
} else if (token->id == TokenIdKeywordTrue) {
AstNode *node = ast_create_node(pc, NodeTypeBoolLiteral, token);
node->data.bool_literal.value = true;
@@ -1357,8 +1338,16 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
node->data.bool_literal.value = false;
*token_index += 1;
return node;
- } else if (token->id == TokenIdKeywordNull) {
- AstNode *node = ast_create_node(pc, NodeTypeNullLiteral, token);
+ } else if (token->id == TokenIdKeywordNull) {
+ AstNode *node = ast_create_node(pc, NodeTypeNullLiteral, token);
+ *token_index += 1;
+ return node;
+ } else if (token->id == TokenIdKeywordBreak) {
+ AstNode *node = ast_create_node(pc, NodeTypeBreak, token);
+ *token_index += 1;
+ return node;
+ } else if (token->id == TokenIdKeywordContinue) {
+ AstNode *node = ast_create_node(pc, NodeTypeContinue, token);
*token_index += 1;
return node;
} else if (token->id == TokenIdAtSign) {
@@ -1374,16 +1363,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
node->data.fn_call_expr.is_builtin = true;
return node;
} else if (token->id == TokenIdSymbol) {
- Token *next_token = &pc->tokens->at(*token_index + 1);
-
- if (next_token->id == TokenIdLBrace) {
- return ast_parse_struct_val_expr(pc, token_index);
- } else {
- *token_index += 1;
- AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
- ast_buf_from_token(pc, token, &node->data.symbol_expr.symbol);
- return node;
- }
+ *token_index += 1;
+ AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
+ ast_buf_from_token(pc, token, &node->data.symbol_expr.symbol);
+ return node;
} else if (token->id == TokenIdKeywordGoto) {
AstNode *node = ast_create_node(pc, NodeTypeGoto, token);
*token_index += 1;
@@ -1394,14 +1377,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
ast_buf_from_token(pc, dest_symbol, &node->data.goto_expr.name);
return node;
- } else if (token->id == TokenIdKeywordBreak) {
- AstNode *node = ast_create_node(pc, NodeTypeBreak, token);
- *token_index += 1;
- return node;
- } else if (token->id == TokenIdKeywordContinue) {
- AstNode *node = ast_create_node(pc, NodeTypeContinue, token);
- *token_index += 1;
- return node;
}
AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);
@@ -1414,9 +1389,14 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
return block_expr_node;
}
- AstNode *compiler_fn_type = ast_parse_compiler_fn_type(pc, token_index, false);
- if (compiler_fn_type) {
- return compiler_fn_type;
+ AstNode *array_type_node = ast_parse_array_type_expr(pc, token_index, false);
+ if (array_type_node) {
+ return array_type_node;
+ }
+
+ AstNode *asm_expr = ast_parse_asm_expr(pc, token_index, false);
+ if (asm_expr) {
+ return asm_expr;
}
if (!mandatory)
@@ -1426,11 +1406,14 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
}
/*
-SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
+SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ContainerInitExpression)
FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
ArrayAccessExpression : token(LBracket) Expression token(RBracket)
SliceExpression : token(LBracket) Expression token(Ellipsis) option(Expression) token(RBracket) option(token(Const))
FieldAccessExpression : token(Dot) token(Symbol)
+ContainerInitExpression : token(LBrace) ContainerInitBody token(RBrace)
+ContainerInitBody : list(StructLiteralField, token(Comma)) | list(Expression, token(Comma))
+StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
*/
static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, bool mandatory) {
AstNode *primary_expr = ast_parse_primary_expr(pc, token_index, mandatory);
@@ -1439,16 +1422,16 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo
}
while (true) {
- Token *token = &pc->tokens->at(*token_index);
- if (token->id == TokenIdLParen) {
+ Token *first_token = &pc->tokens->at(*token_index);
+ if (first_token->id == TokenIdLParen) {
*token_index += 1;
- AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, token);
+ AstNode *node = ast_create_node(pc, NodeTypeFnCallExpr, first_token);
node->data.fn_call_expr.fn_ref_expr = primary_expr;
ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params);
primary_expr = node;
- } else if (token->id == TokenIdLBracket) {
+ } else if (first_token->id == TokenIdLBracket) {
*token_index += 1;
AstNode *expr_node = ast_parse_expression(pc, token_index, true);
@@ -1458,7 +1441,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo
if (ellipsis_or_r_bracket->id == TokenIdEllipsis) {
*token_index += 1;
- AstNode *node = ast_create_node(pc, NodeTypeSliceExpr, token);
+ AstNode *node = ast_create_node(pc, NodeTypeSliceExpr, first_token);
node->data.slice_expr.array_ref_expr = primary_expr;
node->data.slice_expr.start = expr_node;
node->data.slice_expr.end = ast_parse_expression(pc, token_index, false);
@@ -1475,23 +1458,88 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo
} else if (ellipsis_or_r_bracket->id == TokenIdRBracket) {
*token_index += 1;
- AstNode *node = ast_create_node(pc, NodeTypeArrayAccessExpr, token);
+ AstNode *node = ast_create_node(pc, NodeTypeArrayAccessExpr, first_token);
node->data.array_access_expr.array_ref_expr = primary_expr;
node->data.array_access_expr.subscript = expr_node;
primary_expr = node;
} else {
- ast_invalid_token_error(pc, token);
+ ast_invalid_token_error(pc, first_token);
}
- } else if (token->id == TokenIdDot) {
+ } else if (first_token->id == TokenIdDot) {
*token_index += 1;
Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
- AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, token);
+ AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token);
node->data.field_access_expr.struct_expr = primary_expr;
ast_buf_from_token(pc, name_token, &node->data.field_access_expr.field_name);
+ primary_expr = node;
+ } else if (first_token->id == TokenIdLBrace) {
+ *token_index += 1;
+
+ AstNode *node = ast_create_node(pc, NodeTypeContainerInitExpr, first_token);
+ node->data.container_init_expr.type = primary_expr;
+
+ Token *token = &pc->tokens->at(*token_index);
+ if (token->id == TokenIdDot) {
+ for (;;) {
+ if (token->id == TokenIdDot) {
+ ast_eat_token(pc, token_index, TokenIdDot);
+ Token *field_name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
+ ast_eat_token(pc, token_index, TokenIdEq);
+
+ AstNode *field_node = ast_create_node(pc, NodeTypeStructValueField, token);
+
+ ast_buf_from_token(pc, field_name_tok, &field_node->data.struct_val_field.name);
+ field_node->data.struct_val_field.expr = ast_parse_expression(pc, token_index, true);
+
+ node->data.container_init_expr.entries.append(field_node);
+
+ Token *comma_tok = &pc->tokens->at(*token_index);
+ if (comma_tok->id == TokenIdComma) {
+ *token_index += 1;
+ token = &pc->tokens->at(*token_index);
+ continue;
+ } else if (comma_tok->id != TokenIdRBrace) {
+ ast_invalid_token_error(pc, comma_tok);
+ } else {
+ *token_index += 1;
+ break;
+ }
+ } else if (token->id == TokenIdRBrace) {
+ *token_index += 1;
+ break;
+ } else {
+ ast_invalid_token_error(pc, token);
+ }
+ }
+
+ } else {
+ for (;;) {
+ if (token->id == TokenIdRBrace) {
+ *token_index += 1;
+ break;
+ } else {
+ AstNode *elem_node = ast_parse_expression(pc, token_index, true);
+ node->data.container_init_expr.entries.append(elem_node);
+
+ Token *comma_tok = &pc->tokens->at(*token_index);
+ if (comma_tok->id == TokenIdComma) {
+ *token_index += 1;
+ token = &pc->tokens->at(*token_index);
+ continue;
+ } else if (comma_tok->id != TokenIdRBrace) {
+ ast_invalid_token_error(pc, comma_tok);
+ } else {
+ *token_index += 1;
+ break;
+ }
+ }
+ }
+ }
+
primary_expr = node;
} else {
return primary_expr;
@@ -1506,56 +1554,54 @@ static PrefixOp tok_to_prefix_op(Token *token) {
case TokenIdTilde: return PrefixOpBinNot;
case TokenIdAmpersand: return PrefixOpAddressOf;
case TokenIdStar: return PrefixOpDereference;
+ case TokenIdMaybe: return PrefixOpMaybe;
+ case TokenIdBoolAnd: return PrefixOpAddressOf;
default: return PrefixOpInvalid;
}
}
/*
+PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression
PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const)))
*/
-static PrefixOp ast_parse_prefix_op(ParseContext *pc, int *token_index, bool mandatory) {
+static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
- PrefixOp result = tok_to_prefix_op(token);
- if (result == PrefixOpInvalid) {
- if (mandatory) {
- ast_invalid_token_error(pc, token);
- } else {
- return PrefixOpInvalid;
- }
+ PrefixOp prefix_op = tok_to_prefix_op(token);
+ if (prefix_op == PrefixOpInvalid) {
+ return ast_parse_suffix_op_expr(pc, token_index, mandatory);
}
*token_index += 1;
- if (result == PrefixOpAddressOf) {
+ AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
+ AstNode *parent_node = node;
+ if (token->id == TokenIdBoolAnd) {
+ // pretend that we got 2 ampersand tokens
+
+ parent_node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
+ parent_node->data.prefix_op_expr.primary_expr = node;
+ parent_node->data.prefix_op_expr.prefix_op = PrefixOpAddressOf;
+
+ node->column += 1;
+ }
+
+ if (prefix_op == PrefixOpAddressOf) {
Token *token = &pc->tokens->at(*token_index);
if (token->id == TokenIdKeywordConst) {
*token_index += 1;
- result = PrefixOpConstAddressOf;
+ prefix_op = PrefixOpConstAddressOf;
}
}
- return result;
-}
-
-/*
-PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression
-*/
-static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory) {
- Token *token = &pc->tokens->at(*token_index);
- PrefixOp prefix_op = ast_parse_prefix_op(pc, token_index, false);
- if (prefix_op == PrefixOpInvalid)
- return ast_parse_suffix_op_expr(pc, token_index, mandatory);
-
AstNode *prefix_op_expr = ast_parse_prefix_op_expr(pc, token_index, true);
- AstNode *node = ast_create_node(pc, NodeTypePrefixOpExpr, token);
node->data.prefix_op_expr.primary_expr = prefix_op_expr;
node->data.prefix_op_expr.prefix_op = prefix_op;
- return node;
+ return parent_node;
}
/*
-CastExpression : CastExpression token(as) Type | PrefixOpExpression
+CastExpression : CastExpression token(as) PrimaryExpression | PrefixOpExpression
*/
static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bool mandatory) {
AstNode *operand_1 = ast_parse_prefix_op_expr(pc, token_index, mandatory);
@@ -1571,7 +1617,7 @@ static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bo
AstNode *node = ast_create_node(pc, NodeTypeCastExpr, as_kw);
node->data.cast_expr.expr = operand_1;
- node->data.cast_expr.type = ast_parse_type(pc, token_index);
+ node->data.cast_expr.type = ast_parse_primary_expr(pc, token_index, true);
operand_1 = node;
}
@@ -1899,7 +1945,7 @@ static AstNode *ast_parse_else(ParseContext *pc, int *token_index, bool mandator
/*
IfExpression : IfVarExpression | IfBoolExpression
IfBoolExpression : token(If) token(LParen) Expression token(RParen) Expression option(Else)
-IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(token(Colon) Type) Token(MaybeAssign) Expression token(RParen) Expression Option(Else)
+IfVarExpression : token(If) token(LParen) (token(Const) | token(Var)) token(Symbol) option(Expression) Token(MaybeAssign) Expression token(RParen) Expression Option(Else)
*/
static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *if_tok = &pc->tokens->at(*token_index);
@@ -1924,11 +1970,12 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
ast_buf_from_token(pc, name_token, &node->data.if_var_expr.var_decl.symbol);
Token *eq_or_colon = &pc->tokens->at(*token_index);
- *token_index += 1;
if (eq_or_colon->id == TokenIdMaybeAssign) {
+ *token_index += 1;
node->data.if_var_expr.var_decl.expr = ast_parse_expression(pc, token_index, true);
} else if (eq_or_colon->id == TokenIdColon) {
- node->data.if_var_expr.var_decl.type = ast_parse_type(pc, token_index);
+ *token_index += 1;
+ node->data.if_var_expr.var_decl.type = ast_parse_expression(pc, token_index, true);
ast_eat_token(pc, token_index, TokenIdMaybeAssign);
node->data.if_var_expr.var_decl.expr = ast_parse_expression(pc, token_index, true);
@@ -1967,7 +2014,7 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
}
/*
-VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) Type option(token(Eq) Expression))
+VariableDeclaration : option(FnVisibleMod) (token(Var) | token(Const)) token(Symbol) (token(Eq) Expression | token(Colon) UnwrapMaybeExpression option(token(Eq) Expression))
*/
static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *first_token = &pc->tokens->at(*token_index);
@@ -2008,8 +2055,7 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token
node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true);
return node;
} else if (eq_or_colon->id == TokenIdColon) {
- node->data.variable_declaration.type = ast_parse_type(pc, token_index);
-
+ node->data.variable_declaration.type = ast_parse_unwrap_maybe_expr(pc, token_index, true);
Token *eq_token = &pc->tokens->at(*token_index);
if (eq_token->id == TokenIdEq) {
*token_index += 1;
@@ -2138,6 +2184,7 @@ static BinOpType ast_parse_ass_op(ParseContext *pc, int *token_index, bool manda
/*
UnwrapMaybeExpression : BoolOrExpression token(DoubleQuestion) BoolOrExpression | BoolOrExpression
*/
+// this is currently the first child expression of assignment
static AstNode *ast_parse_unwrap_maybe_expr(ParseContext *pc, int *token_index, bool mandatory) {
AstNode *lhs = ast_parse_bool_or_expr(pc, token_index, mandatory);
if (!lhs)
@@ -2185,190 +2232,7 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand
}
/*
-AsmInputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) Expression token(RParen)
-*/
-static void ast_parse_asm_input_item(ParseContext *pc, int *token_index, AstNode *node) {
- ast_eat_token(pc, token_index, TokenIdLBracket);
- Token *alias = ast_eat_token(pc, token_index, TokenIdSymbol);
- ast_eat_token(pc, token_index, TokenIdRBracket);
-
- Token *constraint = ast_eat_token(pc, token_index, TokenIdStringLiteral);
-
- ast_eat_token(pc, token_index, TokenIdLParen);
- AstNode *expr_node = ast_parse_expression(pc, token_index, true);
- ast_eat_token(pc, token_index, TokenIdRParen);
-
- AsmInput *asm_input = allocate<AsmInput>(1);
- ast_buf_from_token(pc, alias, &asm_input->asm_symbolic_name);
- parse_string_literal(pc, constraint, &asm_input->constraint, nullptr, nullptr);
- asm_input->expr = expr_node;
- node->data.asm_expr.input_list.append(asm_input);
-}
-
-/*
-AsmOutputItem : token(LBracket) token(Symbol) token(RBracket) token(String) token(LParen) (token(Symbol) | token(Arrow) Type) token(RParen)
-*/
-static void ast_parse_asm_output_item(ParseContext *pc, int *token_index, AstNode *node) {
- ast_eat_token(pc, token_index, TokenIdLBracket);
- Token *alias = ast_eat_token(pc, token_index, TokenIdSymbol);
- ast_eat_token(pc, token_index, TokenIdRBracket);
-
- Token *constraint = ast_eat_token(pc, token_index, TokenIdStringLiteral);
-
- AsmOutput *asm_output = allocate<AsmOutput>(1);
-
- ast_eat_token(pc, token_index, TokenIdLParen);
-
- Token *token = &pc->tokens->at(*token_index);
- *token_index += 1;
- if (token->id == TokenIdSymbol) {
- ast_buf_from_token(pc, token, &asm_output->variable_name);
- } else if (token->id == TokenIdArrow) {
- asm_output->return_type = ast_parse_type(pc, token_index);
- } else {
- ast_invalid_token_error(pc, token);
- }
-
- ast_eat_token(pc, token_index, TokenIdRParen);
-
- ast_buf_from_token(pc, alias, &asm_output->asm_symbolic_name);
- parse_string_literal(pc, constraint, &asm_output->constraint, nullptr, nullptr);
- node->data.asm_expr.output_list.append(asm_output);
-}
-
-/*
-AsmClobbers: token(Colon) list(token(String), token(Comma))
-*/
-static void ast_parse_asm_clobbers(ParseContext *pc, int *token_index, AstNode *node) {
- Token *colon_tok = &pc->tokens->at(*token_index);
-
- if (colon_tok->id != TokenIdColon)
- return;
-
- *token_index += 1;
-
- for (;;) {
- Token *string_tok = &pc->tokens->at(*token_index);
- ast_expect_token(pc, string_tok, TokenIdStringLiteral);
- *token_index += 1;
-
- Buf *clobber_buf = buf_alloc();
- parse_string_literal(pc, string_tok, clobber_buf, nullptr, nullptr);
- node->data.asm_expr.clobber_list.append(clobber_buf);
-
- Token *comma = &pc->tokens->at(*token_index);
-
- if (comma->id == TokenIdComma) {
- *token_index += 1;
- continue;
- } else {
- break;
- }
- }
-}
-
-/*
-AsmInput : token(Colon) list(AsmInputItem, token(Comma)) option(AsmClobbers)
-*/
-static void ast_parse_asm_input(ParseContext *pc, int *token_index, AstNode *node) {
- Token *colon_tok = &pc->tokens->at(*token_index);
-
- if (colon_tok->id != TokenIdColon)
- return;
-
- *token_index += 1;
-
- for (;;) {
- ast_parse_asm_input_item(pc, token_index, node);
-
- Token *comma = &pc->tokens->at(*token_index);
-
- if (comma->id == TokenIdComma) {
- *token_index += 1;
- continue;
- } else {
- break;
- }
- }
-
- ast_parse_asm_clobbers(pc, token_index, node);
-}
-
-/*
-AsmOutput : token(Colon) list(AsmOutputItem, token(Comma)) option(AsmInput)
-*/
-static void ast_parse_asm_output(ParseContext *pc, int *token_index, AstNode *node) {
- Token *colon_tok = &pc->tokens->at(*token_index);
-
- if (colon_tok->id != TokenIdColon)
- return;
-
- *token_index += 1;
-
- for (;;) {
- ast_parse_asm_output_item(pc, token_index, node);
-
- Token *comma = &pc->tokens->at(*token_index);
-
- if (comma->id == TokenIdComma) {
- *token_index += 1;
- continue;
- } else {
- break;
- }
- }
-
- ast_parse_asm_input(pc, token_index, node);
-}
-
-/*
-AsmExpression : token(Asm) option(token(Volatile)) token(LParen) token(String) option(AsmOutput) token(RParen)
-*/
-static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mandatory) {
- Token *asm_token = &pc->tokens->at(*token_index);
-
- if (asm_token->id != TokenIdKeywordAsm) {
- if (mandatory) {
- ast_invalid_token_error(pc, asm_token);
- } else {
- return nullptr;
- }
- }
-
- AstNode *node = ast_create_node(pc, NodeTypeAsmExpr, asm_token);
-
- *token_index += 1;
- Token *lparen_tok = &pc->tokens->at(*token_index);
-
- if (lparen_tok->id == TokenIdKeywordVolatile) {
- node->data.asm_expr.is_volatile = true;
-
- *token_index += 1;
- lparen_tok = &pc->tokens->at(*token_index);
- }
-
- ast_expect_token(pc, lparen_tok, TokenIdLParen);
- *token_index += 1;
-
- Token *template_tok = &pc->tokens->at(*token_index);
- ast_expect_token(pc, template_tok, TokenIdStringLiteral);
- *token_index += 1;
-
- parse_string_literal(pc, template_tok, &node->data.asm_expr.asm_template, nullptr,
- &node->data.asm_expr.offset_map);
- parse_asm_template(pc, node);
-
- ast_parse_asm_output(pc, token_index, node);
-
- Token *rparen_tok = &pc->tokens->at(*token_index);
- ast_expect_token(pc, rparen_tok, TokenIdRParen);
- *token_index += 1;
-
- return node;
-}
-
-/*
-NonBlockExpression : ReturnExpression | AssignmentExpression | AsmExpression
+NonBlockExpression : ReturnExpression | AssignmentExpression
*/
static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
@@ -2381,10 +2245,6 @@ static AstNode *ast_parse_non_block_expr(ParseContext *pc, int *token_index, boo
if (ass_expr)
return ass_expr;
- AstNode *asm_expr = ast_parse_asm_expr(pc, token_index, false);
- if (asm_expr)
- return asm_expr;
-
if (mandatory)
ast_invalid_token_error(pc, token);
@@ -2440,6 +2300,14 @@ static AstNode *ast_parse_label(ParseContext *pc, int *token_index, bool mandato
return node;
}
+static AstNode *ast_create_void_expr(ParseContext *pc, Token *token) {
+ AstNode *node = ast_create_node(pc, NodeTypeContainerInitExpr, token);
+ node->data.container_init_expr.type = ast_create_node(pc, NodeTypeSymbol, token);
+ node->data.container_init_expr.kind = ContainerInitKindArray;
+ buf_init_from_str(&node->data.container_init_expr.type->data.symbol_expr.symbol, "void");
+ return node;
+}
+
/*
Block : token(LBrace) list(option(Statement), token(Semicolon)) token(RBrace)
Statement : Label | VariableDeclaration token(Semicolon) | NonBlockExpression token(Semicolon) | BlockExpression
@@ -2478,7 +2346,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
if (!statement_node) {
statement_node = ast_parse_non_block_expr(pc, token_index, false);
if (!statement_node) {
- statement_node = ast_create_node(pc, NodeTypeVoid, last_token);
+ statement_node = ast_create_void_expr(pc, last_token);
}
}
}
@@ -2501,7 +2369,7 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
}
/*
-FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(token(Arrow) Type)
+FnProto : many(Directive) option(FnVisibleMod) token(Fn) token(Symbol) ParamDeclList option(Expression)
*/
static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mandatory) {
Token *first_token = &pc->tokens->at(*token_index);
@@ -2552,19 +2420,17 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand
ast_parse_param_decl_list(pc, token_index, &node->data.fn_proto.params, &node->data.fn_proto.is_var_args);
- Token *arrow = &pc->tokens->at(*token_index);
- if (arrow->id == TokenIdArrow) {
- *token_index += 1;
- node->data.fn_proto.return_type = ast_parse_type(pc, token_index);
- } else {
- node->data.fn_proto.return_type = ast_create_void_type_node(pc, arrow);
+ Token *next_token = &pc->tokens->at(*token_index);
+ node->data.fn_proto.return_type = ast_parse_expression(pc, token_index, false);
+ if (!node->data.fn_proto.return_type) {
+ node->data.fn_proto.return_type = ast_create_void_type_node(pc, next_token);
}
return node;
}
/*
-FnDef : FnProto Block
+FnDef : FnProto token(FatArrow) Block
*/
static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandatory) {
AstNode *fn_proto = ast_parse_fn_proto(pc, token_index, mandatory);
@@ -2573,6 +2439,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandat
AstNode *node = ast_create_node_with_node(pc, NodeTypeFnDef, fn_proto);
node->data.fn_def.fn_proto = fn_proto;
+ ast_eat_token(pc, token_index, TokenIdFatArrow);
node->data.fn_def.body = ast_parse_block(pc, token_index, true);
return node;
@@ -2709,7 +2576,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index) {
/*
ContainerDecl : many(Directive) option(FnVisibleMod) (token(Struct) | token(Enum)) token(Symbol) token(LBrace) many(StructMember) token(RBrace)
StructMember: StructField | FnDecl
-StructField : token(Symbol) token(Colon) Type token(Comma)
+StructField : token(Symbol) option(token(Colon) Expression) token(Comma))
*/
static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
Token *first_token = &pc->tokens->at(*token_index);
@@ -2792,16 +2659,16 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
ast_buf_from_token(pc, token, &field_node->data.struct_field.name);
- Token *colon_tok = &pc->tokens->at(*token_index);
- if (colon_tok->id == TokenIdColon) {
+ Token *expr_or_comma = &pc->tokens->at(*token_index);
+ if (expr_or_comma->id == TokenIdComma) {
+ field_node->data.struct_field.type = ast_create_void_type_node(pc, expr_or_comma);
*token_index += 1;
- field_node->data.struct_field.type = ast_parse_type(pc, token_index);
} else {
- field_node->data.struct_field.type = ast_create_void_type_node(pc, colon_tok);
+ ast_eat_token(pc, token_index, TokenIdColon);
+ field_node->data.struct_field.type = ast_parse_expression(pc, token_index, true);
+ ast_eat_token(pc, token_index, TokenIdComma);
}
- ast_eat_token(pc, token_index, TokenIdComma);
-
node->data.struct_decl.fields.append(field_node);
} else {
ast_invalid_token_error(pc, token);
src/tokenizer.cpp
@@ -207,8 +207,6 @@ static void end_token(Tokenize *t) {
t->cur_tok->id = TokenIdKeywordConst;
} else if (mem_eql_str(token_mem, token_len, "extern")) {
t->cur_tok->id = TokenIdKeywordExtern;
- } else if (mem_eql_str(token_mem, token_len, "unreachable")) {
- t->cur_tok->id = TokenIdKeywordUnreachable;
} else if (mem_eql_str(token_mem, token_len, "pub")) {
t->cur_tok->id = TokenIdKeywordPub;
} else if (mem_eql_str(token_mem, token_len, "export")) {
@@ -217,8 +215,6 @@ static void end_token(Tokenize *t) {
t->cur_tok->id = TokenIdKeywordAs;
} else if (mem_eql_str(token_mem, token_len, "use")) {
t->cur_tok->id = TokenIdKeywordUse;
- } else if (mem_eql_str(token_mem, token_len, "void")) {
- t->cur_tok->id = TokenIdKeywordVoid;
} 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")) {
@@ -553,6 +549,11 @@ void tokenize(Buf *buf, Tokenization *out) {
end_token(&t);
t.state = TokenizeStateStart;
break;
+ case '>':
+ t.cur_tok->id = TokenIdFatArrow;
+ end_token(&t);
+ t.state = TokenizeStateStart;
+ break;
default:
t.pos -= 1;
end_token(&t);
@@ -1009,12 +1010,10 @@ static const char * token_name(Token *token) {
case TokenIdKeywordVar: return "Var";
case TokenIdKeywordReturn: return "Return";
case TokenIdKeywordExtern: return "Extern";
- case TokenIdKeywordUnreachable: return "Unreachable";
case TokenIdKeywordPub: return "Pub";
case TokenIdKeywordExport: return "Export";
case TokenIdKeywordAs: return "As";
case TokenIdKeywordUse: return "Use";
- case TokenIdKeywordVoid: return "Void";
case TokenIdKeywordTrue: return "True";
case TokenIdKeywordFalse: return "False";
case TokenIdKeywordIf: return "If";
@@ -1044,6 +1043,7 @@ static const char * token_name(Token *token) {
case TokenIdPlus: return "Plus";
case TokenIdColon: return "Colon";
case TokenIdArrow: return "Arrow";
+ case TokenIdFatArrow: return "FatArrow";
case TokenIdDash: return "Dash";
case TokenIdNumberSign: return "NumberSign";
case TokenIdBinOr: return "BinOr";
src/tokenizer.hpp
@@ -18,12 +18,10 @@ enum TokenId {
TokenIdKeywordVar,
TokenIdKeywordConst,
TokenIdKeywordExtern,
- TokenIdKeywordUnreachable,
TokenIdKeywordPub,
TokenIdKeywordExport,
TokenIdKeywordAs,
TokenIdKeywordUse,
- TokenIdKeywordVoid,
TokenIdKeywordTrue,
TokenIdKeywordFalse,
TokenIdKeywordIf,
@@ -53,6 +51,7 @@ enum TokenId {
TokenIdPlus,
TokenIdColon,
TokenIdArrow,
+ TokenIdFatArrow,
TokenIdDash,
TokenIdNumberSign,
TokenIdBoolOr,
std/bootstrap.zig
@@ -3,10 +3,35 @@ use "syscall.zig";
// The compiler treats this file special by implicitly importing the function `main`
// from the root source file.
+var env: &&u8;
+
#attribute("naked")
-export fn _start() -> unreachable {
- const argc = asm("mov (%%rsp), %[argc]" : [argc] "=r" (-> isize));
- const argv = asm("lea 0x8(%%rsp), %[argv]" : [argv] "=r" (-> &&u8));
- const env = asm("lea 0x10(%%rsp,%%rdi,8), %[env]" : [env] "=r" (-> &&u8));
- exit(main(argc, argv, env))
+export fn _start() unreachable => {
+ const argc = asm("mov (%%rsp), %[argc]": [argc] "=r" (-> isize));
+ const argv = asm("lea 0x8(%%rsp), %[argv]": [argv] "=r" (-> &&u8));
+ env = asm("lea 0x10(%%rsp,%%rdi,8), %[env]": [env] "=r" (-> &&u8));
+
+ exit(main(argc, argv, env));
+
+/*
+ var args = @alloca_array([]u8, argc);
+ var i : @typeof(argc) = 0;
+ // TODO for in loop over the array
+ while (i < argc) {
+ const ptr = argv[i];
+ args[i] = ptr[0...strlen(ptr)];
+ i += 1;
+ }
+ exit(main(args))
+ */
+}
+
+/*
+fn strlen(ptr: &u8) isize => {
+ var count: isize = 0;
+ while (ptr[count]) {
+ count += 1;
+ }
+ return count;
}
+*/
std/builtin.zig
@@ -1,8 +1,8 @@
// These functions are provided when not linking against libc because LLVM
// sometimes generates code that calls them.
-export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
- var index : #typeof(n) = 0;
+export fn memset(dest: &u8, c: u8, n: usize) &u8 => {
+ var index : @typeof(n) = 0;
while (index != n) {
dest[index] = c;
index += 1;
@@ -10,8 +10,8 @@ export fn memset(dest: &u8, c: u8, n: usize) -> &u8 {
return dest;
}
-export fn memcpy(dest: &noalias u8, src: &const noalias u8, n: usize) -> &u8 {
- var index : #typeof(n) = 0;
+export fn memcpy(noalias dest: &u8, noalias src: &const u8, n: usize) &u8 => {
+ var index : @typeof(n) = 0;
while (index != n) {
dest[index] = src[index];
index += 1;
std/rand.zig
@@ -4,13 +4,13 @@ const ARRAY_SIZE : u16 = 624;
/// Use `rand_init` to initialize this state.
pub struct Rand {
array: [ARRAY_SIZE]u32,
- index: #typeof(ARRAY_SIZE),
+ index: @typeof(ARRAY_SIZE),
/// Initialize random state with the given seed.
- pub fn init(r: &Rand, seed: u32) {
+ pub fn init(r: &Rand, seed: u32) => {
r.index = 0;
r.array[0] = seed;
- var i : #typeof(ARRAY_SIZE) = 1;
+ var i : @typeof(ARRAY_SIZE) = 1;
while (i < ARRAY_SIZE) {
const prev_value : u64 = r.array[i - 1];
r.array[i] = ((prev_value ^ (prev_value << 30)) * 0x6c078965 + i) as u32;
@@ -20,7 +20,7 @@ pub struct Rand {
/// Get 32 bits of randomness.
- pub fn get_u32(r: &Rand) -> u32 {
+ pub fn get_u32(r: &Rand) u32 => {
if (r.index == 0) {
r.generate_numbers();
}
@@ -37,13 +37,13 @@ pub struct Rand {
}
/// Fill `buf` with randomness.
- pub fn get_bytes(r: &Rand, buf: []u8) {
+ pub fn get_bytes(r: &Rand, buf: []u8) => {
var bytes_left = r.get_bytes_aligned(buf);
if (bytes_left > 0) {
- var rand_val_array : [#sizeof(u32)]u8;
- *(rand_val_array.ptr as &u32) = r.get_u32();
+ var rand_val_array : [@sizeof(u32)]u8;
+ *(rand_val_array.ptr as (&u32)) = r.get_u32();
while (bytes_left > 0) {
- buf[buf.len - bytes_left] = rand_val_array[#sizeof(u32) - bytes_left];
+ buf[buf.len - bytes_left] = rand_val_array[@sizeof(u32) - bytes_left];
bytes_left -= 1;
}
}
@@ -51,23 +51,23 @@ pub struct Rand {
/// Get a random unsigned integer with even distribution between `start`
/// inclusive and `end` exclusive.
- pub fn range_u64(r: &Rand, start: u64, end: u64) -> u64 {
+ pub fn range_u64(r: &Rand, start: u64, end: u64) u64 => {
const range = end - start;
- const leftover = #max_value(u64) % range;
- const upper_bound = #max_value(u64) - leftover;
- var rand_val_array : [#sizeof(u64)]u8;
+ const leftover = @max_value(u64) % range;
+ const upper_bound = @max_value(u64) - leftover;
+ var rand_val_array : [@sizeof(u64)]u8;
while (true) {
r.get_bytes_aligned(rand_val_array);
- const rand_val = *(rand_val_array.ptr as &u64);
+ const rand_val = *(rand_val_array.ptr as (&u64));
if (rand_val < upper_bound) {
return start + (rand_val % range);
}
}
}
- fn generate_numbers(r: &Rand) {
- var i : #typeof(ARRAY_SIZE) = 0;
+ fn generate_numbers(r: &Rand) => {
+ var i : @typeof(ARRAY_SIZE) = 0;
while (i < ARRAY_SIZE) {
const y : u32 = (r.array[i] & 0x80000000) + (r.array[(i + 1) % ARRAY_SIZE] & 0x7fffffff);
const untempered : u32 = r.array[(i + 397) % ARRAY_SIZE] ^ (y >> 1);
@@ -82,11 +82,11 @@ pub struct Rand {
}
// does not populate the remaining (buf.len % 4) bytes
- fn get_bytes_aligned(r: &Rand, buf: []u8) -> usize {
+ fn get_bytes_aligned(r: &Rand, buf: []u8) usize => {
var bytes_left = buf.len;
while (bytes_left >= 4) {
- *(&buf[buf.len - bytes_left] as &u32) = r.get_u32();
- bytes_left -= #sizeof(u32);
+ *(&buf[buf.len - bytes_left] as (&u32)) = r.get_u32();
+ bytes_left -= @sizeof(u32);
}
return bytes_left;
}
std/std.zig
@@ -5,25 +5,25 @@ pub const stdout_fileno : isize = 1;
pub const stderr_fileno : isize = 2;
// TODO error handling
-pub fn os_get_random_bytes(buf: &u8, count: usize) -> isize {
+pub fn os_get_random_bytes(buf: &u8, count: usize) isize => {
getrandom(buf, count, 0)
}
// TODO error handling
// TODO handle buffering and flushing (mutex protected)
-pub fn print_str(str: []const u8) -> isize {
+pub fn print_str(str: []const u8) isize => {
fprint_str(stdout_fileno, str)
}
// TODO error handling
// TODO handle buffering and flushing (mutex protected)
-pub fn fprint_str(fd: isize, str: []const u8) -> isize {
+pub fn fprint_str(fd: isize, str: []const u8) isize => {
write(fd, str.ptr, str.len)
}
// TODO handle buffering and flushing (mutex protected)
// TODO error handling
-pub fn print_u64(x: u64) -> isize {
+pub fn print_u64(x: u64) isize => {
var buf: [max_u64_base10_digits]u8;
const len = buf_print_u64(buf, x);
return write(stdout_fileno, buf.ptr, len);
@@ -31,14 +31,14 @@ pub fn print_u64(x: u64) -> isize {
// TODO handle buffering and flushing (mutex protected)
// TODO error handling
-pub fn print_i64(x: i64) -> isize {
+pub fn print_i64(x: i64) isize => {
var buf: [max_u64_base10_digits]u8;
const len = buf_print_i64(buf, x);
return write(stdout_fileno, buf.ptr, len);
}
// TODO error handling
-pub fn readline(buf: []u8, out_len: &usize) -> bool {
+pub fn readline(buf: []u8, out_len: &usize) bool => {
const amt_read = read(stdin_fileno, buf.ptr, buf.len);
if (amt_read < 0) {
return true;
@@ -48,10 +48,10 @@ pub fn readline(buf: []u8, out_len: &usize) -> bool {
}
// TODO return ?u64 when we support returning struct byval
-pub fn parse_u64(buf: []u8, radix: u8, result: &u64) -> bool {
+pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {
var x : u64 = 0;
- var i : #typeof(buf.len) = 0;
+ var i : @typeof(buf.len) = 0;
while (i < buf.len) {
const c = buf[i];
const digit = char_to_digit(c);
@@ -77,7 +77,7 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) -> bool {
return false;
}
-fn char_to_digit(c: u8) -> u8 {
+fn char_to_digit(c: u8) u8 => {
if ('0' <= c && c <= '9') {
c - '0'
} else if ('A' <= c && c <= 'Z') {
@@ -85,13 +85,13 @@ fn char_to_digit(c: u8) -> u8 {
} else if ('a' <= c && c <= 'z') {
c - 'a' + 10
} else {
- #max_value(u8)
+ @max_value(u8)
}
}
const max_u64_base10_digits: usize = 20;
-fn buf_print_i64(out_buf: []u8, x: i64) -> usize {
+fn buf_print_i64(out_buf: []u8, x: i64) usize => {
if (x < 0) {
out_buf[0] = '-';
return 1 + buf_print_u64(out_buf[1...], ((-(x + 1)) as u64) + 1);
@@ -100,7 +100,7 @@ fn buf_print_i64(out_buf: []u8, x: i64) -> usize {
}
}
-fn buf_print_u64(out_buf: []u8, x: u64) -> usize {
+fn buf_print_u64(out_buf: []u8, x: u64) usize => {
var buf: [max_u64_base10_digits]u8;
var a = x;
var index = buf.len;
std/syscall.zig
@@ -3,34 +3,34 @@ const SYS_write : usize = 1;
const SYS_exit : usize = 60;
const SYS_getrandom : usize = 318;
-fn syscall1(number: usize, arg1: usize) -> usize {
+fn syscall1(number: usize, arg1: usize) usize => {
asm volatile ("syscall"
: [ret] "={rax}" (-> usize)
: [number] "{rax}" (number), [arg1] "{rdi}" (arg1)
: "rcx", "r11")
}
-fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
+fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize => {
asm volatile ("syscall"
: [ret] "={rax}" (-> usize)
: [number] "{rax}" (number), [arg1] "{rdi}" (arg1), [arg2] "{rsi}" (arg2), [arg3] "{rdx}" (arg3)
: "rcx", "r11")
}
-pub fn read(fd: isize, buf: &u8, count: usize) -> isize {
+pub fn read(fd: isize, buf: &u8, count: usize) isize => {
syscall3(SYS_read, fd as usize, buf as usize, count) as isize
}
-pub fn write(fd: isize, buf: &const u8, count: usize) -> isize {
+pub fn write(fd: isize, buf: &const u8, count: usize) isize => {
syscall3(SYS_write, fd as usize, buf as usize, count) as isize
}
-pub fn exit(status: i32) -> unreachable {
+pub fn exit(status: i32) unreachable => {
syscall1(SYS_exit, status as usize);
- unreachable
+ unreachable{}
}
-pub fn getrandom(buf: &u8, count: usize, flags: u32) -> isize {
+pub fn getrandom(buf: &u8, count: usize, flags: u32) isize => {
syscall3(SYS_getrandom, buf as usize, count, flags as usize) as isize
}
test/run_tests.cpp
@@ -96,50 +96,50 @@ static TestCase *add_compile_fail_case(const char *case_name, const char *source
static void add_compiling_test_cases(void) {
add_simple_case("hello world with libc", R"SOURCE(
- #link("c")
- extern {
- fn puts(s: &const u8) -> i32;
- }
+#link("c")
+extern {
+ fn puts(s: &const u8) i32;
+}
- export fn main(argc: i32, argv: &&u8, env: &&u8) -> i32 {
- puts(c"Hello, world!");
- return 0;
- }
+export fn main(argc: i32, argv: &&u8, env: &&u8) i32 => {
+ puts(c"Hello, world!");
+ return 0;
+}
)SOURCE", "Hello, world!\n");
add_simple_case("function call", R"SOURCE(
- use "std.zig";
- use "syscall.zig";
+use "std.zig";
+use "syscall.zig";
- fn empty_function_1() {}
- fn empty_function_2() { return; }
+fn empty_function_1() => {}
+fn empty_function_2() => { return; }
- pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
- empty_function_1();
- empty_function_2();
- this_is_a_function();
- }
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
+ empty_function_1();
+ empty_function_2();
+ this_is_a_function();
+}
- fn this_is_a_function() -> unreachable {
- print_str("OK\n");
- exit(0);
- }
+fn this_is_a_function() unreachable => {
+ print_str("OK\n");
+ exit(0);
+}
)SOURCE", "OK\n");
add_simple_case("comments", R"SOURCE(
- use "std.zig";
-
- /**
- * multi line doc comment
- */
- fn another_function() {}
-
- /// this is a documentation comment
- /// doc comment line 2
- pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
- print_str(/* mid-line comment /* nested */ */ "OK\n");
- return 0;
- }
+use "std.zig";
+
+/**
+ * multi line doc comment
+ */
+fn another_function() => {}
+
+/// this is a documentation comment
+/// doc comment line 2
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
+ print_str(/* mid-line comment /* nested */ */ "OK\n");
+ return 0;
+}
)SOURCE", "OK\n");
{
@@ -147,13 +147,13 @@ static void add_compiling_test_cases(void) {
use "std.zig";
use "foo.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
private_function();
print_str("OK 2\n");
return 0;
}
-fn private_function() {
+fn private_function() => {
print_text();
}
)SOURCE", "OK 1\nOK 2\n");
@@ -163,11 +163,11 @@ use "std.zig";
// purposefully conflicting function with main.zig
// but it's private so it should be OK
-fn private_function() {
+fn private_function() => {
print_str("OK 1\n");
}
-pub fn print_text() {
+pub fn print_text() => {
private_function();
}
)SOURCE");
@@ -178,7 +178,7 @@ pub fn print_text() {
use "foo.zig";
use "bar.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
foo_function();
bar_function();
return 0;
@@ -187,7 +187,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
add_source_file(tc, "foo.zig", R"SOURCE(
use "std.zig";
-pub fn foo_function() {
+pub fn foo_function() => {
print_str("OK\n");
}
)SOURCE");
@@ -196,7 +196,7 @@ pub fn foo_function() {
use "other.zig";
use "std.zig";
-pub fn bar_function() {
+pub fn bar_function() => {
if (foo_function()) {
print_str("OK\n");
}
@@ -204,7 +204,7 @@ pub fn bar_function() {
)SOURCE");
add_source_file(tc, "other.zig", R"SOURCE(
-pub fn foo_function() -> bool {
+pub fn foo_function() bool => {
// this one conflicts with the one from foo
return true;
}
@@ -212,65 +212,65 @@ pub fn foo_function() -> bool {
}
add_simple_case("if statements", R"SOURCE(
- use "std.zig";
+use "std.zig";
- pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
- if (1 != 0) {
- print_str("1 is true\n");
- } else {
- print_str("1 is false\n");
- }
- if (0 != 0) {
- print_str("0 is true\n");
- } else if (1 - 1 != 0) {
- print_str("1 - 1 is true\n");
- }
- if (!(0 != 0)) {
- print_str("!0 is true\n");
- }
- return 0;
- }
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
+ if (1 != 0) {
+ print_str("1 is true\n");
+ } else {
+ print_str("1 is false\n");
+ }
+ if (0 != 0) {
+ print_str("0 is true\n");
+ } else if (1 - 1 != 0) {
+ print_str("1 - 1 is true\n");
+ }
+ if (!(0 != 0)) {
+ print_str("!0 is true\n");
+ }
+ return 0;
+}
)SOURCE", "1 is true\n!0 is true\n");
add_simple_case("params", R"SOURCE(
- use "std.zig";
+use "std.zig";
- fn add(a: i32, b: i32) -> i32 {
- a + b
- }
+fn add(a: i32, b: i32) i32 => {
+ a + b
+}
- pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
- if (add(22, 11) == 33) {
- print_str("pass\n");
- }
- return 0;
- }
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
+ if (add(22, 11) == 33) {
+ print_str("pass\n");
+ }
+ return 0;
+}
)SOURCE", "pass\n");
add_simple_case("goto", R"SOURCE(
- use "std.zig";
+use "std.zig";
- fn loop(a : i32) {
- if (a == 0) {
- goto done;
- }
- print_str("loop\n");
- loop(a - 1);
+fn loop(a : i32) => {
+ if (a == 0) {
+ goto done;
+ }
+ print_str("loop\n");
+ loop(a - 1);
- done:
- return;
- }
+done:
+ return;
+}
- pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
- loop(3);
- return 0;
- }
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
+ loop(3);
+ return 0;
+}
)SOURCE", "loop\nloop\nloop\n");
add_simple_case("local variables", R"SOURCE(
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
const a : i32 = 1;
const b = 2 as i32;
if (a + b == 3) {
@@ -283,7 +283,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
add_simple_case("bool literals", R"SOURCE(
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
if (true) { print_str("OK 1\n"); }
if (false) { print_str("BAD 1\n"); }
if (!true) { print_str("BAD 2\n"); }
@@ -295,7 +295,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
add_simple_case("separate block scopes", R"SOURCE(
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
if (true) {
const no_conflict : i32 = 5;
if (no_conflict == 5) { print_str("OK 1\n"); }
@@ -313,12 +313,12 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
add_simple_case("void parameters", R"SOURCE(
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
- void_fun(1, void, 2);
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
+ void_fun(1, void{}, 2);
return 0;
}
-fn void_fun(a : i32, b : void, c : i32) {
+fn void_fun(a : i32, b : void, c : i32) => {
const v = b;
const vv : void = if (a == 1) {v} else {};
if (a + c == 3) { print_str("OK\n"); }
@@ -333,16 +333,16 @@ struct Foo {
b : i32,
c : void,
}
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
const foo = Foo {
- .a = void,
+ .a = void{},
.b = 1,
- .c = void,
+ .c = void{},
};
if (foo.b != 1) {
print_str("BAD\n");
}
- if (#sizeof(Foo) != 4) {
+ if (@sizeof(Foo) != 4) {
print_str("BAD\n");
}
print_str("OK\n");
@@ -354,7 +354,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
add_simple_case("mutable local variables", R"SOURCE(
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
var zero : i32 = 0;
if (zero == 0) { print_str("zero\n"); }
@@ -374,7 +374,7 @@ done:
add_simple_case("arrays", R"SOURCE(
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
var array : [5]u32;
var i : u32 = 0;
@@ -401,7 +401,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
return 0;
}
-fn get_array_len(a: []u32) -> usize {
+fn get_array_len(a: []u32) usize => {
a.len
}
)SOURCE", "OK\n");
@@ -410,7 +410,7 @@ fn get_array_len(a: []u32) -> usize {
add_simple_case("hello world without libc", R"SOURCE(
use "std.zig";
-pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
+pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
print_str("Hello, world!\n");
return 0;
}
@@ -420,7 +420,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("a + b + c", R"SOURCE(
use "std.zig";
-pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
+pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
if (false || false || false) { print_str("BAD 1\n"); }
if (true && true && false) { print_str("BAD 2\n"); }
if (1 | 2 | 4 != 7) { print_str("BAD 3\n"); }
@@ -442,7 +442,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("short circuit", R"SOURCE(
use "std.zig";
-pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
+pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
if (true || { print_str("BAD 1\n"); false }) {
print_str("OK 1\n");
}
@@ -465,7 +465,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("modify operators", R"SOURCE(
use "std.zig";
-pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
+pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
var i : i32 = 0;
i += 5; if (i != 5) { print_str("BAD +=\n"); }
i -= 2; if (i != 3) { print_str("BAD -=\n"); }
@@ -488,10 +488,10 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("number literals", R"SOURCE(
#link("c")
extern {
- fn printf(__format: &const u8, ...) -> i32;
+ fn printf(__format: &const u8, ...) i32;
}
-export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
+export fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
printf(c"\n");
printf(c"0: %llu\n",
@@ -617,9 +617,9 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("structs", R"SOURCE(
use "std.zig";
-pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
+pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
var foo : Foo;
- @memset(&foo, 0, #sizeof(Foo));
+ @memset(&foo, 0, @sizeof(Foo));
foo.a += 1;
foo.b = foo.a == 1;
test_foo(foo);
@@ -638,12 +638,12 @@ struct Foo {
b : bool,
c : f32,
}
-fn test_foo(foo : Foo) {
+fn test_foo(foo : Foo) => {
if (!foo.b) {
print_str("BAD\n");
}
}
-fn test_mutation(foo : &Foo) {
+fn test_mutation(foo : &Foo) => {
foo.c = 100;
}
struct Node {
@@ -654,7 +654,7 @@ struct Node {
struct Val {
x: i32,
}
-fn test_point_to_self() {
+fn test_point_to_self() => {
var root : Node;
root.val.x = 1;
@@ -668,7 +668,7 @@ fn test_point_to_self() {
print_str("BAD\n");
}
}
-fn test_byval_assign() {
+fn test_byval_assign() => {
var foo1 : Foo;
var foo2 : Foo;
@@ -680,7 +680,7 @@ fn test_byval_assign() {
if (foo2.a != 1234) { print_str("BAD - byval assignment failed\n"); }
}
-fn test_initializer() {
+fn test_initializer() => {
const val = Val { .x = 42 };
if (val.x != 42) { print_str("BAD\n"); }
}
@@ -692,7 +692,7 @@ use "std.zig";
const g1 : i32 = 1233 + 1;
var g2 : i32 = 0;
-pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
+pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
if (g2 != 0) { print_str("BAD\n"); }
g2 = g1;
if (g2 != 1234) { print_str("BAD\n"); }
@@ -703,7 +703,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("while loop", R"SOURCE(
use "std.zig";
-pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
+pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
var i : i32 = 0;
while (i < 4) {
print_str("loop\n");
@@ -711,7 +711,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
}
return f();
}
-fn f() -> i32 {
+fn f() i32 => {
while (true) {
return 0;
}
@@ -720,7 +720,7 @@ fn f() -> i32 {
add_simple_case("continue and break", R"SOURCE(
use "std.zig";
-pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
+pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
var i : i32 = 0;
while (true) {
print_str("loop\n");
@@ -736,7 +736,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("maybe type", R"SOURCE(
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
const x : ?bool = true;
if (const y ?= x) {
@@ -759,7 +759,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
const final_x : ?i32 = 13;
- const num = final_x ?? unreachable;
+ const num = final_x ?? unreachable{};
if (num != 13) {
print_str("BAD\n");
@@ -771,26 +771,26 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
add_simple_case("implicit cast after unreachable", R"SOURCE(
use "std.zig";
-pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
+pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
const x = outer();
if (x == 1234) {
print_str("OK\n");
}
return 0;
}
-fn inner() -> i32 { 1234 }
-fn outer() -> isize {
+fn inner() i32 => { 1234 }
+fn outer() isize => {
return inner();
}
)SOURCE", "OK\n");
- add_simple_case("#sizeof() and #typeof()", R"SOURCE(
+ add_simple_case("@sizeof() and @typeof()", R"SOURCE(
use "std.zig";
const x: u16 = 13;
-const z: #typeof(x) = 19;
-pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
- const y: #typeof(x) = 120;
- print_u64(#sizeof(#typeof(y)));
+const z: @typeof(x) = 19;
+pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
+ const y: @typeof(x) = 120;
+ print_u64(@sizeof(@typeof(y)));
print_str("\n");
return 0;
}
@@ -800,11 +800,11 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
use "std.zig";
struct Rand {
seed: u32,
- pub fn get_seed(r: Rand) -> u32 {
+ pub fn get_seed(r: Rand) u32 => {
r.seed
}
}
-pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
+pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
const r = Rand {.seed = 1234};
if (r.get_seed() != 1234) {
print_str("BAD seed\n");
@@ -817,7 +817,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("pointer dereferencing", R"SOURCE(
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
var x = 3 as i32;
const y = &x;
@@ -839,9 +839,9 @@ use "std.zig";
const ARRAY_SIZE : u8 = 20;
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
var array : [ARRAY_SIZE]u8;
- print_u64(#sizeof(#typeof(array)));
+ print_u64(@sizeof(@typeof(array)));
print_str("\n");
return 0;
}
@@ -849,69 +849,69 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
add_simple_case("#min_value() and #max_value()", R"SOURCE(
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
print_str("max u8: ");
- print_u64(#max_value(u8));
+ print_u64(@max_value(u8));
print_str("\n");
print_str("max u16: ");
- print_u64(#max_value(u16));
+ print_u64(@max_value(u16));
print_str("\n");
print_str("max u32: ");
- print_u64(#max_value(u32));
+ print_u64(@max_value(u32));
print_str("\n");
print_str("max u64: ");
- print_u64(#max_value(u64));
+ print_u64(@max_value(u64));
print_str("\n");
print_str("max i8: ");
- print_i64(#max_value(i8));
+ print_i64(@max_value(i8));
print_str("\n");
print_str("max i16: ");
- print_i64(#max_value(i16));
+ print_i64(@max_value(i16));
print_str("\n");
print_str("max i32: ");
- print_i64(#max_value(i32));
+ print_i64(@max_value(i32));
print_str("\n");
print_str("max i64: ");
- print_i64(#max_value(i64));
+ print_i64(@max_value(i64));
print_str("\n");
print_str("min u8: ");
- print_u64(#min_value(u8));
+ print_u64(@min_value(u8));
print_str("\n");
print_str("min u16: ");
- print_u64(#min_value(u16));
+ print_u64(@min_value(u16));
print_str("\n");
print_str("min u32: ");
- print_u64(#min_value(u32));
+ print_u64(@min_value(u32));
print_str("\n");
print_str("min u64: ");
- print_u64(#min_value(u64));
+ print_u64(@min_value(u64));
print_str("\n");
print_str("min i8: ");
- print_i64(#min_value(i8));
+ print_i64(@min_value(i8));
print_str("\n");
print_str("min i16: ");
- print_i64(#min_value(i16));
+ print_i64(@min_value(i16));
print_str("\n");
print_str("min i32: ");
- print_i64(#min_value(i32));
+ print_i64(@min_value(i32));
print_str("\n");
print_str("min i64: ");
- print_i64(#min_value(i64));
+ print_i64(@min_value(i64));
print_str("\n");
return 0;
@@ -937,7 +937,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
add_simple_case("slicing", R"SOURCE(
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
var array : [20]i32;
array[5] = 1234;
@@ -965,13 +965,13 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
add_simple_case("else if expression", R"SOURCE(
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
if (f(1) == 1) {
print_str("OK\n");
}
return 0;
}
-fn f(c: u8) -> u8 {
+fn f(c: u8) u8 => {
if (c == 0) {
0
} else if (c == 1) {
@@ -984,7 +984,7 @@ fn f(c: u8) -> u8 {
add_simple_case("overflow intrinsics", R"SOURCE(
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
var result: u8;
if (!@add_with_overflow_u8(250, 100, &result)) {
print_str("BAD\n");
@@ -1002,7 +1002,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
add_simple_case("memcpy and memset intrinsics", R"SOURCE(
use "std.zig";
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
var foo : [20]u8;
var bar : [20]u8;
@@ -1020,13 +1020,13 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
add_simple_case("order-independent declarations", R"SOURCE(
use "std.zig";
-const z : #typeof(stdin_fileno) = 0;
-const x : #typeof(y) = 1234;
+const z : @typeof(stdin_fileno) = 0;
+const x : @typeof(y) = 1234;
const y : u16 = 5678;
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
print_ok(x)
}
-fn print_ok(val: #typeof(x)) -> #typeof(foo) {
+fn print_ok(val: @typeof(x)) @typeof(foo) => {
print_str("OK\n");
return 0;
}
@@ -1054,7 +1054,7 @@ enum Bar {
D,
}
-pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
+pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
const foo1 = Foo.One(13);
const foo2 = Foo.Two(Point { .x = 1234, .y = 5678, });
const bar = Bar.B;
@@ -1063,18 +1063,18 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
print_str("BAD\n");
}
- if (#value_count(Foo) != 3) {
+ if (@value_count(Foo) != 3) {
print_str("BAD\n");
}
- if (#value_count(Bar) != 4) {
+ if (@value_count(Bar) != 4) {
print_str("BAD\n");
}
- if (#sizeof(Foo) != 17) {
+ if (@sizeof(Foo) != 17) {
print_str("BAD\n");
}
- if (#sizeof(Bar) != 1) {
+ if (@sizeof(Bar) != 1) {
print_str("BAD\n");
}
@@ -1090,8 +1090,8 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
static void add_compile_failure_test_cases(void) {
add_compile_fail_case("multiple function definitions", R"SOURCE(
-fn a() {}
-fn a() {}
+fn a() => {}
+fn a() => {}
)SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'a'");
add_compile_fail_case("bad directive", R"SOURCE(
@@ -1100,46 +1100,46 @@ extern {
fn b();
}
#bogus2("")
-fn a() {}
+fn a() => {}
)SOURCE", 2, ".tmp_source.zig:2:1: error: invalid directive: 'bogus1'",
".tmp_source.zig:6:1: error: invalid directive: 'bogus2'");
add_compile_fail_case("unreachable with return", R"SOURCE(
-fn a() -> unreachable {return;}
+fn a() unreachable => {return;}
)SOURCE", 1, ".tmp_source.zig:2:24: error: expected type 'unreachable', got 'void'");
add_compile_fail_case("control reaches end of non-void function", R"SOURCE(
-fn a() -> i32 {}
+fn a() i32 => {}
)SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got 'void'");
add_compile_fail_case("undefined function call", R"SOURCE(
-fn a() {
+fn a() => {
b();
}
)SOURCE", 1, ".tmp_source.zig:3:5: error: undefined function: 'b'");
add_compile_fail_case("wrong number of arguments", R"SOURCE(
-fn a() {
+fn a() => {
b(1);
}
-fn b(a: i32, b: i32, c: i32) { }
+fn b(a: i32, b: i32, c: i32) => { }
)SOURCE", 1, ".tmp_source.zig:3:6: error: expected 3 arguments, got 1");
add_compile_fail_case("invalid type", R"SOURCE(
-fn a() -> bogus {}
- )SOURCE", 1, ".tmp_source.zig:2:11: error: invalid type name: 'bogus'");
+fn a() bogus => {}
+ )SOURCE", 1, ".tmp_source.zig:2:8: error: use of undeclared identifier 'bogus'");
add_compile_fail_case("pointer to unreachable", R"SOURCE(
-fn a() -> &unreachable {}
- )SOURCE", 1, ".tmp_source.zig:2:11: error: pointer to unreachable not allowed");
+fn a() &unreachable => {}
+ )SOURCE", 1, ".tmp_source.zig:2:8: error: pointer to unreachable not allowed");
add_compile_fail_case("unreachable code", R"SOURCE(
-fn a() {
+fn a() => {
return;
b();
}
-fn b() {}
+fn b() => {}
)SOURCE", 1, ".tmp_source.zig:4:5: error: unreachable code");
add_compile_fail_case("bad version string", R"SOURCE(
@@ -1152,7 +1152,7 @@ use "bogus-does-not-exist.zig";
)SOURCE", 1, ".tmp_source.zig:2:1: error: unable to find 'bogus-does-not-exist.zig'");
add_compile_fail_case("undeclared identifier", R"SOURCE(
-fn a() {
+fn a() => {
b +
c
}
@@ -1161,99 +1161,99 @@ fn a() {
".tmp_source.zig:4:5: error: use of undeclared identifier 'c'");
add_compile_fail_case("goto cause unreachable code", R"SOURCE(
-fn a() {
+fn a() => {
goto done;
b();
done:
return;
}
-fn b() {}
+fn b() => {}
)SOURCE", 1, ".tmp_source.zig:4:5: error: unreachable code");
add_compile_fail_case("parameter redeclaration", R"SOURCE(
-fn f(a : i32, a : i32) {
+fn f(a : i32, a : i32) => {
}
)SOURCE", 1, ".tmp_source.zig:2:1: error: redeclaration of parameter 'a'");
add_compile_fail_case("local variable redeclaration", R"SOURCE(
-fn f() {
+fn f() => {
const a : i32 = 0;
const a = 0;
}
)SOURCE", 1, ".tmp_source.zig:4:5: error: redeclaration of variable 'a'");
add_compile_fail_case("local variable redeclares parameter", R"SOURCE(
-fn f(a : i32) {
+fn f(a : i32) => {
const a = 0;
}
)SOURCE", 1, ".tmp_source.zig:3:5: error: redeclaration of variable 'a'");
add_compile_fail_case("variable has wrong type", R"SOURCE(
-fn f() -> i32 {
+fn f() i32 => {
const a = c"a";
a
}
)SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got '&const u8'");
add_compile_fail_case("if condition is bool, not int", R"SOURCE(
-fn f() {
+fn f() => {
if (0) {}
}
)SOURCE", 1, ".tmp_source.zig:3:9: error: expected type 'bool', got '(u8 literal)'");
add_compile_fail_case("assign unreachable", R"SOURCE(
-fn f() {
+fn f() => {
const a = return;
}
)SOURCE", 1, ".tmp_source.zig:3:5: error: variable initialization is unreachable");
add_compile_fail_case("unreachable variable", R"SOURCE(
-fn f() {
+fn f() => {
const a : unreachable = return;
}
)SOURCE", 1, ".tmp_source.zig:3:15: error: variable of type 'unreachable' not allowed");
add_compile_fail_case("unreachable parameter", R"SOURCE(
-fn f(a : unreachable) {}
+fn f(a : unreachable) => {}
)SOURCE", 1, ".tmp_source.zig:2:10: error: parameter of type 'unreachable' not allowed");
add_compile_fail_case("exporting a void parameter", R"SOURCE(
-export fn f(a : void) {}
+export fn f(a : void) => {}
)SOURCE", 1, ".tmp_source.zig:2:17: error: parameter of type 'void' not allowed on exported functions");
add_compile_fail_case("unused label", R"SOURCE(
-fn f() {
+fn f() => {
a_label:
}
)SOURCE", 1, ".tmp_source.zig:3:1: error: label 'a_label' defined but not used");
add_compile_fail_case("bad assignment target", R"SOURCE(
-fn f() {
+fn f() => {
3 = 3;
}
)SOURCE", 1, ".tmp_source.zig:3:5: error: invalid assignment target");
add_compile_fail_case("assign to constant variable", R"SOURCE(
-fn f() {
+fn f() => {
const a = 3;
a = 4;
}
)SOURCE", 1, ".tmp_source.zig:4:5: error: cannot assign to constant");
add_compile_fail_case("use of undeclared identifier", R"SOURCE(
-fn f() {
+fn f() => {
b = 3;
}
)SOURCE", 1, ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'");
add_compile_fail_case("const is a statement, not an expression", R"SOURCE(
-fn f() {
+fn f() => {
(const a = 0);
}
)SOURCE", 1, ".tmp_source.zig:3:6: error: invalid token: 'const'");
add_compile_fail_case("array access errors", R"SOURCE(
-fn f() {
+fn f() => {
var bad : bool;
i[i] = i[i];
bad[bad] = bad[bad];
@@ -1268,19 +1268,19 @@ fn f() {
".tmp_source.zig:5:20: error: expected type 'usize', got 'bool'");
add_compile_fail_case("variadic functions only allowed in extern", R"SOURCE(
-fn f(...) {}
+fn f(...) => {}
)SOURCE", 1, ".tmp_source.zig:2:1: error: variadic arguments only allowed in extern functions");
add_compile_fail_case("write to const global variable", R"SOURCE(
const x : i32 = 99;
-fn f() {
+fn f() => {
x = 1;
}
)SOURCE", 1, ".tmp_source.zig:4:5: error: cannot assign to constant");
add_compile_fail_case("missing else clause", R"SOURCE(
-fn f() {
+fn f() => {
const x : i32 = if (true) { 1 };
const y = if (true) { 1 as i32 };
}
@@ -1299,7 +1299,7 @@ struct C { a : A, }
add_compile_fail_case("invalid struct field", R"SOURCE(
struct A { x : i32, }
-fn f() {
+fn f() => {
var a : A;
a.foo = 1;
const y = a.bar;
@@ -1315,7 +1315,7 @@ struct A { y : i32, }
add_compile_fail_case("byvalue struct on exported functions", R"SOURCE(
struct A { x : i32, }
-export fn f(a : A) {}
+export fn f(a : A) => {}
)SOURCE", 1, ".tmp_source.zig:3:13: error: byvalue struct parameters not yet supported on exported functions");
add_compile_fail_case("duplicate field in struct value expression", R"SOURCE(
@@ -1324,7 +1324,7 @@ struct A {
y : i32,
z : i32,
}
-fn f() {
+fn f() => {
const a = A {
.z = 1,
.y = 2,
@@ -1340,13 +1340,13 @@ struct A {
y : i32,
z : i32,
}
-fn f() {
+fn f() => {
const a = A {
.z = 4,
.y = 2,
};
}
- )SOURCE", 1, ".tmp_source.zig:8:15: error: missing field: 'x'");
+ )SOURCE", 1, ".tmp_source.zig:8:17: error: missing field: 'x'");
add_compile_fail_case("invalid field in struct value expression", R"SOURCE(
struct A {
@@ -1354,7 +1354,7 @@ struct A {
y : i32,
z : i32,
}
-fn f() {
+fn f() => {
const a = A {
.z = 4,
.y = 2,
@@ -1364,37 +1364,37 @@ fn f() {
)SOURCE", 1, ".tmp_source.zig:11:9: error: no member named 'foo' in 'A'");
add_compile_fail_case("invalid break expression", R"SOURCE(
-fn f() {
+fn f() => {
break;
}
)SOURCE", 1, ".tmp_source.zig:3:5: error: 'break' expression outside loop");
add_compile_fail_case("invalid continue expression", R"SOURCE(
-fn f() {
+fn f() => {
continue;
}
)SOURCE", 1, ".tmp_source.zig:3:5: error: 'continue' expression outside loop");
add_compile_fail_case("invalid maybe type", R"SOURCE(
-fn f() {
+fn f() => {
if (const x ?= true) { }
}
)SOURCE", 1, ".tmp_source.zig:3:20: error: expected maybe type");
add_compile_fail_case("cast unreachable", R"SOURCE(
-fn f() -> i32 {
+fn f() i32 => {
(return 1) as i32
}
)SOURCE", 1, ".tmp_source.zig:3:16: error: invalid cast from type 'unreachable' to 'i32'");
- add_compile_fail_case("invalid compiler fn", R"SOURCE(
-fn f() -> #bogus(foo) {
+ add_compile_fail_case("invalid builtin fn", R"SOURCE(
+fn f() @bogus(foo) => {
}
- )SOURCE", 1, ".tmp_source.zig:2:11: error: invalid compiler function: 'bogus'");
+ )SOURCE", 1, ".tmp_source.zig:2:8: error: invalid builtin function: 'bogus'");
add_compile_fail_case("top level decl dependency loop", R"SOURCE(
-const a : #typeof(b) = 0;
-const b : #typeof(a) = 0;
+const a : @typeof(b) = 0;
+const b : @typeof(a) = 0;
)SOURCE", 1, ".tmp_source.zig:3:19: error: use of undeclared identifier 'a'");
}