authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-20 18:18:50-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-20 18:18:50-07:00
log5e212db29cf9e2c06aba363736ffb965e631aa2d
tree2ec22f86549bca4cceb423bb3b66aa796754951f
parent82d1b51b1d34a0c1b21ec2aaae70051379b37f43

parsing error value decls and error value literals

and return with '?' or '%' prefix

10 files changed, 548 insertions(+), 88 deletions(-)

doc/langref.md+23-10
...@@ -5,9 +5,11 @@...@@ -5,9 +5,11 @@
5```5```
6Root : many(TopLevelDecl) "EOF"6Root : many(TopLevelDecl) "EOF"
77
8TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration8TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration | ErrorValueDecl
99
10VariableDeclaration : option(FnVisibleMod) ("var" | "const") "symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression))10ErrorValueDecl : option(FnVisibleMod) "%." "Symbol"
11
12VariableDeclaration : option(FnVisibleMod) ("var" | "const") "Symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression))
1113
12ContainerDecl : many(Directive) option(FnVisibleMod) ("struct" | "enum") "Symbol" "{" many(StructMember) "}"14ContainerDecl : many(Directive) option(FnVisibleMod) ("struct" | "enum") "Symbol" "{" many(StructMember) "}"
1315
...@@ -77,7 +79,7 @@ ForExpression : "for" "(" "Symbol" "," Expression option("," "Symbol") ")" Expre...@@ -77,7 +79,7 @@ ForExpression : "for" "(" "Symbol" "," Expression option("," "Symbol") ")" Expre
7779
78BoolOrExpression : BoolAndExpression "||" BoolOrExpression | BoolAndExpression80BoolOrExpression : BoolAndExpression "||" BoolOrExpression | BoolAndExpression
7981
80ReturnExpression : "return" option(Expression)82ReturnExpression : option("%" | "?") "return" option(Expression)
8183
82IfExpression : IfVarExpression | IfBoolExpression84IfExpression : IfVarExpression | IfBoolExpression
8385
...@@ -133,7 +135,7 @@ StructLiteralField : "." "Symbol" "=" Expression...@@ -133,7 +135,7 @@ StructLiteralField : "." "Symbol" "=" Expression
133135
134PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?"136PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?"
135137
136PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression138PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("%." "Symbol")
137139
138ArrayType : "[" option(Expression) "]" option("const") PrefixOpExpression140ArrayType : "[" option(Expression) "]" option("const") PrefixOpExpression
139141
...@@ -148,7 +150,7 @@ KeywordLiteral : "true" | "false" | "null" | "break" | "continue"...@@ -148,7 +150,7 @@ KeywordLiteral : "true" | "false" | "null" | "break" | "continue"
148150
149```151```
150x() x[] x.y152x() x[] x.y
151!x -x ~x *x &x ?x153!x -x ~x *x &x ?x %x
152x{}154x{}
153* / %155* / %
154+ -156+ -
...@@ -199,12 +201,20 @@ c_ulonglong unsigned long long for ABI compatibility with C...@@ -199,12 +201,20 @@ c_ulonglong unsigned long long for ABI compatibility with C
199### Boolean Type201### Boolean Type
200The boolean type has the name `bool` and represents either true or false.202The boolean type has the name `bool` and represents either true or false.
201203
202### Function Types204### Function Type
203TODO205TODO
204206
205### Array Types207### Fixed-Size Array Type
206TODO208
207Also, are there slices?209Example: The string `"aoeu"` has type `[4]u8`.
210
211The size is known at compile time and is part of the type.
212
213### Slice Type
214
215A slice can be obtained with the slicing syntax: `array[start...end]`
216
217Example: `"aoeu"[0...2]` has type `[]u8`.
208218
209### Struct Types219### Struct Types
210TODO220TODO
...@@ -213,10 +223,13 @@ TODO...@@ -213,10 +223,13 @@ TODO
213TODO223TODO
214224
215### Unreachable Type225### Unreachable Type
226
216The unreachable type has the name `unreachable`. TODO explanation227The unreachable type has the name `unreachable`. TODO explanation
217228
218### Void Type229### Void Type
219The void type has the name `void`. TODO explanation230
231The void type has the name `void`. void types are zero bits and are omitted
232from codegen.
220233
221234
222## Expressions235## Expressions
example/cat/main.zig+17-17
...@@ -3,50 +3,50 @@ export executable "cat";...@@ -3,50 +3,50 @@ export executable "cat";
3import "std.zig";3import "std.zig";
44
5// Things to do to make this work:5// Things to do to make this work:
6// * isize instead of usize for things
7// * var args printing6// * var args printing
8// * update std API7// * %void type
9// * !void type
10// * defer8// * defer
11// * !return9// * %return
12// * !! operator10// * %% operator
13// * make main return !void11// * make main return %void
14// * how to reference error values (!void).Invalid ? !Invalid ?12// * how to reference error values %.Invalid
15// * ~ is bool not, not !
16// * cast err type to string13// * cast err type to string
14// * update std API
15
16pub %.Invalid;
1717
18pub fn main(args: [][]u8) !void => {18pub fn main(args: [][]u8) %void => {
19 const exe = args[0];19 const exe = args[0];
20 var catted_anything = false;20 var catted_anything = false;
21 for (arg, args[1...]) {21 for (arg, args[1...]) {
22 if (arg == "-") {22 if (arg == "-") {
23 catted_anything = true;23 catted_anything = true;
24 !return cat_stream(stdin);24 %return cat_stream(stdin);
25 } else if (arg[0] == '-') {25 } else if (arg[0] == '-') {
26 return usage(exe);26 return usage(exe);
27 } else {27 } else {
28 var is: InputStream;28 var is: InputStream;
29 is.open(arg, OpenReadOnly) !! (err) => {29 is.open(arg, OpenReadOnly) %% (err) => {
30 stderr.print("Unable to open file: {}", ([]u8])(err));30 stderr.print("Unable to open file: {}", ([]u8])(err));
31 return err;31 return err;
32 }32 }
33 defer is.close();33 defer is.close();
3434
35 catted_anything = true;35 catted_anything = true;
36 !return cat_stream(is);36 %return cat_stream(is);
37 }37 }
38 }38 }
39 if (~catted_anything) {39 if (!catted_anything) {
40 !return cat_stream(stdin)40 %return cat_stream(stdin)
41 }41 }
42}42}
4343
44fn usage(exe: []u8) !void => {44fn usage(exe: []u8) %void => {
45 stderr.print("Usage: {} [FILE]...\n", exe);45 stderr.print("Usage: {} [FILE]...\n", exe);
46 return !Invalid;46 return %.Invalid;
47}47}
4848
49fn cat_stream(is: InputStream) !void => {49fn cat_stream(is: InputStream) %void => {
50 var buf: [1024 * 4]u8;50 var buf: [1024 * 4]u8;
5151
52 while (true) {52 while (true) {
example/hello_world/hello.zig+1
...@@ -3,6 +3,7 @@ export executable "hello";...@@ -3,6 +3,7 @@ export executable "hello";
3import "std.zig";3import "std.zig";
44
5pub fn main(args: [][]u8) i32 => {5pub fn main(args: [][]u8) i32 => {
6 //stderr.print_str("Hello, world!\n");
6 print_str("Hello, world!\n");7 print_str("Hello, world!\n");
7 return 0;8 return 0;
8}9}
src/all_types.hpp+35
...@@ -129,10 +129,12 @@ enum NodeType {...@@ -129,10 +129,12 @@ enum NodeType {
129 NodeTypeDirective,129 NodeTypeDirective,
130 NodeTypeReturnExpr,130 NodeTypeReturnExpr,
131 NodeTypeVariableDeclaration,131 NodeTypeVariableDeclaration,
132 NodeTypeErrorValueDecl,
132 NodeTypeBinOpExpr,133 NodeTypeBinOpExpr,
133 NodeTypeNumberLiteral,134 NodeTypeNumberLiteral,
134 NodeTypeStringLiteral,135 NodeTypeStringLiteral,
135 NodeTypeCharLiteral,136 NodeTypeCharLiteral,
137 NodeTypeErrorLiteral,
136 NodeTypeSymbol,138 NodeTypeSymbol,
137 NodeTypePrefixOpExpr,139 NodeTypePrefixOpExpr,
138 NodeTypeFnCallExpr,140 NodeTypeFnCallExpr,
...@@ -222,7 +224,14 @@ struct AstNodeBlock {...@@ -222,7 +224,14 @@ struct AstNodeBlock {
222 Expr resolved_expr;224 Expr resolved_expr;
223};225};
224226
227enum ReturnKind {
228 ReturnKindUnconditional,
229 ReturnKindMaybe,
230 ReturnKindError,
231};
232
225struct AstNodeReturnExpr {233struct AstNodeReturnExpr {
234 ReturnKind kind;
226 // might be null in case of return void;235 // might be null in case of return void;
227 AstNode *expr;236 AstNode *expr;
228237
...@@ -243,6 +252,14 @@ struct AstNodeVariableDeclaration {...@@ -243,6 +252,14 @@ struct AstNodeVariableDeclaration {
243 Expr resolved_expr;252 Expr resolved_expr;
244};253};
245254
255struct AstNodeErrorValueDecl {
256 VisibMod visib_mod;
257 Buf name;
258
259 // populated by semantic analyzer
260 TopLevelDecl top_level_decl;
261};
262
246enum BinOpType {263enum BinOpType {
247 BinOpTypeInvalid,264 BinOpTypeInvalid,
248 BinOpTypeAssign,265 BinOpTypeAssign,
...@@ -358,6 +375,7 @@ enum PrefixOp {...@@ -358,6 +375,7 @@ enum PrefixOp {
358 PrefixOpConstAddressOf,375 PrefixOpConstAddressOf,
359 PrefixOpDereference,376 PrefixOpDereference,
360 PrefixOpMaybe,377 PrefixOpMaybe,
378 PrefixOpError,
361};379};
362380
363struct AstNodePrefixOpExpr {381struct AstNodePrefixOpExpr {
...@@ -564,6 +582,14 @@ struct AstNodeNumberLiteral {...@@ -564,6 +582,14 @@ struct AstNodeNumberLiteral {
564 Expr resolved_expr;582 Expr resolved_expr;
565};583};
566584
585struct AstNodeErrorLiteral {
586 Buf symbol;
587
588 // populated by semantic analyzer
589 NumLitCodeGen codegen;
590 Expr resolved_expr;
591};
592
567struct AstNodeStructValueField {593struct AstNodeStructValueField {
568 Buf name;594 Buf name;
569 AstNode *expr;595 AstNode *expr;
...@@ -644,6 +670,7 @@ struct AstNode {...@@ -644,6 +670,7 @@ struct AstNode {
644 AstNodeBlock block;670 AstNodeBlock block;
645 AstNodeReturnExpr return_expr;671 AstNodeReturnExpr return_expr;
646 AstNodeVariableDeclaration variable_declaration;672 AstNodeVariableDeclaration variable_declaration;
673 AstNodeErrorValueDecl error_value_decl;
647 AstNodeBinOpExpr bin_op_expr;674 AstNodeBinOpExpr bin_op_expr;
648 AstNodeExternBlock extern_block;675 AstNodeExternBlock extern_block;
649 AstNodeDirective directive;676 AstNodeDirective directive;
...@@ -668,6 +695,7 @@ struct AstNode {...@@ -668,6 +695,7 @@ struct AstNode {
668 AstNodeStringLiteral string_literal;695 AstNodeStringLiteral string_literal;
669 AstNodeCharLiteral char_literal;696 AstNodeCharLiteral char_literal;
670 AstNodeNumberLiteral number_literal;697 AstNodeNumberLiteral number_literal;
698 AstNodeErrorLiteral error_literal;
671 AstNodeContainerInitExpr container_init_expr;699 AstNodeContainerInitExpr container_init_expr;
672 AstNodeStructValueField struct_val_field;700 AstNodeStructValueField struct_val_field;
673 AstNodeNullLiteral null_literal;701 AstNodeNullLiteral null_literal;
...@@ -738,6 +766,10 @@ struct TypeTableEntryMaybe {...@@ -738,6 +766,10 @@ struct TypeTableEntryMaybe {
738 TypeTableEntry *child_type;766 TypeTableEntry *child_type;
739};767};
740768
769struct TypeTableEntryError {
770 TypeTableEntry *child_type;
771};
772
741struct TypeTableEntryEnum {773struct TypeTableEntryEnum {
742 AstNode *decl_node;774 AstNode *decl_node;
743 uint32_t field_count;775 uint32_t field_count;
...@@ -778,6 +810,7 @@ enum TypeTableEntryId {...@@ -778,6 +810,7 @@ enum TypeTableEntryId {
778 TypeTableEntryIdStruct,810 TypeTableEntryIdStruct,
779 TypeTableEntryIdNumberLiteral,811 TypeTableEntryIdNumberLiteral,
780 TypeTableEntryIdMaybe,812 TypeTableEntryIdMaybe,
813 TypeTableEntryIdError,
781 TypeTableEntryIdEnum,814 TypeTableEntryIdEnum,
782 TypeTableEntryIdFn,815 TypeTableEntryIdFn,
783};816};
...@@ -799,6 +832,7 @@ struct TypeTableEntry {...@@ -799,6 +832,7 @@ struct TypeTableEntry {
799 TypeTableEntryStruct structure;832 TypeTableEntryStruct structure;
800 TypeTableEntryNumLit num_lit;833 TypeTableEntryNumLit num_lit;
801 TypeTableEntryMaybe maybe;834 TypeTableEntryMaybe maybe;
835 TypeTableEntryError error;
802 TypeTableEntryEnum enumeration;836 TypeTableEntryEnum enumeration;
803 TypeTableEntryFn fn;837 TypeTableEntryFn fn;
804 } data;838 } data;
...@@ -808,6 +842,7 @@ struct TypeTableEntry {...@@ -808,6 +842,7 @@ struct TypeTableEntry {
808 TypeTableEntry *unknown_size_array_parent[2];842 TypeTableEntry *unknown_size_array_parent[2];
809 HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;843 HashMap<uint64_t, TypeTableEntry *, uint64_hash, uint64_eq> arrays_by_size;
810 TypeTableEntry *maybe_parent;844 TypeTableEntry *maybe_parent;
845 TypeTableEntry *error_parent;
811};846};
812847
813struct ImporterInfo {848struct ImporterInfo {
src/analyze.cpp+148-24
...@@ -43,7 +43,9 @@ static AstNode *first_executing_node(AstNode *node) {...@@ -43,7 +43,9 @@ static AstNode *first_executing_node(AstNode *node) {
43 case NodeTypeDirective:43 case NodeTypeDirective:
44 case NodeTypeReturnExpr:44 case NodeTypeReturnExpr:
45 case NodeTypeVariableDeclaration:45 case NodeTypeVariableDeclaration:
46 case NodeTypeErrorValueDecl:
46 case NodeTypeNumberLiteral:47 case NodeTypeNumberLiteral:
48 case NodeTypeErrorLiteral:
47 case NodeTypeStringLiteral:49 case NodeTypeStringLiteral:
48 case NodeTypeCharLiteral:50 case NodeTypeCharLiteral:
49 case NodeTypeSymbol:51 case NodeTypeSymbol:
...@@ -104,6 +106,7 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {...@@ -104,6 +106,7 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
104 case TypeTableEntryIdNumberLiteral:106 case TypeTableEntryIdNumberLiteral:
105 case TypeTableEntryIdMaybe:107 case TypeTableEntryIdMaybe:
106 case TypeTableEntryIdFn:108 case TypeTableEntryIdFn:
109 case TypeTableEntryIdError:
107 // nothing to init110 // nothing to init
108 break;111 break;
109 case TypeTableEntryIdStruct:112 case TypeTableEntryIdStruct:
...@@ -215,6 +218,57 @@ static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {...@@ -215,6 +218,57 @@ static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
215 }218 }
216}219}
217220
221static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
222 if (child_type->error_parent) {
223 return child_type->error_parent;
224 } else {
225 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdError);
226 zig_panic("TODO get_error_type");
227 // create a struct with a boolean whether this is the null value
228 assert(child_type->type_ref);
229 LLVMTypeRef elem_types[] = {
230 child_type->type_ref,
231 LLVMInt1Type(),
232 };
233 entry->type_ref = LLVMStructType(elem_types, 2, false);
234 buf_resize(&entry->name, 0);
235 buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
236 entry->size_in_bits = child_type->size_in_bits + 8;
237 entry->align_in_bits = child_type->align_in_bits;
238 assert(child_type->di_type);
239
240
241 LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
242 LLVMZigDIFile *di_file = nullptr;
243 unsigned line = 0;
244 entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder,
245 LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name),
246 compile_unit_scope, di_file, line);
247
248 LLVMZigDIType *di_element_types[] = {
249 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
250 "val", di_file, line, child_type->size_in_bits, child_type->align_in_bits, 0, 0,
251 child_type->di_type),
252 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
253 "maybe", di_file, line, 8, 8, 8, 0,
254 child_type->di_type),
255 };
256 LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
257 compile_unit_scope,
258 buf_ptr(&entry->name),
259 di_file, line, entry->size_in_bits, entry->align_in_bits, 0,
260 nullptr, di_element_types, 2, 0, nullptr, "");
261
262 LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
263 entry->di_type = replacement_di_type;
264
265 entry->data.maybe.child_type = child_type;
266
267 child_type->maybe_parent = entry;
268 return entry;
269 }
270}
271
218static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size)272static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size)
219{273{
220 auto existing_entry = child_type->arrays_by_size.maybe_get(array_size);274 auto existing_entry = child_type->arrays_by_size.maybe_get(array_size);
...@@ -922,6 +976,11 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode...@@ -922,6 +976,11 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
922 g->global_vars.append(var);976 g->global_vars.append(var);
923 break;977 break;
924 }978 }
979 case NodeTypeErrorValueDecl:
980 {
981 zig_panic("TODO resolve_top_level_decl NodeTypeErrorValueDecl");
982 break;
983 }
925 case NodeTypeUse:984 case NodeTypeUse:
926 // nothing to do here985 // nothing to do here
927 break;986 break;
...@@ -937,6 +996,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode...@@ -937,6 +996,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
937 case NodeTypeArrayAccessExpr:996 case NodeTypeArrayAccessExpr:
938 case NodeTypeSliceExpr:997 case NodeTypeSliceExpr:
939 case NodeTypeNumberLiteral:998 case NodeTypeNumberLiteral:
999 case NodeTypeErrorLiteral:
940 case NodeTypeStringLiteral:1000 case NodeTypeStringLiteral:
941 case NodeTypeCharLiteral:1001 case NodeTypeCharLiteral:
942 case NodeTypeBoolLiteral:1002 case NodeTypeBoolLiteral:
...@@ -1005,6 +1065,7 @@ static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type,...@@ -1005,6 +1065,7 @@ static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type,
1005 case TypeTableEntryIdEnum:1065 case TypeTableEntryIdEnum:
1006 case TypeTableEntryIdMetaType:1066 case TypeTableEntryIdMetaType:
1007 case TypeTableEntryIdFn:1067 case TypeTableEntryIdFn:
1068 case TypeTableEntryIdError:
1008 return false;1069 return false;
1009 case TypeTableEntryIdInt:1070 case TypeTableEntryIdInt:
1010 if (is_num_lit_unsigned(num_lit)) {1071 if (is_num_lit_unsigned(num_lit)) {
...@@ -2263,6 +2324,12 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry...@@ -2263,6 +2324,12 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry
2263 }2324 }
2264}2325}
22652326
2327static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
2328 BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
2329{
2330 zig_panic("TODO analyze_error_literal_expr");
2331}
2332
2266static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,2333static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
2267 TypeTableEntry *expected_type, AstNode *node)2334 TypeTableEntry *expected_type, AstNode *node)
2268{2335{
...@@ -3021,7 +3088,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo...@@ -3021,7 +3088,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
3021 if (meta_type->id == TypeTableEntryIdInvalid) {3088 if (meta_type->id == TypeTableEntryIdInvalid) {
3022 return g->builtin_types.entry_invalid;3089 return g->builtin_types.entry_invalid;
3023 } else if (meta_type->id == TypeTableEntryIdUnreachable) {3090 } else if (meta_type->id == TypeTableEntryIdUnreachable) {
3024 add_node_error(g, node, buf_create_from_str("maybe unreachable type not allowed"));3091 add_node_error(g, node, buf_create_from_str("unable to wrap unreachable in maybe type"));
3025 return g->builtin_types.entry_invalid;3092 return g->builtin_types.entry_invalid;
3026 } else {3093 } else {
3027 return resolve_expr_const_val_as_type(g, node, get_maybe_type(g, meta_type));3094 return resolve_expr_const_val_as_type(g, node, get_maybe_type(g, meta_type));
...@@ -3034,6 +3101,31 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo...@@ -3034,6 +3101,31 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
3034 return get_maybe_type(g, type_entry);3101 return get_maybe_type(g, type_entry);
3035 }3102 }
3036 }3103 }
3104 case PrefixOpError:
3105 {
3106 TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr, expr_node);
3107
3108 if (type_entry->id == TypeTableEntryIdInvalid) {
3109 return type_entry;
3110 } else if (type_entry->id == TypeTableEntryIdMetaType) {
3111 TypeTableEntry *meta_type = resolve_type(g, expr_node);
3112 if (meta_type->id == TypeTableEntryIdInvalid) {
3113 return meta_type;
3114 } else if (meta_type->id == TypeTableEntryIdUnreachable) {
3115 add_node_error(g, node, buf_create_from_str("unable to wrap unreachable in error type"));
3116 return g->builtin_types.entry_invalid;
3117 } else {
3118 return resolve_expr_const_val_as_type(g, node, get_error_type(g, meta_type));
3119 }
3120 } else if (type_entry->id == TypeTableEntryIdUnreachable) {
3121 add_node_error(g, expr_node, buf_sprintf("unable to wrap unreachable in error type"));
3122 return g->builtin_types.entry_invalid;
3123 } else {
3124 // TODO eval const expr
3125 return get_error_type(g, type_entry);
3126 }
3127
3128 }
3037 }3129 }
3038 zig_unreachable();3130 zig_unreachable();
3039}3131}
...@@ -3099,6 +3191,37 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,...@@ -3099,6 +3191,37 @@ static TypeTableEntry *analyze_switch_expr(CodeGen *g, ImportTableEntry *import,
3099 return expected_type;3191 return expected_type;
3100}3192}
31013193
3194static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
3195 TypeTableEntry *expected_type, AstNode *node)
3196{
3197 if (!context->fn_entry) {
3198 add_node_error(g, node, buf_sprintf("return expression outside function definition"));
3199 return g->builtin_types.entry_invalid;
3200 }
3201
3202 if (node->data.return_expr.kind != ReturnKindUnconditional) {
3203 zig_panic("TODO analyze_return_expr conditional");
3204 }
3205
3206 TypeTableEntry *expected_return_type = get_return_type(context);
3207 TypeTableEntry *actual_return_type;
3208 if (node->data.return_expr.expr) {
3209 actual_return_type = analyze_expression(g, import, context, expected_return_type, node->data.return_expr.expr);
3210 } else {
3211 actual_return_type = g->builtin_types.entry_void;
3212 }
3213
3214 if (actual_return_type->id == TypeTableEntryIdUnreachable) {
3215 // "return exit(0)" should just be "exit(0)".
3216 add_node_error(g, node, buf_sprintf("returning is unreachable"));
3217 actual_return_type = g->builtin_types.entry_invalid;
3218 }
3219
3220 resolve_type_compatibility(g, context, node, expected_return_type, actual_return_type);
3221
3222 return g->builtin_types.entry_unreachable;
3223}
3224
3102static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,3225static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
3103 TypeTableEntry *expected_type, AstNode *node)3226 TypeTableEntry *expected_type, AstNode *node)
3104{3227{
...@@ -3140,29 +3263,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -3140,29 +3263,8 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
3140 }3263 }
31413264
3142 case NodeTypeReturnExpr:3265 case NodeTypeReturnExpr:
3143 {3266 return_type = analyze_return_expr(g, import, context, expected_type, node);
3144 if (context->fn_entry) {3267 break;
3145 TypeTableEntry *expected_return_type = get_return_type(context);
3146 TypeTableEntry *actual_return_type;
3147 if (node->data.return_expr.expr) {
3148 actual_return_type = analyze_expression(g, import, context, expected_return_type, node->data.return_expr.expr);
3149 } else {
3150 actual_return_type = g->builtin_types.entry_void;
3151 }
3152
3153 if (actual_return_type->id == TypeTableEntryIdUnreachable) {
3154 // "return exit(0)" should just be "exit(0)".
3155 add_node_error(g, node, buf_sprintf("returning is unreachable"));
3156 actual_return_type = g->builtin_types.entry_invalid;
3157 }
3158
3159 resolve_type_compatibility(g, context, node, expected_return_type, actual_return_type);
3160 } else {
3161 add_node_error(g, node, buf_sprintf("return expression outside function definition"));
3162 }
3163 return_type = g->builtin_types.entry_unreachable;
3164 break;
3165 }
3166 case NodeTypeVariableDeclaration:3268 case NodeTypeVariableDeclaration:
3167 analyze_variable_declaration(g, import, context, expected_type, node);3269 analyze_variable_declaration(g, import, context, expected_type, node);
3168 return_type = g->builtin_types.entry_void;3270 return_type = g->builtin_types.entry_void;
...@@ -3236,6 +3338,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -3236,6 +3338,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
3236 case NodeTypeNumberLiteral:3338 case NodeTypeNumberLiteral:
3237 return_type = analyze_number_literal_expr(g, import, context, expected_type, node);3339 return_type = analyze_number_literal_expr(g, import, context, expected_type, node);
3238 break;3340 break;
3341 case NodeTypeErrorLiteral:
3342 return_type = analyze_error_literal_expr(g, import, context, expected_type, node);
3343 break;
3239 case NodeTypeStringLiteral:3344 case NodeTypeStringLiteral:
3240 if (node->data.string_literal.c) {3345 if (node->data.string_literal.c) {
3241 return_type = g->builtin_types.entry_c_string_literal;3346 return_type = g->builtin_types.entry_c_string_literal;
...@@ -3294,6 +3399,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -3294,6 +3399,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
3294 case NodeTypeStructDecl:3399 case NodeTypeStructDecl:
3295 case NodeTypeStructField:3400 case NodeTypeStructField:
3296 case NodeTypeStructValueField:3401 case NodeTypeStructValueField:
3402 case NodeTypeErrorValueDecl:
3297 zig_unreachable();3403 zig_unreachable();
3298 }3404 }
3299 assert(return_type);3405 assert(return_type);
...@@ -3411,6 +3517,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode...@@ -3411,6 +3517,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
3411 case NodeTypeExternBlock:3517 case NodeTypeExternBlock:
3412 case NodeTypeUse:3518 case NodeTypeUse:
3413 case NodeTypeVariableDeclaration:3519 case NodeTypeVariableDeclaration:
3520 case NodeTypeErrorValueDecl:
3414 // already took care of these3521 // already took care of these
3415 break;3522 break;
3416 case NodeTypeDirective:3523 case NodeTypeDirective:
...@@ -3425,6 +3532,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode...@@ -3425,6 +3532,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
3425 case NodeTypeArrayAccessExpr:3532 case NodeTypeArrayAccessExpr:
3426 case NodeTypeSliceExpr:3533 case NodeTypeSliceExpr:
3427 case NodeTypeNumberLiteral:3534 case NodeTypeNumberLiteral:
3535 case NodeTypeErrorLiteral:
3428 case NodeTypeStringLiteral:3536 case NodeTypeStringLiteral:
3429 case NodeTypeCharLiteral:3537 case NodeTypeCharLiteral:
3430 case NodeTypeBoolLiteral:3538 case NodeTypeBoolLiteral:
...@@ -3457,6 +3565,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode...@@ -3457,6 +3565,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
3457{3565{
3458 switch (node->type) {3566 switch (node->type) {
3459 case NodeTypeNumberLiteral:3567 case NodeTypeNumberLiteral:
3568 case NodeTypeErrorLiteral:
3460 case NodeTypeStringLiteral:3569 case NodeTypeStringLiteral:
3461 case NodeTypeCharLiteral:3570 case NodeTypeCharLiteral:
3462 case NodeTypeBoolLiteral:3571 case NodeTypeBoolLiteral:
...@@ -3464,6 +3573,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode...@@ -3464,6 +3573,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
3464 case NodeTypeGoto:3573 case NodeTypeGoto:
3465 case NodeTypeBreak:3574 case NodeTypeBreak:
3466 case NodeTypeContinue:3575 case NodeTypeContinue:
3576 case NodeTypeErrorValueDecl:
3467 // no dependencies on other top level declarations3577 // no dependencies on other top level declarations
3468 break;3578 break;
3469 case NodeTypeSymbol:3579 case NodeTypeSymbol:
...@@ -3758,6 +3868,10 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast...@@ -3758,6 +3868,10 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
3758 case NodeTypeUse:3868 case NodeTypeUse:
3759 // already taken care of3869 // already taken care of
3760 break;3870 break;
3871 case NodeTypeErrorValueDecl:
3872 // error value declarations do not depend on other top level decls
3873 resolve_top_level_decl(g, import, node);
3874 break;
3761 case NodeTypeDirective:3875 case NodeTypeDirective:
3762 case NodeTypeParamDecl:3876 case NodeTypeParamDecl:
3763 case NodeTypeFnDecl:3877 case NodeTypeFnDecl:
...@@ -3769,6 +3883,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast...@@ -3769,6 +3883,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
3769 case NodeTypeArrayAccessExpr:3883 case NodeTypeArrayAccessExpr:
3770 case NodeTypeSliceExpr:3884 case NodeTypeSliceExpr:
3771 case NodeTypeNumberLiteral:3885 case NodeTypeNumberLiteral:
3886 case NodeTypeErrorLiteral:
3772 case NodeTypeStringLiteral:3887 case NodeTypeStringLiteral:
3773 case NodeTypeCharLiteral:3888 case NodeTypeCharLiteral:
3774 case NodeTypeBoolLiteral:3889 case NodeTypeBoolLiteral:
...@@ -3966,6 +4081,8 @@ Expr *get_resolved_expr(AstNode *node) {...@@ -3966,6 +4081,8 @@ Expr *get_resolved_expr(AstNode *node) {
3966 return &node->data.container_init_expr.resolved_expr;4081 return &node->data.container_init_expr.resolved_expr;
3967 case NodeTypeNumberLiteral:4082 case NodeTypeNumberLiteral:
3968 return &node->data.number_literal.resolved_expr;4083 return &node->data.number_literal.resolved_expr;
4084 case NodeTypeErrorLiteral:
4085 return &node->data.error_literal.resolved_expr;
3969 case NodeTypeStringLiteral:4086 case NodeTypeStringLiteral:
3970 return &node->data.string_literal.resolved_expr;4087 return &node->data.string_literal.resolved_expr;
3971 case NodeTypeBlock:4088 case NodeTypeBlock:
...@@ -4006,6 +4123,7 @@ Expr *get_resolved_expr(AstNode *node) {...@@ -4006,6 +4123,7 @@ Expr *get_resolved_expr(AstNode *node) {
4006 case NodeTypeStructDecl:4123 case NodeTypeStructDecl:
4007 case NodeTypeStructField:4124 case NodeTypeStructField:
4008 case NodeTypeStructValueField:4125 case NodeTypeStructValueField:
4126 case NodeTypeErrorValueDecl:
4009 zig_unreachable();4127 zig_unreachable();
4010 }4128 }
4011 zig_unreachable();4129 zig_unreachable();
...@@ -4015,6 +4133,8 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {...@@ -4015,6 +4133,8 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
4015 switch (node->type) {4133 switch (node->type) {
4016 case NodeTypeNumberLiteral:4134 case NodeTypeNumberLiteral:
4017 return &node->data.number_literal.codegen;4135 return &node->data.number_literal.codegen;
4136 case NodeTypeErrorLiteral:
4137 return &node->data.error_literal.codegen;
4018 case NodeTypeFnCallExpr:4138 case NodeTypeFnCallExpr:
4019 return &node->data.fn_call_expr.resolved_num_lit;4139 return &node->data.fn_call_expr.resolved_num_lit;
4020 case NodeTypeReturnExpr:4140 case NodeTypeReturnExpr:
...@@ -4056,6 +4176,7 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {...@@ -4056,6 +4176,7 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
4056 case NodeTypeStructField:4176 case NodeTypeStructField:
4057 case NodeTypeStructValueField:4177 case NodeTypeStructValueField:
4058 case NodeTypeArrayType:4178 case NodeTypeArrayType:
4179 case NodeTypeErrorValueDecl:
4059 zig_unreachable();4180 zig_unreachable();
4060 }4181 }
4061 zig_unreachable();4182 zig_unreachable();
...@@ -4069,7 +4190,10 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {...@@ -4069,7 +4190,10 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
4069 return &node->data.fn_proto.top_level_decl;4190 return &node->data.fn_proto.top_level_decl;
4070 case NodeTypeStructDecl:4191 case NodeTypeStructDecl:
4071 return &node->data.struct_decl.top_level_decl;4192 return &node->data.struct_decl.top_level_decl;
4193 case NodeTypeErrorValueDecl:
4194 return &node->data.error_value_decl.top_level_decl;
4072 case NodeTypeNumberLiteral:4195 case NodeTypeNumberLiteral:
4196 case NodeTypeErrorLiteral:
4073 case NodeTypeReturnExpr:4197 case NodeTypeReturnExpr:
4074 case NodeTypeBinOpExpr:4198 case NodeTypeBinOpExpr:
4075 case NodeTypePrefixOpExpr:4199 case NodeTypePrefixOpExpr:
src/codegen.cpp+13
...@@ -829,6 +829,10 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {...@@ -829,6 +829,10 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
829 {829 {
830 zig_panic("TODO codegen PrefixOpMaybe");830 zig_panic("TODO codegen PrefixOpMaybe");
831 }831 }
832 case PrefixOpError:
833 {
834 zig_panic("TODO codegen PrefixOpError");
835 }
832 }836 }
833 zig_unreachable();837 zig_unreachable();
834}838}
...@@ -1937,6 +1941,12 @@ static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {...@@ -1937,6 +1941,12 @@ static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
1937 return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal);1941 return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal);
1938}1942}
19391943
1944static LLVMValueRef gen_error_literal(CodeGen *g, AstNode *node) {
1945 assert(node->type == NodeTypeErrorLiteral);
1946
1947 zig_panic("TODO gen_error_literal");
1948}
1949
1940static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {1950static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) {
1941 assert(node->type == NodeTypeSymbol);1951 assert(node->type == NodeTypeSymbol);
1942 VariableTableEntry *variable = node->data.symbol_expr.variable;1952 VariableTableEntry *variable = node->data.symbol_expr.variable;
...@@ -2070,6 +2080,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -2070,6 +2080,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
2070 return gen_asm_expr(g, node);2080 return gen_asm_expr(g, node);
2071 case NodeTypeNumberLiteral:2081 case NodeTypeNumberLiteral:
2072 return gen_number_literal(g, node);2082 return gen_number_literal(g, node);
2083 case NodeTypeErrorLiteral:
2084 return gen_error_literal(g, node);
2073 case NodeTypeStringLiteral:2085 case NodeTypeStringLiteral:
2074 {2086 {
2075 Buf *str = &node->data.string_literal.buf;2087 Buf *str = &node->data.string_literal.buf;
...@@ -2125,6 +2137,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -2125,6 +2137,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
2125 case NodeTypeArrayType:2137 case NodeTypeArrayType:
2126 case NodeTypeSwitchProng:2138 case NodeTypeSwitchProng:
2127 case NodeTypeSwitchRange:2139 case NodeTypeSwitchRange:
2140 case NodeTypeErrorValueDecl:
2128 zig_unreachable();2141 zig_unreachable();
2129 }2142 }
2130 zig_unreachable();2143 zig_unreachable();
src/parser.cpp+154-21
...@@ -63,6 +63,16 @@ static const char *prefix_op_str(PrefixOp prefix_op) {...@@ -63,6 +63,16 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
63 case PrefixOpConstAddressOf: return "&const";63 case PrefixOpConstAddressOf: return "&const";
64 case PrefixOpDereference: return "*";64 case PrefixOpDereference: return "*";
65 case PrefixOpMaybe: return "?";65 case PrefixOpMaybe: return "?";
66 case PrefixOpError: return "%";
67 }
68 zig_unreachable();
69}
70
71static const char *return_prefix_str(ReturnKind kind) {
72 switch (kind) {
73 case ReturnKindError: return "%";
74 case ReturnKindMaybe: return "?";
75 case ReturnKindUnconditional: return "";
66 }76 }
67 zig_unreachable();77 zig_unreachable();
68}78}
...@@ -99,8 +109,12 @@ const char *node_type_str(NodeType node_type) {...@@ -99,8 +109,12 @@ const char *node_type_str(NodeType node_type) {
99 return "ReturnExpr";109 return "ReturnExpr";
100 case NodeTypeVariableDeclaration:110 case NodeTypeVariableDeclaration:
101 return "VariableDeclaration";111 return "VariableDeclaration";
112 case NodeTypeErrorValueDecl:
113 return "ErrorValueDecl";
102 case NodeTypeNumberLiteral:114 case NodeTypeNumberLiteral:
103 return "NumberLiteral";115 return "NumberLiteral";
116 case NodeTypeErrorLiteral:
117 return "ErrorLiteral";
104 case NodeTypeStringLiteral:118 case NodeTypeStringLiteral:
105 return "StringLiteral";119 return "StringLiteral";
106 case NodeTypeCharLiteral:120 case NodeTypeCharLiteral:
...@@ -214,10 +228,13 @@ void ast_print(AstNode *node, int indent) {...@@ -214,10 +228,13 @@ void ast_print(AstNode *node, int indent) {
214 break;228 break;
215 }229 }
216 case NodeTypeReturnExpr:230 case NodeTypeReturnExpr:
217 fprintf(stderr, "%s\n", node_type_str(node->type));231 {
218 if (node->data.return_expr.expr)232 const char *prefix_str = return_prefix_str(node->data.return_expr.kind);
219 ast_print(node->data.return_expr.expr, indent + 2);233 fprintf(stderr, "%s%s\n", prefix_str, node_type_str(node->type));
220 break;234 if (node->data.return_expr.expr)
235 ast_print(node->data.return_expr.expr, indent + 2);
236 break;
237 }
221 case NodeTypeVariableDeclaration:238 case NodeTypeVariableDeclaration:
222 {239 {
223 Buf *name_buf = &node->data.variable_declaration.symbol;240 Buf *name_buf = &node->data.variable_declaration.symbol;
...@@ -228,6 +245,12 @@ void ast_print(AstNode *node, int indent) {...@@ -228,6 +245,12 @@ void ast_print(AstNode *node, int indent) {
228 ast_print(node->data.variable_declaration.expr, indent + 2);245 ast_print(node->data.variable_declaration.expr, indent + 2);
229 break;246 break;
230 }247 }
248 case NodeTypeErrorValueDecl:
249 {
250 Buf *name_buf = &node->data.error_value_decl.name;
251 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(name_buf));
252 break;
253 }
231 case NodeTypeExternBlock:254 case NodeTypeExternBlock:
232 {255 {
233 fprintf(stderr, "%s\n", node_type_str(node->type));256 fprintf(stderr, "%s\n", node_type_str(node->type));
...@@ -288,6 +311,11 @@ void ast_print(AstNode *node, int indent) {...@@ -288,6 +311,11 @@ void ast_print(AstNode *node, int indent) {
288 }311 }
289 break;312 break;
290 }313 }
314 case NodeTypeErrorLiteral:
315 {
316 fprintf(stderr, "%s '%s'", node_type_str(node->type), buf_ptr(&node->data.error_literal.symbol));
317 break;
318 }
291 case NodeTypeStringLiteral:319 case NodeTypeStringLiteral:
292 {320 {
293 const char *c = node->data.string_literal.c ? "c" : "";321 const char *c = node->data.string_literal.c ? "c" : "";
...@@ -1345,7 +1373,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand...@@ -1345,7 +1373,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
1345}1373}
13461374
1347/*1375/*
1348PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | token(Symbol) | (token(AtSign) token(Symbol) FnCallExpression) | ArrayType | AsmExpression1376PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("%." "Symbol")
1349KeywordLiteral : token(True) | token(False) | token(Null) | token(Break) | token(Continue)1377KeywordLiteral : token(True) | token(False) | token(Null) | token(Break) | token(Continue)
1350*/1378*/
1351static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {1379static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
...@@ -1415,6 +1443,12 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool...@@ -1415,6 +1443,12 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
14151443
1416 ast_buf_from_token(pc, dest_symbol, &node->data.goto_expr.name);1444 ast_buf_from_token(pc, dest_symbol, &node->data.goto_expr.name);
1417 return node;1445 return node;
1446 } else if (token->id == TokenIdPercentDot) {
1447 *token_index += 1;
1448 Token *symbol_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
1449 AstNode *node = ast_create_node(pc, NodeTypeErrorLiteral, token);
1450 ast_buf_from_token(pc, symbol_tok, &node->data.error_literal.symbol);
1451 return node;
1418 }1452 }
14191453
1420 AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);1454 AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false);
...@@ -1612,6 +1646,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {...@@ -1612,6 +1646,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {
1612 case TokenIdAmpersand: return PrefixOpAddressOf;1646 case TokenIdAmpersand: return PrefixOpAddressOf;
1613 case TokenIdStar: return PrefixOpDereference;1647 case TokenIdStar: return PrefixOpDereference;
1614 case TokenIdMaybe: return PrefixOpMaybe;1648 case TokenIdMaybe: return PrefixOpMaybe;
1649 case TokenIdPercent: return PrefixOpError;
1615 case TokenIdBoolAnd: return PrefixOpAddressOf;1650 case TokenIdBoolAnd: return PrefixOpAddressOf;
1616 default: return PrefixOpInvalid;1651 default: return PrefixOpInvalid;
1617 }1652 }
...@@ -2031,20 +2066,46 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda...@@ -2031,20 +2066,46 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
2031}2066}
20322067
2033/*2068/*
2034ReturnExpression : token(Return) option(Expression)2069ReturnExpression : option("%" | "?") "return" option(Expression)
2035*/2070*/
2036static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool mandatory) {2071static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool mandatory) {
2037 Token *return_tok = &pc->tokens->at(*token_index);2072 Token *token = &pc->tokens->at(*token_index);
2038 if (return_tok->id == TokenIdKeywordReturn) {2073
2074 ReturnKind kind;
2075
2076 if (token->id == TokenIdPercent) {
2077 Token *next_token = &pc->tokens->at(*token_index + 1);
2078 if (next_token->id == TokenIdKeywordReturn) {
2079 kind = ReturnKindError;
2080 *token_index += 2;
2081 } else if (mandatory) {
2082 ast_invalid_token_error(pc, token);
2083 } else {
2084 return nullptr;
2085 }
2086 } else if (token->id == TokenIdMaybe) {
2087 Token *next_token = &pc->tokens->at(*token_index + 1);
2088 if (next_token->id == TokenIdKeywordReturn) {
2089 kind = ReturnKindMaybe;
2090 *token_index += 2;
2091 } else if (mandatory) {
2092 ast_invalid_token_error(pc, token);
2093 } else {
2094 return nullptr;
2095 }
2096 } else if (token->id == TokenIdKeywordReturn) {
2097 kind = ReturnKindUnconditional;
2039 *token_index += 1;2098 *token_index += 1;
2040 AstNode *node = ast_create_node(pc, NodeTypeReturnExpr, return_tok);
2041 node->data.return_expr.expr = ast_parse_expression(pc, token_index, false);
2042 return node;
2043 } else if (mandatory) {2099 } else if (mandatory) {
2044 ast_invalid_token_error(pc, return_tok);2100 ast_invalid_token_error(pc, token);
2045 } else {2101 } else {
2046 return nullptr;2102 return nullptr;
2047 }2103 }
2104
2105 AstNode *node = ast_create_node(pc, NodeTypeReturnExpr, token);
2106 node->data.return_expr.kind = kind;
2107 node->data.return_expr.expr = ast_parse_expression(pc, token_index, false);
2108 return node;
2048}2109}
20492110
2050/*2111/*
...@@ -2054,27 +2115,46 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token...@@ -2054,27 +2115,46 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token
2054 Token *first_token = &pc->tokens->at(*token_index);2115 Token *first_token = &pc->tokens->at(*token_index);
20552116
2056 VisibMod visib_mod;2117 VisibMod visib_mod;
2118 bool is_const;
20572119
2058 if (first_token->id == TokenIdKeywordPub) {2120 if (first_token->id == TokenIdKeywordPub) {
2059 *token_index += 1;2121 Token *next_token = &pc->tokens->at(*token_index + 1);
2060 visib_mod = VisibModPub;2122 if (next_token->id == TokenIdKeywordVar ||
2123 next_token->id == TokenIdKeywordConst)
2124 {
2125 visib_mod = VisibModPub;
2126 is_const = (next_token->id == TokenIdKeywordConst);
2127 *token_index += 2;
2128 } else if (mandatory) {
2129 ast_invalid_token_error(pc, next_token);
2130 } else {
2131 return nullptr;
2132 }
2061 } else if (first_token->id == TokenIdKeywordExport) {2133 } else if (first_token->id == TokenIdKeywordExport) {
2062 *token_index += 1;2134 Token *next_token = &pc->tokens->at(*token_index + 1);
2063 visib_mod = VisibModExport;2135 if (next_token->id == TokenIdKeywordVar ||
2136 next_token->id == TokenIdKeywordConst)
2137 {
2138 visib_mod = VisibModExport;
2139 is_const = (next_token->id == TokenIdKeywordConst);
2140 *token_index += 2;
2141 } else if (mandatory) {
2142 ast_invalid_token_error(pc, next_token);
2143 } else {
2144 return nullptr;
2145 }
2064 } else if (first_token->id == TokenIdKeywordVar ||2146 } else if (first_token->id == TokenIdKeywordVar ||
2065 first_token->id == TokenIdKeywordConst)2147 first_token->id == TokenIdKeywordConst)
2066 {2148 {
2067 visib_mod = VisibModPrivate;2149 visib_mod = VisibModPrivate;
2150 is_const = (first_token->id == TokenIdKeywordConst);
2151 *token_index += 1;
2068 } else if (mandatory) {2152 } else if (mandatory) {
2069 ast_invalid_token_error(pc, first_token);2153 ast_invalid_token_error(pc, first_token);
2070 } else {2154 } else {
2071 return nullptr;2155 return nullptr;
2072 }2156 }
20732157
2074 Token *var_or_const_tok = &pc->tokens->at(*token_index);
2075 bool is_const = (var_or_const_tok->id == TokenIdKeywordConst);
2076 *token_index += 1;
2077
2078 AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, first_token);2158 AstNode *node = ast_create_node(pc, NodeTypeVariableDeclaration, first_token);
20792159
2080 node->data.variable_declaration.is_const = is_const;2160 node->data.variable_declaration.is_const = is_const;
...@@ -2836,7 +2916,54 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {...@@ -2836,7 +2916,54 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
2836}2916}
28372917
2838/*2918/*
2839TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | VariableDeclaration | EnumDecl2919ErrorValueDecl : option(FnVisibleMod) "%." "Symbol"
2920*/
2921static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index, bool mandatory) {
2922 Token *first_token = &pc->tokens->at(*token_index);
2923
2924 VisibMod visib_mod;
2925
2926 if (first_token->id == TokenIdKeywordPub) {
2927 Token *next_token = &pc->tokens->at(*token_index + 1);
2928 if (next_token->id == TokenIdPercentDot) {
2929 visib_mod = VisibModPub;
2930 *token_index += 2;
2931 } else if (mandatory) {
2932 ast_invalid_token_error(pc, next_token);
2933 } else {
2934 return nullptr;
2935 }
2936 } else if (first_token->id == TokenIdKeywordExport) {
2937 Token *next_token = &pc->tokens->at(*token_index + 1);
2938 if (next_token->id == TokenIdPercentDot) {
2939 visib_mod = VisibModExport;
2940 *token_index += 2;
2941 } else if (mandatory) {
2942 ast_invalid_token_error(pc, next_token);
2943 } else {
2944 return nullptr;
2945 }
2946 } else if (first_token->id == TokenIdPercentDot) {
2947 visib_mod = VisibModPrivate;
2948 *token_index += 1;
2949 } else if (mandatory) {
2950 ast_invalid_token_error(pc, first_token);
2951 } else {
2952 return nullptr;
2953 }
2954
2955 Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
2956 ast_eat_token(pc, token_index, TokenIdSemicolon);
2957
2958 AstNode *node = ast_create_node(pc, NodeTypeErrorValueDecl, first_token);
2959 node->data.error_value_decl.visib_mod = visib_mod;
2960 ast_buf_from_token(pc, name_tok, &node->data.error_value_decl.name);
2961
2962 return node;
2963}
2964
2965/*
2966TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration | ErrorValueDecl
2840*/2967*/
2841static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {2968static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) {
2842 for (;;) {2969 for (;;) {
...@@ -2887,6 +3014,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis...@@ -2887,6 +3014,12 @@ static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigLis
2887 continue;3014 continue;
2888 }3015 }
28893016
3017 AstNode *error_value_node = ast_parse_error_value_decl(pc, token_index, false);
3018 if (error_value_node) {
3019 top_level_decls->append(error_value_node);
3020 continue;
3021 }
3022
2890 return;3023 return;
2891 }3024 }
2892 zig_unreachable();3025 zig_unreachable();
src/tokenizer.cpp+6
...@@ -584,6 +584,11 @@ void tokenize(Buf *buf, Tokenization *out) {...@@ -584,6 +584,11 @@ void tokenize(Buf *buf, Tokenization *out) {
584 end_token(&t);584 end_token(&t);
585 t.state = TokenizeStateStart;585 t.state = TokenizeStateStart;
586 break;586 break;
587 case '.':
588 t.cur_tok->id = TokenIdPercentDot;
589 end_token(&t);
590 t.state = TokenizeStateStart;
591 break;
587 default:592 default:
588 t.pos -= 1;593 t.pos -= 1;
589 end_token(&t);594 end_token(&t);
...@@ -1092,6 +1097,7 @@ const char * token_name(TokenId id) {...@@ -1092,6 +1097,7 @@ const char * token_name(TokenId id) {
1092 case TokenIdDoubleQuestion: return "??";1097 case TokenIdDoubleQuestion: return "??";
1093 case TokenIdMaybeAssign: return "?=";1098 case TokenIdMaybeAssign: return "?=";
1094 case TokenIdAtSign: return "@";1099 case TokenIdAtSign: return "@";
1100 case TokenIdPercentDot: return "%.";
1095 }1101 }
1096 return "(invalid token)";1102 return "(invalid token)";
1097}1103}
src/tokenizer.hpp+1
...@@ -91,6 +91,7 @@ enum TokenId {...@@ -91,6 +91,7 @@ enum TokenId {
91 TokenIdDoubleQuestion,91 TokenIdDoubleQuestion,
92 TokenIdMaybeAssign,92 TokenIdMaybeAssign,
93 TokenIdAtSign,93 TokenIdAtSign,
94 TokenIdPercentDot,
94};95};
9596
96struct Token {97struct Token {
std/std.zig+150-16
...@@ -1,43 +1,177 @@...@@ -1,43 +1,177 @@
1import "syscall.zig";1import "syscall.zig";
2//import "errno.zig";
23
3pub const stdin_fileno : isize = 0;4pub const stdin_fileno : isize = 0;
4pub const stdout_fileno : isize = 1;5pub const stdout_fileno : isize = 1;
5pub const stderr_fileno : isize = 2;6pub const stderr_fileno : isize = 2;
67
7// TODO error handling8/*
8pub fn os_get_random_bytes(buf: []u8) isize => {9pub var stdin = InStream {
9 getrandom(buf.ptr, buf.len, 0)10 .fd = stdin_fileno,
11};
12
13pub var stdout = OutStream {
14 .fd = stdout_fileno,
15 .buffer = uninitialized,
16 .index = 0,
17 .buffered = true,
18};
19
20pub var stderr = OutStream {
21 .fd = stderr_fileno,
22 .buffer = uninitialized,
23 .index = 0,
24 .buffered = false,
25};
26
27pub %.Unexpected;
28pub %.DiskQuota;
29pub %.FileTooBig;
30pub %.SigInterrupt;
31pub %.Io;
32pub %.NoSpaceLeft;
33pub %.BadPerm;
34pub %.PipeFail;
35*/
36
37const buffer_size: u16 = 4 * 1024;
38const max_u64_base10_digits: isize = 20;
39
40/*
41pub struct OutStream {
42 fd: isize,
43 buffer: [buffer_size]u8,
44 index: @typeof(buffer_size),
45 buffered: bool,
46
47 pub fn print_str(os: &OutStream, str: []const u8) %isize => {
48 var src_bytes_left = str.len;
49 var src_index: @typeof(str.len) = 0;
50 const dest_space_left = os.buffer.len - index;
51
52 while (src_bytes_left > 0) {
53 const copy_amt = min_isize(dest_space_left, src_bytes_left);
54 @memcpy(&buffer[os.index], &str[src_index], copy_amt);
55 os.index += copy_amt;
56 if (os.index == os.buffer.len) {
57 %return os.flush();
58 }
59 src_bytes_left -= copy_amt;
60 }
61 if (!os.buffered) {
62 %return os.flush();
63 }
64 return str.len;
65 }
66
67 pub fn print_u64(os: &OutStream, x: u64) %isize => {
68 if (os.index + max_u64_base10_digits >= os.buffer.len) {
69 %return os.flush();
70 }
71 const amt_printed = buf_print_u64(buf[os.index...], x);
72 os.index += amt_printed;
73
74 if (!os.buffered) {
75 %return os.flush();
76 }
77
78 return amt_printed;
79 }
80
81
82 pub fn print_i64(os: &OutStream, x: i64) %isize => {
83 if (os.index + max_u64_base10_digits >= os.buffer.len) {
84 %return os.flush();
85 }
86 const amt_printed = buf_print_i64(buf[os.index...], x);
87 os.index += amt_printed;
88
89 if (!os.buffered) {
90 %return os.flush();
91 }
92
93 return amt_printed;
94 }
95
96
97 pub fn flush(os: &OutStream) %void => {
98 const amt_to_write = os.index;
99 os.index = 0;
100 switch (write(fd, os.buffer.ptr, amt_to_write)) {
101 EINVAL => unreachable{},
102 EDQUOT => %.DiskQuota,
103 EFBIG => %.FileTooBig,
104 EINTR => %.SigInterrupt,
105 EIO => %.Io,
106 ENOSPC => %.NoSpaceLeft,
107 EPERM => %.BadPerm,
108 EPIPE => %.PipeFail,
109 else => %.Unexpected,
110 }
111 }
112}
113
114pub struct InStream {
115 fd: isize,
116
117 pub fn readline(buf: []u8) %isize => {
118 const amt_read = read(stdin_fileno, buf.ptr, buf.len);
119 if (amt_read < 0) {
120 switch (-amt_read) {
121 EINVAL => unreachable{},
122 EFAULT => unreachable{},
123 EBADF => %.BadFd,
124 EINTR => %.SigInterrupt,
125 EIO => %.Io,
126 else => %.Unexpected,
127 }
128 }
129 return amt_read;
130 }
131
132}
133
134pub fn os_get_random_bytes(buf: []u8) %void => {
135 switch (getrandom(buf.ptr, buf.len, 0)) {
136 EINVAL => unreachable{},
137 EFAULT => unreachable{},
138 EINTR => %.SigInterrupt,
139 else => %.Unexpected,
140 }
10}141}
142*/
143
11144
12// TODO error handling145// TODO remove this
13// TODO handle buffering and flushing (mutex protected)
14pub fn print_str(str: []const u8) isize => {146pub fn print_str(str: []const u8) isize => {
15 fprint_str(stdout_fileno, str)147 fprint_str(stdout_fileno, str)
16}148}
17149
18// TODO error handling150// TODO remove this
19// TODO handle buffering and flushing (mutex protected)
20pub fn fprint_str(fd: isize, str: []const u8) isize => {151pub fn fprint_str(fd: isize, str: []const u8) isize => {
21 write(fd, str.ptr, str.len)152 write(fd, str.ptr, str.len)
22}153}
23154
24// TODO handle buffering and flushing (mutex protected)155// TODO remove this
25// TODO error handling156pub fn os_get_random_bytes(buf: []u8) isize => {
157 getrandom(buf.ptr, buf.len, 0)
158}
159
160// TODO remove this
26pub fn print_u64(x: u64) isize => {161pub fn print_u64(x: u64) isize => {
27 var buf: [max_u64_base10_digits]u8;162 var buf: [max_u64_base10_digits]u8;
28 const len = buf_print_u64(buf, x);163 const len = buf_print_u64(buf, x);
29 return write(stdout_fileno, buf.ptr, len);164 return write(stdout_fileno, buf.ptr, len);
30}165}
31166
32// TODO handle buffering and flushing (mutex protected)167// TODO remove this
33// TODO error handling
34pub fn print_i64(x: i64) isize => {168pub fn print_i64(x: i64) isize => {
35 var buf: [max_u64_base10_digits]u8;169 var buf: [max_u64_base10_digits]u8;
36 const len = buf_print_i64(buf, x);170 const len = buf_print_i64(buf, x);
37 return write(stdout_fileno, buf.ptr, len);171 return write(stdout_fileno, buf.ptr, len);
38}172}
39173
40// TODO error handling174// TODO remove this
41pub fn readline(buf: []u8, out_len: &isize) bool => {175pub fn readline(buf: []u8, out_len: &isize) bool => {
42 const amt_read = read(stdin_fileno, buf.ptr, buf.len);176 const amt_read = read(stdin_fileno, buf.ptr, buf.len);
43 if (amt_read < 0) {177 if (amt_read < 0) {
...@@ -47,7 +181,8 @@ pub fn readline(buf: []u8, out_len: &isize) bool => {...@@ -47,7 +181,8 @@ pub fn readline(buf: []u8, out_len: &isize) bool => {
47 return false;181 return false;
48}182}
49183
50// TODO return ?u64 when we support returning struct byval184
185// TODO return %u64 when we support errors
51pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {186pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {
52 var x : u64 = 0;187 var x : u64 = 0;
53188
...@@ -74,6 +209,7 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {...@@ -74,6 +209,7 @@ pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => {
74}209}
75210
76fn char_to_digit(c: u8) u8 => {211fn char_to_digit(c: u8) u8 => {
212 // TODO use switch with range
77 if ('0' <= c && c <= '9') {213 if ('0' <= c && c <= '9') {
78 c - '0'214 c - '0'
79 } else if ('A' <= c && c <= 'Z') {215 } else if ('A' <= c && c <= 'Z') {
...@@ -85,8 +221,6 @@ fn char_to_digit(c: u8) u8 => {...@@ -85,8 +221,6 @@ fn char_to_digit(c: u8) u8 => {
85 }221 }
86}222}
87223
88const max_u64_base10_digits: isize = 20;
89
90fn buf_print_i64(out_buf: []u8, x: i64) isize => {224fn buf_print_i64(out_buf: []u8, x: i64) isize => {
91 if (x < 0) {225 if (x < 0) {
92 out_buf[0] = '-';226 out_buf[0] = '-';
...@@ -112,7 +246,7 @@ fn buf_print_u64(out_buf: []u8, x: u64) isize => {...@@ -112,7 +246,7 @@ fn buf_print_u64(out_buf: []u8, x: u64) isize => {
112246
113 const len = buf.len - index;247 const len = buf.len - index;
114248
115 @memcpy(out_buf.ptr, &buf[index], len);249 @memcpy(&out_buf[0], &buf[index], len);
116250
117 return len;251 return len;
118}252}