| author | |
| committer | |
| log | 5c18826240fe983a30a9de6e04d3848643db7cf6 |
| tree | d427af30c78ff59d768bf75cd194e008757ab7bf |
| parent | 37aae530098f10565ea3408891c901e086b8d5b8 |
See #2312 files changed, 223 insertions(+), 128 deletions(-)
doc/langref.md+4-4| ... | ... | @@ -7,7 +7,7 @@ Root : many(TopLevelDecl) "EOF" |
| 7 | 7 | |
| 8 | 8 | TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration | ErrorValueDecl |
| 9 | 9 | |
| 10 | ErrorValueDecl : option(FnVisibleMod) "%." "Symbol" | |
| 10 | ErrorValueDecl : option(FnVisibleMod) "error" "Symbol" | |
| 11 | 11 | |
| 12 | 12 | VariableDeclaration : option(FnVisibleMod) ("var" | "const") "Symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression)) |
| 13 | 13 | |
| ... | ... | @@ -133,9 +133,9 @@ ContainerInitBody : list(StructLiteralField, ",") | list(Expression, ",") |
| 133 | 133 | |
| 134 | 134 | StructLiteralField : "." "Symbol" "=" Expression |
| 135 | 135 | |
| 136 | PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | |
| 136 | PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | |
| 137 | 137 | |
| 138 | PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("%." "Symbol") | |
| 138 | PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("error" "." "Symbol") | |
| 139 | 139 | |
| 140 | 140 | ArrayType : "[" option(Expression) "]" option("const") PrefixOpExpression |
| 141 | 141 | |
| ... | ... | @@ -143,7 +143,7 @@ GotoExpression: "goto" "Symbol" |
| 143 | 143 | |
| 144 | 144 | GroupedExpression : "(" Expression ")" |
| 145 | 145 | |
| 146 | KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined" | |
| 146 | KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | |
| 147 | 147 | ``` |
| 148 | 148 | |
| 149 | 149 | ## Operator Precedence |
doc/vim/syntax/zig.vim+1-1| ... | ... | @@ -15,7 +15,7 @@ syn keyword zigRepeat while for |
| 15 | 15 | |
| 16 | 16 | syn keyword zigConstant null undefined |
| 17 | 17 | syn keyword zigKeyword fn import |
| 18 | syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void unreachable type | |
| 18 | syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void unreachable type error | |
| 19 | 19 | |
| 20 | 20 | syn keyword zigBoolean true false |
| 21 | 21 |
example/cat/main.zig+2-1| ... | ... | @@ -10,6 +10,7 @@ import "std.zig"; |
| 10 | 10 | // * %% binary operator |
| 11 | 11 | // * %% prefix operator |
| 12 | 12 | // * cast err type to string |
| 13 | // * string equality | |
| 13 | 14 | |
| 14 | 15 | pub fn main(args: [][]u8) %void => { |
| 15 | 16 | const exe = args[0]; |
| ... | ... | @@ -39,7 +40,7 @@ pub fn main(args: [][]u8) %void => { |
| 39 | 40 | |
| 40 | 41 | fn usage(exe: []u8) %void => { |
| 41 | 42 | %%stderr.print("Usage: {} [FILE]...\n", exe); |
| 42 | return %.Invalid; | |
| 43 | return error.Invalid; | |
| 43 | 44 | } |
| 44 | 45 | |
| 45 | 46 | fn cat_stream(is: InputStream) %void => { |
example/guess_number/main.zig+4-4| ... | ... | @@ -3,8 +3,8 @@ export executable "guess_number"; |
| 3 | 3 | import "std.zig"; |
| 4 | 4 | import "rand.zig"; |
| 5 | 5 | |
| 6 | %.GetRandomFail; | |
| 7 | %.ReadInputFail; | |
| 6 | error GetRandomFail; | |
| 7 | error ReadInputFail; | |
| 8 | 8 | |
| 9 | 9 | pub fn main(args: [][]u8) %void => { |
| 10 | 10 | print_str("Welcome to the Guess Number Game in Zig.\n"); |
| ... | ... | @@ -15,7 +15,7 @@ pub fn main(args: [][]u8) %void => { |
| 15 | 15 | if (err != @sizeof(u32)) { |
| 16 | 16 | // TODO full error message |
| 17 | 17 | fprint_str(stderr_fileno, "unable to get random bytes\n"); |
| 18 | return %.GetRandomFail; | |
| 18 | return error.GetRandomFail; | |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | var rand : Rand; |
| ... | ... | @@ -31,7 +31,7 @@ pub fn main(args: [][]u8) %void => { |
| 31 | 31 | if (readline(line_buf, &line_len) || line_len == line_buf.len) { |
| 32 | 32 | // TODO full error message |
| 33 | 33 | fprint_str(stderr_fileno, "unable to read input\n"); |
| 34 | return %.ReadInputFail; | |
| 34 | return error.ReadInputFail; | |
| 35 | 35 | } |
| 36 | 36 | |
| 37 | 37 | var guess : u64; |
src/all_types.hpp+11-10| ... | ... | @@ -133,7 +133,6 @@ enum NodeType { |
| 133 | 133 | NodeTypeNumberLiteral, |
| 134 | 134 | NodeTypeStringLiteral, |
| 135 | 135 | NodeTypeCharLiteral, |
| 136 | NodeTypeErrorLiteral, | |
| 137 | 136 | NodeTypeSymbol, |
| 138 | 137 | NodeTypePrefixOpExpr, |
| 139 | 138 | NodeTypeFnCallExpr, |
| ... | ... | @@ -161,6 +160,7 @@ enum NodeType { |
| 161 | 160 | NodeTypeContainerInitExpr, |
| 162 | 161 | NodeTypeStructValueField, |
| 163 | 162 | NodeTypeArrayType, |
| 163 | NodeTypeErrorType, | |
| 164 | 164 | }; |
| 165 | 165 | |
| 166 | 166 | struct AstNodeRoot { |
| ... | ... | @@ -315,6 +315,7 @@ enum CastOp { |
| 315 | 315 | CastOpToUnknownSizeArray, |
| 316 | 316 | CastOpMaybeWrap, |
| 317 | 317 | CastOpErrorWrap, |
| 318 | CastOpPureErrorWrap, | |
| 318 | 319 | CastOpPointerReinterpret, |
| 319 | 320 | CastOpErrToInt, |
| 320 | 321 | }; |
| ... | ... | @@ -584,13 +585,6 @@ struct AstNodeNumberLiteral { |
| 584 | 585 | Expr resolved_expr; |
| 585 | 586 | }; |
| 586 | 587 | |
| 587 | struct AstNodeErrorLiteral { | |
| 588 | Buf symbol; | |
| 589 | ||
| 590 | // populated by semantic analyzer | |
| 591 | Expr resolved_expr; | |
| 592 | }; | |
| 593 | ||
| 594 | 588 | struct AstNodeStructValueField { |
| 595 | 589 | Buf name; |
| 596 | 590 | AstNode *expr; |
| ... | ... | @@ -663,6 +657,11 @@ struct AstNodeArrayType { |
| 663 | 657 | Expr resolved_expr; |
| 664 | 658 | }; |
| 665 | 659 | |
| 660 | struct AstNodeErrorType { | |
| 661 | // populated by semantic analyzer | |
| 662 | Expr resolved_expr; | |
| 663 | }; | |
| 664 | ||
| 666 | 665 | struct AstNode { |
| 667 | 666 | enum NodeType type; |
| 668 | 667 | int line; |
| ... | ... | @@ -705,7 +704,6 @@ struct AstNode { |
| 705 | 704 | AstNodeStringLiteral string_literal; |
| 706 | 705 | AstNodeCharLiteral char_literal; |
| 707 | 706 | AstNodeNumberLiteral number_literal; |
| 708 | AstNodeErrorLiteral error_literal; | |
| 709 | 707 | AstNodeContainerInitExpr container_init_expr; |
| 710 | 708 | AstNodeStructValueField struct_val_field; |
| 711 | 709 | AstNodeNullLiteral null_literal; |
| ... | ... | @@ -715,6 +713,7 @@ struct AstNode { |
| 715 | 713 | AstNodeBreakExpr break_expr; |
| 716 | 714 | AstNodeContinueExpr continue_expr; |
| 717 | 715 | AstNodeArrayType array_type; |
| 716 | AstNodeErrorType error_type; | |
| 718 | 717 | } data; |
| 719 | 718 | }; |
| 720 | 719 | |
| ... | ... | @@ -820,7 +819,8 @@ enum TypeTableEntryId { |
| 820 | 819 | TypeTableEntryIdNumLitInt, |
| 821 | 820 | TypeTableEntryIdUndefLit, |
| 822 | 821 | TypeTableEntryIdMaybe, |
| 823 | TypeTableEntryIdError, | |
| 822 | TypeTableEntryIdErrorUnion, | |
| 823 | TypeTableEntryIdPureError, | |
| 824 | 824 | TypeTableEntryIdEnum, |
| 825 | 825 | TypeTableEntryIdFn, |
| 826 | 826 | }; |
| ... | ... | @@ -961,6 +961,7 @@ struct CodeGen { |
| 961 | 961 | TypeTableEntry *entry_num_lit_int; |
| 962 | 962 | TypeTableEntry *entry_num_lit_float; |
| 963 | 963 | TypeTableEntry *entry_undef; |
| 964 | TypeTableEntry *entry_pure_error; | |
| 964 | 965 | } builtin_types; |
| 965 | 966 | |
| 966 | 967 | LLVMTargetDataRef target_data_ref; |
src/analyze.cpp+111-50| ... | ... | @@ -19,6 +19,8 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE |
| 19 | 19 | static TypeTableEntry *unwrapped_node_type(AstNode *node); |
| 20 | 20 | static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 21 | 21 | AstNode *node); |
| 22 | static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import, | |
| 23 | BlockContext *context, AstNode *node, Buf *err_name); | |
| 22 | 24 | |
| 23 | 25 | static AstNode *first_executing_node(AstNode *node) { |
| 24 | 26 | switch (node->type) { |
| ... | ... | @@ -47,7 +49,6 @@ static AstNode *first_executing_node(AstNode *node) { |
| 47 | 49 | case NodeTypeVariableDeclaration: |
| 48 | 50 | case NodeTypeErrorValueDecl: |
| 49 | 51 | case NodeTypeNumberLiteral: |
| 50 | case NodeTypeErrorLiteral: | |
| 51 | 52 | case NodeTypeStringLiteral: |
| 52 | 53 | case NodeTypeCharLiteral: |
| 53 | 54 | case NodeTypeSymbol: |
| ... | ... | @@ -71,6 +72,7 @@ static AstNode *first_executing_node(AstNode *node) { |
| 71 | 72 | case NodeTypeSwitchExpr: |
| 72 | 73 | case NodeTypeSwitchProng: |
| 73 | 74 | case NodeTypeArrayType: |
| 75 | case NodeTypeErrorType: | |
| 74 | 76 | case NodeTypeContainerInitExpr: |
| 75 | 77 | return node; |
| 76 | 78 | } |
| ... | ... | @@ -110,7 +112,8 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) { |
| 110 | 112 | case TypeTableEntryIdNumLitInt: |
| 111 | 113 | case TypeTableEntryIdMaybe: |
| 112 | 114 | case TypeTableEntryIdFn: |
| 113 | case TypeTableEntryIdError: | |
| 115 | case TypeTableEntryIdErrorUnion: | |
| 116 | case TypeTableEntryIdPureError: | |
| 114 | 117 | case TypeTableEntryIdUndefLit: |
| 115 | 118 | // nothing to init |
| 116 | 119 | break; |
| ... | ... | @@ -200,7 +203,7 @@ static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) { |
| 200 | 203 | "val", di_file, line, child_type->size_in_bits, child_type->align_in_bits, 0, 0, |
| 201 | 204 | child_type->di_type), |
| 202 | 205 | LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type), |
| 203 | "maybe", di_file, line, 8, 8, 8, 0, | |
| 206 | "maybe", di_file, line, 8, 8, child_type->size_in_bits, 0, | |
| 204 | 207 | child_type->di_type), |
| 205 | 208 | }; |
| 206 | 209 | LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder, |
| ... | ... | @@ -223,7 +226,7 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { |
| 223 | 226 | if (child_type->error_parent) { |
| 224 | 227 | return child_type->error_parent; |
| 225 | 228 | } else { |
| 226 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdError); | |
| 229 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion); | |
| 227 | 230 | assert(child_type->type_ref); |
| 228 | 231 | assert(child_type->di_type); |
| 229 | 232 | |
| ... | ... | @@ -239,7 +242,38 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) { |
| 239 | 242 | entry->di_type = g->err_tag_type->di_type; |
| 240 | 243 | |
| 241 | 244 | } else { |
| 242 | zig_panic("TODO get_error_type non-void"); | |
| 245 | LLVMTypeRef elem_types[] = { | |
| 246 | g->err_tag_type->type_ref, | |
| 247 | child_type->type_ref, | |
| 248 | }; | |
| 249 | entry->type_ref = LLVMStructType(elem_types, 2, false); | |
| 250 | entry->size_in_bits = g->err_tag_type->size_in_bits + child_type->size_in_bits; | |
| 251 | entry->align_in_bits = g->err_tag_type->align_in_bits; | |
| 252 | ||
| 253 | LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit); | |
| 254 | LLVMZigDIFile *di_file = nullptr; | |
| 255 | unsigned line = 0; | |
| 256 | entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder, | |
| 257 | LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name), | |
| 258 | compile_unit_scope, di_file, line); | |
| 259 | ||
| 260 | LLVMZigDIType *di_element_types[] = { | |
| 261 | LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type), | |
| 262 | "tag", di_file, line, g->err_tag_type->size_in_bits, g->err_tag_type->align_in_bits, | |
| 263 | 0, 0, child_type->di_type), | |
| 264 | LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type), | |
| 265 | "value", di_file, line, child_type->size_in_bits, child_type->align_in_bits, | |
| 266 | g->err_tag_type->size_in_bits, 0, child_type->di_type), | |
| 267 | }; | |
| 268 | ||
| 269 | LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder, | |
| 270 | compile_unit_scope, | |
| 271 | buf_ptr(&entry->name), | |
| 272 | di_file, line, entry->size_in_bits, entry->align_in_bits, 0, | |
| 273 | nullptr, di_element_types, 2, 0, nullptr, ""); | |
| 274 | ||
| 275 | LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type); | |
| 276 | entry->di_type = replacement_di_type; | |
| 243 | 277 | } |
| 244 | 278 | |
| 245 | 279 | child_type->error_parent = entry; |
| ... | ... | @@ -1012,7 +1046,6 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 1012 | 1046 | case NodeTypeArrayAccessExpr: |
| 1013 | 1047 | case NodeTypeSliceExpr: |
| 1014 | 1048 | case NodeTypeNumberLiteral: |
| 1015 | case NodeTypeErrorLiteral: | |
| 1016 | 1049 | case NodeTypeStringLiteral: |
| 1017 | 1050 | case NodeTypeCharLiteral: |
| 1018 | 1051 | case NodeTypeBoolLiteral: |
| ... | ... | @@ -1037,6 +1070,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 1037 | 1070 | case NodeTypeStructValueField: |
| 1038 | 1071 | case NodeTypeContainerInitExpr: |
| 1039 | 1072 | case NodeTypeArrayType: |
| 1073 | case NodeTypeErrorType: | |
| 1040 | 1074 | zig_unreachable(); |
| 1041 | 1075 | } |
| 1042 | 1076 | } |
| ... | ... | @@ -1083,7 +1117,8 @@ static bool type_has_codegen_value(TypeTableEntryId id) { |
| 1083 | 1117 | case TypeTableEntryIdArray: |
| 1084 | 1118 | case TypeTableEntryIdStruct: |
| 1085 | 1119 | case TypeTableEntryIdMaybe: |
| 1086 | case TypeTableEntryIdError: | |
| 1120 | case TypeTableEntryIdErrorUnion: | |
| 1121 | case TypeTableEntryIdPureError: | |
| 1087 | 1122 | case TypeTableEntryIdEnum: |
| 1088 | 1123 | case TypeTableEntryIdFn: |
| 1089 | 1124 | return true; |
| ... | ... | @@ -1166,8 +1201,8 @@ static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTable |
| 1166 | 1201 | } |
| 1167 | 1202 | |
| 1168 | 1203 | // error |
| 1169 | if (expected_type->id == TypeTableEntryIdError && | |
| 1170 | actual_type->id == TypeTableEntryIdError) | |
| 1204 | if (expected_type->id == TypeTableEntryIdErrorUnion && | |
| 1205 | actual_type->id == TypeTableEntryIdErrorUnion) | |
| 1171 | 1206 | { |
| 1172 | 1207 | return types_match_const_cast_only( |
| 1173 | 1208 | expected_type->data.error.child_type, |
| ... | ... | @@ -1224,11 +1259,11 @@ static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *pa |
| 1224 | 1259 | prev_type = cur_type; |
| 1225 | 1260 | prev_node = cur_node; |
| 1226 | 1261 | } |
| 1227 | } else if (prev_type->id == TypeTableEntryIdError && | |
| 1262 | } else if (prev_type->id == TypeTableEntryIdErrorUnion && | |
| 1228 | 1263 | types_match_const_cast_only(prev_type->data.error.child_type, cur_type)) |
| 1229 | 1264 | { |
| 1230 | 1265 | continue; |
| 1231 | } else if (cur_type->id == TypeTableEntryIdError && | |
| 1266 | } else if (cur_type->id == TypeTableEntryIdErrorUnion && | |
| 1232 | 1267 | types_match_const_cast_only(cur_type->data.error.child_type, prev_type)) |
| 1233 | 1268 | { |
| 1234 | 1269 | prev_type = cur_type; |
| ... | ... | @@ -1287,13 +1322,20 @@ static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_ |
| 1287 | 1322 | } |
| 1288 | 1323 | |
| 1289 | 1324 | // implicit conversion from error child type to error type |
| 1290 | if (expected_type->id == TypeTableEntryIdError && | |
| 1325 | if (expected_type->id == TypeTableEntryIdErrorUnion && | |
| 1291 | 1326 | types_match_with_implicit_cast(g, expected_type->data.error.child_type, actual_type, |
| 1292 | 1327 | literal_node, reported_err)) |
| 1293 | 1328 | { |
| 1294 | 1329 | return true; |
| 1295 | 1330 | } |
| 1296 | 1331 | |
| 1332 | // implicit conversion from pure error to error union type | |
| 1333 | if (expected_type->id == TypeTableEntryIdErrorUnion && | |
| 1334 | actual_type->id == TypeTableEntryIdPureError) | |
| 1335 | { | |
| 1336 | return true; | |
| 1337 | } | |
| 1338 | ||
| 1297 | 1339 | // implicit widening conversion |
| 1298 | 1340 | if (expected_type->id == TypeTableEntryIdInt && |
| 1299 | 1341 | actual_type->id == TypeTableEntryIdInt && |
| ... | ... | @@ -1695,12 +1737,11 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 1695 | 1737 | |
| 1696 | 1738 | AstNode *struct_expr_node = node->data.field_access_expr.struct_expr; |
| 1697 | 1739 | TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, struct_expr_node); |
| 1740 | Buf *field_name = &node->data.field_access_expr.field_name; | |
| 1698 | 1741 | |
| 1699 | 1742 | if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer && |
| 1700 | 1743 | struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)) |
| 1701 | 1744 | { |
| 1702 | Buf *field_name = &node->data.field_access_expr.field_name; | |
| 1703 | ||
| 1704 | 1745 | TypeTableEntry *bare_struct_type = (struct_type->id == TypeTableEntryIdStruct) ? |
| 1705 | 1746 | struct_type : struct_type->data.pointer.child_type; |
| 1706 | 1747 | |
| ... | ... | @@ -1713,15 +1754,14 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 1713 | 1754 | return g->builtin_types.entry_invalid; |
| 1714 | 1755 | } |
| 1715 | 1756 | } else if (struct_type->id == TypeTableEntryIdArray) { |
| 1716 | Buf *name = &node->data.field_access_expr.field_name; | |
| 1717 | if (buf_eql_str(name, "len")) { | |
| 1757 | if (buf_eql_str(field_name, "len")) { | |
| 1718 | 1758 | return g->builtin_types.entry_isize; |
| 1719 | } else if (buf_eql_str(name, "ptr")) { | |
| 1759 | } else if (buf_eql_str(field_name, "ptr")) { | |
| 1720 | 1760 | // TODO determine whether the pointer should be const |
| 1721 | 1761 | return get_pointer_to_type(g, struct_type->data.array.child_type, false); |
| 1722 | 1762 | } else { |
| 1723 | 1763 | add_node_error(g, node, |
| 1724 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(name), | |
| 1764 | buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name), | |
| 1725 | 1765 | buf_ptr(&struct_type->name))); |
| 1726 | 1766 | return g->builtin_types.entry_invalid; |
| 1727 | 1767 | } |
| ... | ... | @@ -1731,8 +1771,9 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i |
| 1731 | 1771 | if (enum_type->id == TypeTableEntryIdInvalid) { |
| 1732 | 1772 | return g->builtin_types.entry_invalid; |
| 1733 | 1773 | } else if (enum_type->id == TypeTableEntryIdEnum) { |
| 1734 | Buf *field_name = &node->data.field_access_expr.field_name; | |
| 1735 | 1774 | return analyze_enum_value_expr(g, import, context, node, nullptr, enum_type, field_name); |
| 1775 | } else if (enum_type->id == TypeTableEntryIdPureError) { | |
| 1776 | return analyze_error_literal_expr(g, import, context, node, field_name); | |
| 1736 | 1777 | } else { |
| 1737 | 1778 | add_node_error(g, node, |
| 1738 | 1779 | buf_sprintf("type '%s' does not support field access", buf_ptr(&struct_type->name))); |
| ... | ... | @@ -1846,7 +1887,7 @@ static TypeTableEntry *resolve_expr_const_val_as_err(CodeGen *g, AstNode *node, |
| 1846 | 1887 | Expr *expr = get_resolved_expr(node); |
| 1847 | 1888 | expr->const_val.ok = true; |
| 1848 | 1889 | expr->const_val.data.x_err.err = err; |
| 1849 | return get_error_type(g, g->builtin_types.entry_void); | |
| 1890 | return g->builtin_types.entry_pure_error; | |
| 1850 | 1891 | } |
| 1851 | 1892 | |
| 1852 | 1893 | static TypeTableEntry *resolve_expr_const_val_as_bool(CodeGen *g, AstNode *node, bool value) { |
| ... | ... | @@ -1959,6 +2000,21 @@ static TypeTableEntry *resolve_expr_const_val_as_bignum_op(CodeGen *g, AstNode * |
| 1959 | 2000 | return resolved_type; |
| 1960 | 2001 | } |
| 1961 | 2002 | |
| 2003 | static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import, | |
| 2004 | BlockContext *context, AstNode *node, Buf *err_name) | |
| 2005 | { | |
| 2006 | auto err_table_entry = import->block_context->error_table.maybe_get(err_name); | |
| 2007 | ||
| 2008 | if (err_table_entry) { | |
| 2009 | return resolve_expr_const_val_as_err(g, node, err_table_entry->value); | |
| 2010 | } | |
| 2011 | ||
| 2012 | add_node_error(g, node, | |
| 2013 | buf_sprintf("use of undeclared error value '%s'", buf_ptr(err_name))); | |
| 2014 | ||
| 2015 | return get_error_type(g, g->builtin_types.entry_void); | |
| 2016 | } | |
| 2017 | ||
| 1962 | 2018 | |
| 1963 | 2019 | static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 1964 | 2020 | TypeTableEntry *expected_type, AstNode *node) |
| ... | ... | @@ -2564,23 +2620,6 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry |
| 2564 | 2620 | } |
| 2565 | 2621 | } |
| 2566 | 2622 | |
| 2567 | static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import, | |
| 2568 | BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node) | |
| 2569 | { | |
| 2570 | Buf *err_name = &node->data.error_literal.symbol; | |
| 2571 | ||
| 2572 | auto err_table_entry = import->block_context->error_table.maybe_get(err_name); | |
| 2573 | ||
| 2574 | if (err_table_entry) { | |
| 2575 | return resolve_expr_const_val_as_err(g, node, err_table_entry->value); | |
| 2576 | } | |
| 2577 | ||
| 2578 | add_node_error(g, node, | |
| 2579 | buf_sprintf("use of undeclared error value '%s'", buf_ptr(err_name))); | |
| 2580 | ||
| 2581 | return get_error_type(g, g->builtin_types.entry_void); | |
| 2582 | } | |
| 2583 | ||
| 2584 | 2623 | static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context, |
| 2585 | 2624 | TypeTableEntry *expected_type, AstNode *node) |
| 2586 | 2625 | { |
| ... | ... | @@ -2906,6 +2945,10 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex |
| 2906 | 2945 | const_val->data.x_err.payload = other_val; |
| 2907 | 2946 | const_val->ok = true; |
| 2908 | 2947 | break; |
| 2948 | case CastOpPureErrorWrap: | |
| 2949 | const_val->data.x_err.err = other_val->data.x_err.err; | |
| 2950 | const_val->ok = true; | |
| 2951 | break; | |
| 2909 | 2952 | case CastOpErrToInt: |
| 2910 | 2953 | { |
| 2911 | 2954 | uint64_t value = other_val->data.x_err.err ? other_val->data.x_err.err->value : 0; |
| ... | ... | @@ -3007,7 +3050,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 3007 | 3050 | } |
| 3008 | 3051 | |
| 3009 | 3052 | // explicit cast from child type of error type to error type |
| 3010 | if (wanted_type->id == TypeTableEntryIdError) { | |
| 3053 | if (wanted_type->id == TypeTableEntryIdErrorUnion) { | |
| 3011 | 3054 | if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) { |
| 3012 | 3055 | node->data.fn_call_expr.cast_op = CastOpErrorWrap; |
| 3013 | 3056 | eval_const_expr_implicit_cast(g, node, expr_node); |
| ... | ... | @@ -3025,6 +3068,15 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 3025 | 3068 | } |
| 3026 | 3069 | } |
| 3027 | 3070 | |
| 3071 | // explicit cast from pure error to error union type | |
| 3072 | if (wanted_type->id == TypeTableEntryIdErrorUnion && | |
| 3073 | actual_type->id == TypeTableEntryIdPureError) | |
| 3074 | { | |
| 3075 | node->data.fn_call_expr.cast_op = CastOpPureErrorWrap; | |
| 3076 | eval_const_expr_implicit_cast(g, node, expr_node); | |
| 3077 | return wanted_type; | |
| 3078 | } | |
| 3079 | ||
| 3028 | 3080 | // explicit cast from number literal to another type |
| 3029 | 3081 | if (actual_type->id == TypeTableEntryIdNumLitFloat || |
| 3030 | 3082 | actual_type->id == TypeTableEntryIdNumLitInt) |
| ... | ... | @@ -3039,8 +3091,10 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B |
| 3039 | 3091 | } |
| 3040 | 3092 | |
| 3041 | 3093 | // explicit cast from %void to integer type which can fit it |
| 3042 | if (actual_type->id == TypeTableEntryIdError && | |
| 3043 | actual_type->data.error.child_type->size_in_bits == 0 && | |
| 3094 | bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion && | |
| 3095 | actual_type->data.error.child_type->size_in_bits == 0; | |
| 3096 | bool actual_type_is_pure_err = actual_type->id == TypeTableEntryIdPureError; | |
| 3097 | if ((actual_type_is_void_err || actual_type_is_pure_err) && | |
| 3044 | 3098 | wanted_type->id == TypeTableEntryIdInt) |
| 3045 | 3099 | { |
| 3046 | 3100 | BigNum bn; |
| ... | ... | @@ -3754,9 +3808,6 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 3754 | 3808 | case NodeTypeNumberLiteral: |
| 3755 | 3809 | return_type = analyze_number_literal_expr(g, import, context, expected_type, node); |
| 3756 | 3810 | break; |
| 3757 | case NodeTypeErrorLiteral: | |
| 3758 | return_type = analyze_error_literal_expr(g, import, context, expected_type, node); | |
| 3759 | break; | |
| 3760 | 3811 | case NodeTypeStringLiteral: |
| 3761 | 3812 | return_type = analyze_string_literal_expr(g, import, context, expected_type, node); |
| 3762 | 3813 | break; |
| ... | ... | @@ -3794,6 +3845,9 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, |
| 3794 | 3845 | case NodeTypeArrayType: |
| 3795 | 3846 | return_type = analyze_array_type(g, import, context, expected_type, node); |
| 3796 | 3847 | break; |
| 3848 | case NodeTypeErrorType: | |
| 3849 | return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_pure_error); | |
| 3850 | break; | |
| 3797 | 3851 | case NodeTypeSwitchExpr: |
| 3798 | 3852 | return_type = analyze_switch_expr(g, import, context, expected_type, node); |
| 3799 | 3853 | break; |
| ... | ... | @@ -3933,7 +3987,6 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 3933 | 3987 | case NodeTypeArrayAccessExpr: |
| 3934 | 3988 | case NodeTypeSliceExpr: |
| 3935 | 3989 | case NodeTypeNumberLiteral: |
| 3936 | case NodeTypeErrorLiteral: | |
| 3937 | 3990 | case NodeTypeStringLiteral: |
| 3938 | 3991 | case NodeTypeCharLiteral: |
| 3939 | 3992 | case NodeTypeBoolLiteral: |
| ... | ... | @@ -3958,6 +4011,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode |
| 3958 | 4011 | case NodeTypeStructValueField: |
| 3959 | 4012 | case NodeTypeContainerInitExpr: |
| 3960 | 4013 | case NodeTypeArrayType: |
| 4014 | case NodeTypeErrorType: | |
| 3961 | 4015 | zig_unreachable(); |
| 3962 | 4016 | } |
| 3963 | 4017 | } |
| ... | ... | @@ -3967,7 +4021,6 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode |
| 3967 | 4021 | { |
| 3968 | 4022 | switch (node->type) { |
| 3969 | 4023 | case NodeTypeNumberLiteral: |
| 3970 | case NodeTypeErrorLiteral: | |
| 3971 | 4024 | case NodeTypeStringLiteral: |
| 3972 | 4025 | case NodeTypeCharLiteral: |
| 3973 | 4026 | case NodeTypeBoolLiteral: |
| ... | ... | @@ -3977,6 +4030,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode |
| 3977 | 4030 | case NodeTypeBreak: |
| 3978 | 4031 | case NodeTypeContinue: |
| 3979 | 4032 | case NodeTypeErrorValueDecl: |
| 4033 | case NodeTypeErrorType: | |
| 3980 | 4034 | // no dependencies on other top level declarations |
| 3981 | 4035 | break; |
| 3982 | 4036 | case NodeTypeSymbol: |
| ... | ... | @@ -4286,7 +4340,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 4286 | 4340 | case NodeTypeArrayAccessExpr: |
| 4287 | 4341 | case NodeTypeSliceExpr: |
| 4288 | 4342 | case NodeTypeNumberLiteral: |
| 4289 | case NodeTypeErrorLiteral: | |
| 4290 | 4343 | case NodeTypeStringLiteral: |
| 4291 | 4344 | case NodeTypeCharLiteral: |
| 4292 | 4345 | case NodeTypeBoolLiteral: |
| ... | ... | @@ -4311,6 +4364,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast |
| 4311 | 4364 | case NodeTypeContainerInitExpr: |
| 4312 | 4365 | case NodeTypeStructValueField: |
| 4313 | 4366 | case NodeTypeArrayType: |
| 4367 | case NodeTypeErrorType: | |
| 4314 | 4368 | zig_unreachable(); |
| 4315 | 4369 | } |
| 4316 | 4370 | } |
| ... | ... | @@ -4419,7 +4473,14 @@ void semantic_analyze(CodeGen *g) { |
| 4419 | 4473 | } |
| 4420 | 4474 | } |
| 4421 | 4475 | |
| 4422 | g->err_tag_type = get_smallest_unsigned_int_type(g, g->error_value_count); | |
| 4476 | { | |
| 4477 | g->err_tag_type = get_smallest_unsigned_int_type(g, g->error_value_count); | |
| 4478 | ||
| 4479 | g->builtin_types.entry_pure_error->type_ref = g->err_tag_type->type_ref; | |
| 4480 | g->builtin_types.entry_pure_error->size_in_bits = g->err_tag_type->size_in_bits; | |
| 4481 | g->builtin_types.entry_pure_error->align_in_bits = g->err_tag_type->align_in_bits; | |
| 4482 | g->builtin_types.entry_pure_error->di_type = g->err_tag_type->di_type; | |
| 4483 | } | |
| 4423 | 4484 | |
| 4424 | 4485 | { |
| 4425 | 4486 | auto it = g->import_table.entry_iterator(); |
| ... | ... | @@ -4493,8 +4554,6 @@ Expr *get_resolved_expr(AstNode *node) { |
| 4493 | 4554 | return &node->data.container_init_expr.resolved_expr; |
| 4494 | 4555 | case NodeTypeNumberLiteral: |
| 4495 | 4556 | return &node->data.number_literal.resolved_expr; |
| 4496 | case NodeTypeErrorLiteral: | |
| 4497 | return &node->data.error_literal.resolved_expr; | |
| 4498 | 4557 | case NodeTypeStringLiteral: |
| 4499 | 4558 | return &node->data.string_literal.resolved_expr; |
| 4500 | 4559 | case NodeTypeBlock: |
| ... | ... | @@ -4521,6 +4580,8 @@ Expr *get_resolved_expr(AstNode *node) { |
| 4521 | 4580 | return &node->data.label.resolved_expr; |
| 4522 | 4581 | case NodeTypeArrayType: |
| 4523 | 4582 | return &node->data.array_type.resolved_expr; |
| 4583 | case NodeTypeErrorType: | |
| 4584 | return &node->data.error_type.resolved_expr; | |
| 4524 | 4585 | case NodeTypeSwitchExpr: |
| 4525 | 4586 | return &node->data.switch_expr.resolved_expr; |
| 4526 | 4587 | case NodeTypeSwitchProng: |
| ... | ... | @@ -4554,7 +4615,6 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) { |
| 4554 | 4615 | case NodeTypeErrorValueDecl: |
| 4555 | 4616 | return &node->data.error_value_decl.top_level_decl; |
| 4556 | 4617 | case NodeTypeNumberLiteral: |
| 4557 | case NodeTypeErrorLiteral: | |
| 4558 | 4618 | case NodeTypeReturnExpr: |
| 4559 | 4619 | case NodeTypeBinOpExpr: |
| 4560 | 4620 | case NodeTypePrefixOpExpr: |
| ... | ... | @@ -4593,6 +4653,7 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) { |
| 4593 | 4653 | case NodeTypeStructField: |
| 4594 | 4654 | case NodeTypeStructValueField: |
| 4595 | 4655 | case NodeTypeArrayType: |
| 4656 | case NodeTypeErrorType: | |
| 4596 | 4657 | zig_unreachable(); |
| 4597 | 4658 | } |
| 4598 | 4659 | zig_unreachable(); |
src/codegen.cpp+39-7| ... | ... | @@ -306,7 +306,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { |
| 306 | 306 | case CastOpNoop: |
| 307 | 307 | return expr_val; |
| 308 | 308 | case CastOpErrToInt: |
| 309 | assert(actual_type->id == TypeTableEntryIdError); | |
| 309 | assert(actual_type->id == TypeTableEntryIdErrorUnion); | |
| 310 | 310 | if (actual_type->data.error.child_type->size_in_bits == 0) { |
| 311 | 311 | return gen_widen_or_shorten(g, node, g->err_tag_type, wanted_type, expr_val); |
| 312 | 312 | } else { |
| ... | ... | @@ -330,12 +330,19 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) { |
| 330 | 330 | return cast_expr->tmp_ptr; |
| 331 | 331 | } |
| 332 | 332 | case CastOpErrorWrap: |
| 333 | assert(wanted_type->id == TypeTableEntryIdError); | |
| 333 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); | |
| 334 | 334 | if (wanted_type->data.error.child_type->size_in_bits == 0) { |
| 335 | 335 | return LLVMConstNull(g->err_tag_type->type_ref); |
| 336 | 336 | } else { |
| 337 | 337 | zig_panic("TODO"); |
| 338 | 338 | } |
| 339 | case CastOpPureErrorWrap: | |
| 340 | assert(wanted_type->id == TypeTableEntryIdErrorUnion); | |
| 341 | if (wanted_type->data.error.child_type->size_in_bits == 0) { | |
| 342 | return expr_val; | |
| 343 | } else { | |
| 344 | zig_panic("TODO"); | |
| 345 | } | |
| 339 | 346 | case CastOpPtrToInt: |
| 340 | 347 | add_debug_source_node(g, node); |
| 341 | 348 | return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, ""); |
| ... | ... | @@ -1292,7 +1299,7 @@ static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMV |
| 1292 | 1299 | return nullptr; |
| 1293 | 1300 | } |
| 1294 | 1301 | |
| 1295 | assert(!use_expr_value || then_type->id == TypeTableEntryIdError); | |
| 1302 | assert(!use_expr_value || then_type->id == TypeTableEntryIdErrorUnion); | |
| 1296 | 1303 | |
| 1297 | 1304 | LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then"); |
| 1298 | 1305 | LLVMBasicBlockRef endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf"); |
| ... | ... | @@ -2011,7 +2018,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 2011 | 2018 | return gen_container_init_expr(g, node); |
| 2012 | 2019 | case NodeTypeSwitchExpr: |
| 2013 | 2020 | return gen_switch_expr(g, node); |
| 2014 | case NodeTypeErrorLiteral: | |
| 2015 | 2021 | case NodeTypeNumberLiteral: |
| 2016 | 2022 | case NodeTypeBoolLiteral: |
| 2017 | 2023 | case NodeTypeStringLiteral: |
| ... | ... | @@ -2033,6 +2039,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) { |
| 2033 | 2039 | case NodeTypeStructField: |
| 2034 | 2040 | case NodeTypeStructValueField: |
| 2035 | 2041 | case NodeTypeArrayType: |
| 2042 | case NodeTypeErrorType: | |
| 2036 | 2043 | case NodeTypeSwitchProng: |
| 2037 | 2044 | case NodeTypeSwitchRange: |
| 2038 | 2045 | case NodeTypeErrorValueDecl: |
| ... | ... | @@ -2063,6 +2070,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE |
| 2063 | 2070 | |
| 2064 | 2071 | if (type_entry->id == TypeTableEntryIdInt) { |
| 2065 | 2072 | return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false); |
| 2073 | } else if (type_entry->id == TypeTableEntryIdPureError) { | |
| 2074 | assert(const_val->data.x_err.err); | |
| 2075 | return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref, const_val->data.x_err.err->value, false); | |
| 2066 | 2076 | } else if (type_entry->id == TypeTableEntryIdFloat) { |
| 2067 | 2077 | if (const_val->data.x_bignum.kind == BigNumKindFloat) { |
| 2068 | 2078 | return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float); |
| ... | ... | @@ -2148,12 +2158,26 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE |
| 2148 | 2158 | } else { |
| 2149 | 2159 | return global_value; |
| 2150 | 2160 | } |
| 2151 | } else if (type_entry->id == TypeTableEntryIdError) { | |
| 2152 | if (type_entry->data.error.child_type->size_in_bits == 0) { | |
| 2161 | } else if (type_entry->id == TypeTableEntryIdErrorUnion) { | |
| 2162 | TypeTableEntry *child_type = type_entry->data.error.child_type; | |
| 2163 | if (child_type->size_in_bits == 0) { | |
| 2153 | 2164 | uint64_t value = const_val->data.x_err.err ? const_val->data.x_err.err->value : 0; |
| 2154 | 2165 | return LLVMConstInt(g->err_tag_type->type_ref, value, false); |
| 2155 | 2166 | } else { |
| 2156 | zig_panic("TODO"); | |
| 2167 | LLVMValueRef err_tag_value; | |
| 2168 | LLVMValueRef err_payload_value; | |
| 2169 | if (const_val->data.x_err.err) { | |
| 2170 | err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err.err->value, false); | |
| 2171 | err_payload_value = LLVMConstNull(child_type->type_ref); | |
| 2172 | } else { | |
| 2173 | err_tag_value = LLVMConstNull(g->err_tag_type->type_ref); | |
| 2174 | err_payload_value = gen_const_val(g, child_type, const_val->data.x_err.payload); | |
| 2175 | } | |
| 2176 | LLVMValueRef fields[] = { | |
| 2177 | err_tag_value, | |
| 2178 | err_payload_value, | |
| 2179 | }; | |
| 2180 | return LLVMConstStruct(fields, 2, false); | |
| 2157 | 2181 | } |
| 2158 | 2182 | } else { |
| 2159 | 2183 | zig_unreachable(); |
| ... | ... | @@ -2557,6 +2581,14 @@ static void define_builtin_types(CodeGen *g) { |
| 2557 | 2581 | g->builtin_types.entry_type = entry; |
| 2558 | 2582 | g->primitive_type_table.put(&entry->name, entry); |
| 2559 | 2583 | } |
| 2584 | { | |
| 2585 | // partially complete the error type. we complete it later after we know | |
| 2586 | // error_value_count. | |
| 2587 | TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError); | |
| 2588 | buf_init_from_str(&entry->name, "error"); | |
| 2589 | g->builtin_types.entry_pure_error = entry; | |
| 2590 | g->primitive_type_table.put(&entry->name, entry); | |
| 2591 | } | |
| 2560 | 2592 | |
| 2561 | 2593 | g->builtin_types.entry_u8 = get_int_type(g, false, 8); |
| 2562 | 2594 | g->builtin_types.entry_u16 = get_int_type(g, false, 16); |
src/parser.cpp+18-22| ... | ... | @@ -113,8 +113,6 @@ const char *node_type_str(NodeType node_type) { |
| 113 | 113 | return "ErrorValueDecl"; |
| 114 | 114 | case NodeTypeNumberLiteral: |
| 115 | 115 | return "NumberLiteral"; |
| 116 | case NodeTypeErrorLiteral: | |
| 117 | return "ErrorLiteral"; | |
| 118 | 116 | case NodeTypeStringLiteral: |
| 119 | 117 | return "StringLiteral"; |
| 120 | 118 | case NodeTypeCharLiteral: |
| ... | ... | @@ -167,6 +165,8 @@ const char *node_type_str(NodeType node_type) { |
| 167 | 165 | return "ContainerInitExpr"; |
| 168 | 166 | case NodeTypeArrayType: |
| 169 | 167 | return "ArrayType"; |
| 168 | case NodeTypeErrorType: | |
| 169 | return "ErrorType"; | |
| 170 | 170 | } |
| 171 | 171 | zig_unreachable(); |
| 172 | 172 | } |
| ... | ... | @@ -313,11 +313,6 @@ void ast_print(AstNode *node, int indent) { |
| 313 | 313 | } |
| 314 | 314 | break; |
| 315 | 315 | } |
| 316 | case NodeTypeErrorLiteral: | |
| 317 | { | |
| 318 | fprintf(stderr, "%s '%s'", node_type_str(node->type), buf_ptr(&node->data.error_literal.symbol)); | |
| 319 | break; | |
| 320 | } | |
| 321 | 316 | case NodeTypeStringLiteral: |
| 322 | 317 | { |
| 323 | 318 | const char *c = node->data.string_literal.c ? "c" : ""; |
| ... | ... | @@ -465,6 +460,9 @@ void ast_print(AstNode *node, int indent) { |
| 465 | 460 | ast_print(node->data.array_type.child_type, indent + 2); |
| 466 | 461 | break; |
| 467 | 462 | } |
| 463 | case NodeTypeErrorType: | |
| 464 | fprintf(stderr, "%s\n", node_type_str(node->type)); | |
| 465 | break; | |
| 468 | 466 | } |
| 469 | 467 | } |
| 470 | 468 | |
| ... | ... | @@ -1372,8 +1370,8 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand |
| 1372 | 1370 | } |
| 1373 | 1371 | |
| 1374 | 1372 | /* |
| 1375 | PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("%." "Symbol") | |
| 1376 | KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined" | |
| 1373 | PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("error" "." "Symbol") | |
| 1374 | KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined" | "error" | |
| 1377 | 1375 | */ |
| 1378 | 1376 | static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) { |
| 1379 | 1377 | Token *token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -1419,6 +1417,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1419 | 1417 | AstNode *node = ast_create_node(pc, NodeTypeUndefinedLiteral, token); |
| 1420 | 1418 | *token_index += 1; |
| 1421 | 1419 | return node; |
| 1420 | } else if (token->id == TokenIdKeywordError) { | |
| 1421 | AstNode *node = ast_create_node(pc, NodeTypeErrorType, token); | |
| 1422 | *token_index += 1; | |
| 1423 | return node; | |
| 1422 | 1424 | } else if (token->id == TokenIdAtSign) { |
| 1423 | 1425 | *token_index += 1; |
| 1424 | 1426 | Token *name_tok = ast_eat_token(pc, token_index, TokenIdSymbol); |
| ... | ... | @@ -1448,12 +1450,6 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool |
| 1448 | 1450 | |
| 1449 | 1451 | ast_buf_from_token(pc, dest_symbol, &node->data.goto_expr.name); |
| 1450 | 1452 | return node; |
| 1451 | } else if (token->id == TokenIdPercentDot) { | |
| 1452 | *token_index += 1; | |
| 1453 | Token *symbol_tok = ast_eat_token(pc, token_index, TokenIdSymbol); | |
| 1454 | AstNode *node = ast_create_node(pc, NodeTypeErrorLiteral, token); | |
| 1455 | ast_buf_from_token(pc, symbol_tok, &node->data.error_literal.symbol); | |
| 1456 | return node; | |
| 1457 | 1453 | } |
| 1458 | 1454 | |
| 1459 | 1455 | AstNode *grouped_expr_node = ast_parse_grouped_expr(pc, token_index, false); |
| ... | ... | @@ -2969,7 +2965,7 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) { |
| 2969 | 2965 | } |
| 2970 | 2966 | |
| 2971 | 2967 | /* |
| 2972 | ErrorValueDecl : option(FnVisibleMod) "%." "Symbol" | |
| 2968 | ErrorValueDecl : option(FnVisibleMod) "error" "Symbol" | |
| 2973 | 2969 | */ |
| 2974 | 2970 | static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index, bool mandatory) { |
| 2975 | 2971 | Token *first_token = &pc->tokens->at(*token_index); |
| ... | ... | @@ -2978,7 +2974,7 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index, b |
| 2978 | 2974 | |
| 2979 | 2975 | if (first_token->id == TokenIdKeywordPub) { |
| 2980 | 2976 | Token *next_token = &pc->tokens->at(*token_index + 1); |
| 2981 | if (next_token->id == TokenIdPercentDot) { | |
| 2977 | if (next_token->id == TokenIdKeywordError) { | |
| 2982 | 2978 | visib_mod = VisibModPub; |
| 2983 | 2979 | *token_index += 2; |
| 2984 | 2980 | } else if (mandatory) { |
| ... | ... | @@ -2988,7 +2984,7 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index, b |
| 2988 | 2984 | } |
| 2989 | 2985 | } else if (first_token->id == TokenIdKeywordExport) { |
| 2990 | 2986 | Token *next_token = &pc->tokens->at(*token_index + 1); |
| 2991 | if (next_token->id == TokenIdPercentDot) { | |
| 2987 | if (next_token->id == TokenIdKeywordError) { | |
| 2992 | 2988 | visib_mod = VisibModExport; |
| 2993 | 2989 | *token_index += 2; |
| 2994 | 2990 | } else if (mandatory) { |
| ... | ... | @@ -2996,7 +2992,7 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index, b |
| 2996 | 2992 | } else { |
| 2997 | 2993 | return nullptr; |
| 2998 | 2994 | } |
| 2999 | } else if (first_token->id == TokenIdPercentDot) { | |
| 2995 | } else if (first_token->id == TokenIdKeywordError) { | |
| 3000 | 2996 | visib_mod = VisibModPrivate; |
| 3001 | 2997 | *token_index += 1; |
| 3002 | 2998 | } else if (mandatory) { |
| ... | ... | @@ -3177,9 +3173,6 @@ void normalize_parent_ptrs(AstNode *node) { |
| 3177 | 3173 | case NodeTypeCharLiteral: |
| 3178 | 3174 | // none |
| 3179 | 3175 | break; |
| 3180 | case NodeTypeErrorLiteral: | |
| 3181 | // none | |
| 3182 | break; | |
| 3183 | 3176 | case NodeTypeSymbol: |
| 3184 | 3177 | // none |
| 3185 | 3178 | break; |
| ... | ... | @@ -3290,5 +3283,8 @@ void normalize_parent_ptrs(AstNode *node) { |
| 3290 | 3283 | set_field(&node->data.array_type.size); |
| 3291 | 3284 | set_field(&node->data.array_type.child_type); |
| 3292 | 3285 | break; |
| 3286 | case NodeTypeErrorType: | |
| 3287 | // none | |
| 3288 | break; | |
| 3293 | 3289 | } |
| 3294 | 3290 | } |
src/tokenizer.cpp+3| ... | ... | @@ -247,6 +247,8 @@ static void end_token(Tokenize *t) { |
| 247 | 247 | t->cur_tok->id = TokenIdKeywordSwitch; |
| 248 | 248 | } else if (mem_eql_str(token_mem, token_len, "undefined")) { |
| 249 | 249 | t->cur_tok->id = TokenIdKeywordUndefined; |
| 250 | } else if (mem_eql_str(token_mem, token_len, "error")) { | |
| 251 | t->cur_tok->id = TokenIdKeywordError; | |
| 250 | 252 | } |
| 251 | 253 | |
| 252 | 254 | t->cur_tok = nullptr; |
| ... | ... | @@ -1046,6 +1048,7 @@ const char * token_name(TokenId id) { |
| 1046 | 1048 | case TokenIdKeywordNoAlias: return "noalias"; |
| 1047 | 1049 | case TokenIdKeywordSwitch: return "switch"; |
| 1048 | 1050 | case TokenIdKeywordUndefined: return "undefined"; |
| 1051 | case TokenIdKeywordError: return "error"; | |
| 1049 | 1052 | case TokenIdLParen: return "("; |
| 1050 | 1053 | case TokenIdRParen: return ")"; |
| 1051 | 1054 | case TokenIdComma: return ","; |
src/tokenizer.hpp+1| ... | ... | @@ -38,6 +38,7 @@ enum TokenId { |
| 38 | 38 | TokenIdKeywordNoAlias, |
| 39 | 39 | TokenIdKeywordSwitch, |
| 40 | 40 | TokenIdKeywordUndefined, |
| 41 | TokenIdKeywordError, | |
| 41 | 42 | TokenIdLParen, |
| 42 | 43 | TokenIdRParen, |
| 43 | 44 | TokenIdComma, |
std/std.zig+23-23| ... | ... | @@ -25,15 +25,15 @@ pub var stderr = OutStream { |
| 25 | 25 | }; |
| 26 | 26 | */ |
| 27 | 27 | |
| 28 | pub %.Unexpected; | |
| 29 | pub %.DiskQuota; | |
| 30 | pub %.FileTooBig; | |
| 31 | pub %.SigInterrupt; | |
| 32 | pub %.Io; | |
| 33 | pub %.NoSpaceLeft; | |
| 34 | pub %.BadPerm; | |
| 35 | pub %.PipeFail; | |
| 36 | pub %.Invalid; | |
| 28 | pub error Unexpected; | |
| 29 | pub error DiskQuota; | |
| 30 | pub error FileTooBig; | |
| 31 | pub error SigInterrupt; | |
| 32 | pub error Io; | |
| 33 | pub error NoSpaceLeft; | |
| 34 | pub error BadPerm; | |
| 35 | pub error PipeFail; | |
| 36 | pub error Invalid; | |
| 37 | 37 | |
| 38 | 38 | const buffer_size = 4 * 1024; |
| 39 | 39 | const max_u64_base10_digits = 20; |
| ... | ... | @@ -100,14 +100,14 @@ pub struct OutStream { |
| 100 | 100 | os.index = 0; |
| 101 | 101 | switch (write(os.fd, os.buffer.ptr, amt_to_write)) { |
| 102 | 102 | EINVAL => unreachable{}, |
| 103 | EDQUOT => %.DiskQuota, | |
| 104 | EFBIG => %.FileTooBig, | |
| 105 | EINTR => %.SigInterrupt, | |
| 106 | EIO => %.Io, | |
| 107 | ENOSPC => %.NoSpaceLeft, | |
| 108 | EPERM => %.BadPerm, | |
| 109 | EPIPE => %.PipeFail, | |
| 110 | else => %.Unexpected, | |
| 103 | EDQUOT => error.DiskQuota, | |
| 104 | EFBIG => error.FileTooBig, | |
| 105 | EINTR => error.SigInterrupt, | |
| 106 | EIO => error.Io, | |
| 107 | ENOSPC => error.NoSpaceLeft, | |
| 108 | EPERM => error.BadPerm, | |
| 109 | EPIPE => error.PipeFail, | |
| 110 | else => error.Unexpected, | |
| 111 | 111 | } |
| 112 | 112 | } |
| 113 | 113 | } |
| ... | ... | @@ -121,10 +121,10 @@ pub struct InStream { |
| 121 | 121 | switch (-amt_read) { |
| 122 | 122 | EINVAL => unreachable{}, |
| 123 | 123 | EFAULT => unreachable{}, |
| 124 | EBADF => %.BadFd, | |
| 125 | EINTR => %.SigInterrupt, | |
| 126 | EIO => %.Io, | |
| 127 | else => %.Unexpected, | |
| 124 | EBADF => error.BadFd, | |
| 125 | EINTR => error.SigInterrupt, | |
| 126 | EIO => error.Io, | |
| 127 | else => error.Unexpected, | |
| 128 | 128 | } |
| 129 | 129 | } |
| 130 | 130 | return amt_read; |
| ... | ... | @@ -136,8 +136,8 @@ pub fn os_get_random_bytes(buf: []u8) %void => { |
| 136 | 136 | switch (getrandom(buf.ptr, buf.len, 0)) { |
| 137 | 137 | EINVAL => unreachable{}, |
| 138 | 138 | EFAULT => unreachable{}, |
| 139 | EINTR => %.SigInterrupt, | |
| 140 | else => %.Unexpected, | |
| 139 | EINTR => error.SigInterrupt, | |
| 140 | else => error.Unexpected, | |
| 141 | 141 | } |
| 142 | 142 | } |
| 143 | 143 | */ |
test/run_tests.cpp+6-6| ... | ... | @@ -1213,11 +1213,11 @@ pub fn main(args: [][]u8) %void => { |
| 1213 | 1213 | |
| 1214 | 1214 | add_simple_case("error values", R"SOURCE( |
| 1215 | 1215 | import "std.zig"; |
| 1216 | %.err1; | |
| 1217 | %.err2; | |
| 1216 | error err1; | |
| 1217 | error err2; | |
| 1218 | 1218 | pub fn main(args: [][]u8) %void => { |
| 1219 | const a = i32(%.err1); | |
| 1220 | const b = i32(%.err2); | |
| 1219 | const a = i32(error.err1); | |
| 1220 | const b = i32(error.err2); | |
| 1221 | 1221 | if (a == b) { |
| 1222 | 1222 | print_str("BAD\n"); |
| 1223 | 1223 | } |
| ... | ... | @@ -1467,8 +1467,8 @@ enum A {} |
| 1467 | 1467 | )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'A'"); |
| 1468 | 1468 | |
| 1469 | 1469 | add_compile_fail_case("redefinition of error values", R"SOURCE( |
| 1470 | %.A; | |
| 1471 | %.A; | |
| 1470 | error A; | |
| 1471 | error A; | |
| 1472 | 1472 | )SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of error 'A'"); |
| 1473 | 1473 | |
| 1474 | 1474 | add_compile_fail_case("redefinition of global variables", R"SOURCE( |