| author | |
| committer | |
| log | 5e212db29cf9e2c06aba363736ffb965e631aa2d |
| tree | 2ec22f86549bca4cceb423bb3b66aa796754951f |
| parent | 82d1b51b1d34a0c1b21ec2aaae70051379b37f43 |
and return with '?' or '%' prefix10 files changed, 548 insertions(+), 88 deletions(-)
doc/langref.md+23-10| ... | @@ -5,9 +5,11 @@ | ... | @@ -5,9 +5,11 @@ |
| 5 | ``` | 5 | ``` |
| 6 | Root : many(TopLevelDecl) "EOF" | 6 | Root : many(TopLevelDecl) "EOF" |
| 7 | 7 | ||
| 8 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration | 8 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration | ErrorValueDecl |
| 9 | 9 | ||
| 10 | VariableDeclaration : option(FnVisibleMod) ("var" | "const") "symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression)) | 10 | ErrorValueDecl : option(FnVisibleMod) "%." "Symbol" |
| 11 | |||
| 12 | VariableDeclaration : option(FnVisibleMod) ("var" | "const") "Symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression)) | ||
| 11 | 13 | ||
| 12 | ContainerDecl : many(Directive) option(FnVisibleMod) ("struct" | "enum") "Symbol" "{" many(StructMember) "}" | 14 | ContainerDecl : many(Directive) option(FnVisibleMod) ("struct" | "enum") "Symbol" "{" many(StructMember) "}" |
| 13 | 15 | ||
| ... | @@ -77,7 +79,7 @@ ForExpression : "for" "(" "Symbol" "," Expression option("," "Symbol") ")" Expre | ... | @@ -77,7 +79,7 @@ ForExpression : "for" "(" "Symbol" "," Expression option("," "Symbol") ")" Expre |
| 77 | 79 | ||
| 78 | BoolOrExpression : BoolAndExpression "||" BoolOrExpression | BoolAndExpression | 80 | BoolOrExpression : BoolAndExpression "||" BoolOrExpression | BoolAndExpression |
| 79 | 81 | ||
| 80 | ReturnExpression : "return" option(Expression) | 82 | ReturnExpression : option("%" | "?") "return" option(Expression) |
| 81 | 83 | ||
| 82 | IfExpression : IfVarExpression | IfBoolExpression | 84 | IfExpression : IfVarExpression | IfBoolExpression |
| 83 | 85 | ||
| ... | @@ -133,7 +135,7 @@ StructLiteralField : "." "Symbol" "=" Expression | ... | @@ -133,7 +135,7 @@ StructLiteralField : "." "Symbol" "=" Expression |
| 133 | 135 | ||
| 134 | PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | 136 | PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?" |
| 135 | 137 | ||
| 136 | PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | 138 | PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("%." "Symbol") |
| 137 | 139 | ||
| 138 | ArrayType : "[" option(Expression) "]" option("const") PrefixOpExpression | 140 | ArrayType : "[" option(Expression) "]" option("const") PrefixOpExpression |
| 139 | 141 | ||
| ... | @@ -148,7 +150,7 @@ KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | ... | @@ -148,7 +150,7 @@ KeywordLiteral : "true" | "false" | "null" | "break" | "continue" |
| 148 | 150 | ||
| 149 | ``` | 151 | ``` |
| 150 | x() x[] x.y | 152 | x() x[] x.y |
| 151 | !x -x ~x *x &x ?x | 153 | !x -x ~x *x &x ?x %x |
| 152 | x{} | 154 | x{} |
| 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 Type | 201 | ### Boolean Type |
| 200 | The boolean type has the name `bool` and represents either true or false. | 202 | The boolean type has the name `bool` and represents either true or false. |
| 201 | 203 | ||
| 202 | ### Function Types | 204 | ### Function Type |
| 203 | TODO | 205 | TODO |
| 204 | 206 | ||
| 205 | ### Array Types | 207 | ### Fixed-Size Array Type |
| 206 | TODO | 208 | |
| 207 | Also, are there slices? | 209 | Example: The string `"aoeu"` has type `[4]u8`. |
| 210 | |||
| 211 | The size is known at compile time and is part of the type. | ||
| 212 | |||
| 213 | ### Slice Type | ||
| 214 | |||
| 215 | A slice can be obtained with the slicing syntax: `array[start...end]` | ||
| 216 | |||
| 217 | Example: `"aoeu"[0...2]` has type `[]u8`. | ||
| 208 | 218 | ||
| 209 | ### Struct Types | 219 | ### Struct Types |
| 210 | TODO | 220 | TODO |
| ... | @@ -213,10 +223,13 @@ TODO | ... | @@ -213,10 +223,13 @@ TODO |
| 213 | TODO | 223 | TODO |
| 214 | 224 | ||
| 215 | ### Unreachable Type | 225 | ### Unreachable Type |
| 226 | |||
| 216 | The unreachable type has the name `unreachable`. TODO explanation | 227 | The unreachable type has the name `unreachable`. TODO explanation |
| 217 | 228 | ||
| 218 | ### Void Type | 229 | ### Void Type |
| 219 | The void type has the name `void`. TODO explanation | 230 | |
| 231 | The void type has the name `void`. void types are zero bits and are omitted | ||
| 232 | from codegen. | ||
| 220 | 233 | ||
| 221 | 234 | ||
| 222 | ## Expressions | 235 | ## Expressions |
example/cat/main.zig+17-17| ... | @@ -3,50 +3,50 @@ export executable "cat"; | ... | @@ -3,50 +3,50 @@ export executable "cat"; |
| 3 | import "std.zig"; | 3 | import "std.zig"; |
| 4 | 4 | ||
| 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 printing | 6 | // * var args printing |
| 8 | // * update std API | 7 | // * %void type |
| 9 | // * !void type | ||
| 10 | // * defer | 8 | // * defer |
| 11 | // * !return | 9 | // * %return |
| 12 | // * !! operator | 10 | // * %% operator |
| 13 | // * make main return !void | 11 | // * 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 string | 13 | // * cast err type to string |
| 14 | // * update std API | ||
| 15 | |||
| 16 | pub %.Invalid; | ||
| 17 | 17 | ||
| 18 | pub fn main(args: [][]u8) !void => { | 18 | pub 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(); |
| 34 | 34 | ||
| 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 | } |
| 43 | 43 | ||
| 44 | fn usage(exe: []u8) !void => { | 44 | fn 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 | } |
| 48 | 48 | ||
| 49 | fn cat_stream(is: InputStream) !void => { | 49 | fn cat_stream(is: InputStream) %void => { |
| 50 | var buf: [1024 * 4]u8; | 50 | var buf: [1024 * 4]u8; |
| 51 | 51 | ||
| 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"; |
| 3 | import "std.zig"; | 3 | import "std.zig"; |
| 4 | 4 | ||
| 5 | pub fn main(args: [][]u8) i32 => { | 5 | pub 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 | }; |
| 224 | 226 | ||
| 227 | enum ReturnKind { | ||
| 228 | ReturnKindUnconditional, | ||
| 229 | ReturnKindMaybe, | ||
| 230 | ReturnKindError, | ||
| 231 | }; | ||
| 232 | |||
| 225 | struct AstNodeReturnExpr { | 233 | struct 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; |
| 228 | 237 | ||
| ... | @@ -243,6 +252,14 @@ struct AstNodeVariableDeclaration { | ... | @@ -243,6 +252,14 @@ struct AstNodeVariableDeclaration { |
| 243 | Expr resolved_expr; | 252 | Expr resolved_expr; |
| 244 | }; | 253 | }; |
| 245 | 254 | ||
| 255 | struct AstNodeErrorValueDecl { | ||
| 256 | VisibMod visib_mod; | ||
| 257 | Buf name; | ||
| 258 | |||
| 259 | // populated by semantic analyzer | ||
| 260 | TopLevelDecl top_level_decl; | ||
| 261 | }; | ||
| 262 | |||
| 246 | enum BinOpType { | 263 | enum 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 | }; |
| 362 | 380 | ||
| 363 | struct AstNodePrefixOpExpr { | 381 | struct AstNodePrefixOpExpr { |
| ... | @@ -564,6 +582,14 @@ struct AstNodeNumberLiteral { | ... | @@ -564,6 +582,14 @@ struct AstNodeNumberLiteral { |
| 564 | Expr resolved_expr; | 582 | Expr resolved_expr; |
| 565 | }; | 583 | }; |
| 566 | 584 | ||
| 585 | struct AstNodeErrorLiteral { | ||
| 586 | Buf symbol; | ||
| 587 | |||
| 588 | // populated by semantic analyzer | ||
| 589 | NumLitCodeGen codegen; | ||
| 590 | Expr resolved_expr; | ||
| 591 | }; | ||
| 592 | |||
| 567 | struct AstNodeStructValueField { | 593 | struct 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 | }; |
| 740 | 768 | ||
| 769 | struct TypeTableEntryError { | ||
| 770 | TypeTableEntry *child_type; | ||
| 771 | }; | ||
| 772 | |||
| 741 | struct TypeTableEntryEnum { | 773 | struct 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 | }; |
| 812 | 847 | ||
| 813 | struct ImporterInfo { | 848 | struct 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 init | 110 | // 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 | } |
| 217 | 220 | ||
| 221 | static 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 | |||
| 218 | static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, uint64_t array_size) | 272 | static 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 here | 985 | // 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 | } |
| 2265 | 2326 | ||
| 2327 | static 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 | |||
| 2266 | static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 2333 | static 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 | } |
| 3101 | 3193 | ||
| 3194 | static 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 | |||
| 3102 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 3225 | static 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 | } |
| 3141 | 3264 | ||
| 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 these | 3521 | // 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 declarations | 3577 | // 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 of | 3869 | // 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 | } |
| 1939 | 1943 | ||
| 1944 | static LLVMValueRef gen_error_literal(CodeGen *g, AstNode *node) { | ||
| 1945 | assert(node->type == NodeTypeErrorLiteral); | ||
| 1946 | |||
| 1947 | zig_panic("TODO gen_error_literal"); | ||
| 1948 | } | ||
| 1949 | |||
| 1940 | static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { | 1950 | static 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 | |||
| 71 | static 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 | } |
| 1346 | 1374 | ||
| 1347 | /* | 1375 | /* |
| 1348 | PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | token(Symbol) | (token(AtSign) token(Symbol) FnCallExpression) | ArrayType | AsmExpression | 1376 | PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("%." "Symbol") |
| 1349 | KeywordLiteral : token(True) | token(False) | token(Null) | token(Break) | token(Continue) | 1377 | KeywordLiteral : token(True) | token(False) | token(Null) | token(Break) | token(Continue) |
| 1350 | */ | 1378 | */ |
| 1351 | static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) { | 1379 | static 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 |
| 1415 | 1443 | ||
| 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 | } |
| 1419 | 1453 | ||
| 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 | } |
| 2032 | 2067 | ||
| 2033 | /* | 2068 | /* |
| 2034 | ReturnExpression : token(Return) option(Expression) | 2069 | ReturnExpression : option("%" | "?") "return" option(Expression) |
| 2035 | */ | 2070 | */ |
| 2036 | static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool mandatory) { | 2071 | static 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 | } |
| 2049 | 2110 | ||
| 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); |
| 2055 | 2116 | ||
| 2056 | VisibMod visib_mod; | 2117 | VisibMod visib_mod; |
| 2118 | bool is_const; | ||
| 2057 | 2119 | ||
| 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 | } |
| 2073 | 2157 | ||
| 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); |
| 2079 | 2159 | ||
| 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 | } |
| 2837 | 2917 | ||
| 2838 | /* | 2918 | /* |
| 2839 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Use | StructDecl | VariableDeclaration | EnumDecl | 2919 | ErrorValueDecl : option(FnVisibleMod) "%." "Symbol" |
| 2920 | */ | ||
| 2921 | static 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 | /* | ||
| 2966 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration | ErrorValueDecl | ||
| 2840 | */ | 2967 | */ |
| 2841 | static void ast_parse_top_level_decls(ParseContext *pc, int *token_index, ZigList<AstNode *> *top_level_decls) { | 2968 | static 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 | } |
| 2889 | 3016 | ||
| 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 | }; |
| 95 | 96 | ||
| 96 | struct Token { | 97 | struct Token { |
std/std.zig+150-16| ... | @@ -1,43 +1,177 @@ | ... | @@ -1,43 +1,177 @@ |
| 1 | import "syscall.zig"; | 1 | import "syscall.zig"; |
| 2 | //import "errno.zig"; | ||
| 2 | 3 | ||
| 3 | pub const stdin_fileno : isize = 0; | 4 | pub const stdin_fileno : isize = 0; |
| 4 | pub const stdout_fileno : isize = 1; | 5 | pub const stdout_fileno : isize = 1; |
| 5 | pub const stderr_fileno : isize = 2; | 6 | pub const stderr_fileno : isize = 2; |
| 6 | 7 | ||
| 7 | // TODO error handling | 8 | /* |
| 8 | pub fn os_get_random_bytes(buf: []u8) isize => { | 9 | pub var stdin = InStream { |
| 9 | getrandom(buf.ptr, buf.len, 0) | 10 | .fd = stdin_fileno, |
| 11 | }; | ||
| 12 | |||
| 13 | pub var stdout = OutStream { | ||
| 14 | .fd = stdout_fileno, | ||
| 15 | .buffer = uninitialized, | ||
| 16 | .index = 0, | ||
| 17 | .buffered = true, | ||
| 18 | }; | ||
| 19 | |||
| 20 | pub var stderr = OutStream { | ||
| 21 | .fd = stderr_fileno, | ||
| 22 | .buffer = uninitialized, | ||
| 23 | .index = 0, | ||
| 24 | .buffered = false, | ||
| 25 | }; | ||
| 26 | |||
| 27 | pub %.Unexpected; | ||
| 28 | pub %.DiskQuota; | ||
| 29 | pub %.FileTooBig; | ||
| 30 | pub %.SigInterrupt; | ||
| 31 | pub %.Io; | ||
| 32 | pub %.NoSpaceLeft; | ||
| 33 | pub %.BadPerm; | ||
| 34 | pub %.PipeFail; | ||
| 35 | */ | ||
| 36 | |||
| 37 | const buffer_size: u16 = 4 * 1024; | ||
| 38 | const max_u64_base10_digits: isize = 20; | ||
| 39 | |||
| 40 | /* | ||
| 41 | pub 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 | |||
| 114 | pub 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 | |||
| 134 | pub 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 | |||
| 11 | 144 | ||
| 12 | // TODO error handling | 145 | // TODO remove this |
| 13 | // TODO handle buffering and flushing (mutex protected) | ||
| 14 | pub fn print_str(str: []const u8) isize => { | 146 | pub fn print_str(str: []const u8) isize => { |
| 15 | fprint_str(stdout_fileno, str) | 147 | fprint_str(stdout_fileno, str) |
| 16 | } | 148 | } |
| 17 | 149 | ||
| 18 | // TODO error handling | 150 | // TODO remove this |
| 19 | // TODO handle buffering and flushing (mutex protected) | ||
| 20 | pub fn fprint_str(fd: isize, str: []const u8) isize => { | 151 | pub 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 | } |
| 23 | 154 | ||
| 24 | // TODO handle buffering and flushing (mutex protected) | 155 | // TODO remove this |
| 25 | // TODO error handling | 156 | pub fn os_get_random_bytes(buf: []u8) isize => { |
| 157 | getrandom(buf.ptr, buf.len, 0) | ||
| 158 | } | ||
| 159 | |||
| 160 | // TODO remove this | ||
| 26 | pub fn print_u64(x: u64) isize => { | 161 | pub 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 | } |
| 31 | 166 | ||
| 32 | // TODO handle buffering and flushing (mutex protected) | 167 | // TODO remove this |
| 33 | // TODO error handling | ||
| 34 | pub fn print_i64(x: i64) isize => { | 168 | pub 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 | } |
| 39 | 173 | ||
| 40 | // TODO error handling | 174 | // TODO remove this |
| 41 | pub fn readline(buf: []u8, out_len: &isize) bool => { | 175 | pub 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 | } |
| 49 | 183 | ||
| 50 | // TODO return ?u64 when we support returning struct byval | 184 | |
| 185 | // TODO return %u64 when we support errors | ||
| 51 | pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => { | 186 | pub fn parse_u64(buf: []u8, radix: u8, result: &u64) bool => { |
| 52 | var x : u64 = 0; | 187 | var x : u64 = 0; |
| 53 | 188 | ||
| ... | @@ -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 | } |
| 75 | 210 | ||
| 76 | fn char_to_digit(c: u8) u8 => { | 211 | fn 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 | } |
| 87 | 223 | ||
| 88 | const max_u64_base10_digits: isize = 20; | ||
| 89 | |||
| 90 | fn buf_print_i64(out_buf: []u8, x: i64) isize => { | 224 | fn 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 => { |
| 112 | 246 | ||
| 113 | const len = buf.len - index; | 247 | const len = buf.len - index; |
| 114 | 248 | ||
| 115 | @memcpy(out_buf.ptr, &buf[index], len); | 249 | @memcpy(&out_buf[0], &buf[index], len); |
| 116 | 250 | ||
| 117 | return len; | 251 | return len; |
| 118 | } | 252 | } |