Commit 5c18826240
Changed files (12)
doc
vim
syntax
std
test
doc/vim/syntax/zig.vim
@@ -15,7 +15,7 @@ syn keyword zigRepeat while for
syn keyword zigConstant null undefined
syn keyword zigKeyword fn import
-syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void unreachable type
+syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128 void unreachable type error
syn keyword zigBoolean true false
doc/langref.md
@@ -7,7 +7,7 @@ Root : many(TopLevelDecl) "EOF"
TopLevelDecl : FnDef | ExternBlock | RootExportDecl | Import | ContainerDecl | VariableDeclaration | ErrorValueDecl
-ErrorValueDecl : option(FnVisibleMod) "%." "Symbol"
+ErrorValueDecl : option(FnVisibleMod) "error" "Symbol"
VariableDeclaration : option(FnVisibleMod) ("var" | "const") "Symbol" ("=" Expression | ":" PrefixOpExpression option("=" Expression))
@@ -133,9 +133,9 @@ ContainerInitBody : list(StructLiteralField, ",") | list(Expression, ",")
StructLiteralField : "." "Symbol" "=" Expression
-PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?"
+PrefixOp : "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%"
-PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("%." "Symbol")
+PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("error" "." "Symbol")
ArrayType : "[" option(Expression) "]" option("const") PrefixOpExpression
@@ -143,7 +143,7 @@ GotoExpression: "goto" "Symbol"
GroupedExpression : "(" Expression ")"
-KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined"
+KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined" | "error"
```
## Operator Precedence
example/cat/main.zig
@@ -10,6 +10,7 @@ import "std.zig";
// * %% binary operator
// * %% prefix operator
// * cast err type to string
+// * string equality
pub fn main(args: [][]u8) %void => {
const exe = args[0];
@@ -39,7 +40,7 @@ pub fn main(args: [][]u8) %void => {
fn usage(exe: []u8) %void => {
%%stderr.print("Usage: {} [FILE]...\n", exe);
- return %.Invalid;
+ return error.Invalid;
}
fn cat_stream(is: InputStream) %void => {
example/guess_number/main.zig
@@ -3,8 +3,8 @@ export executable "guess_number";
import "std.zig";
import "rand.zig";
-%.GetRandomFail;
-%.ReadInputFail;
+error GetRandomFail;
+error ReadInputFail;
pub fn main(args: [][]u8) %void => {
print_str("Welcome to the Guess Number Game in Zig.\n");
@@ -15,7 +15,7 @@ pub fn main(args: [][]u8) %void => {
if (err != @sizeof(u32)) {
// TODO full error message
fprint_str(stderr_fileno, "unable to get random bytes\n");
- return %.GetRandomFail;
+ return error.GetRandomFail;
}
var rand : Rand;
@@ -31,7 +31,7 @@ pub fn main(args: [][]u8) %void => {
if (readline(line_buf, &line_len) || line_len == line_buf.len) {
// TODO full error message
fprint_str(stderr_fileno, "unable to read input\n");
- return %.ReadInputFail;
+ return error.ReadInputFail;
}
var guess : u64;
src/all_types.hpp
@@ -133,7 +133,6 @@ enum NodeType {
NodeTypeNumberLiteral,
NodeTypeStringLiteral,
NodeTypeCharLiteral,
- NodeTypeErrorLiteral,
NodeTypeSymbol,
NodeTypePrefixOpExpr,
NodeTypeFnCallExpr,
@@ -161,6 +160,7 @@ enum NodeType {
NodeTypeContainerInitExpr,
NodeTypeStructValueField,
NodeTypeArrayType,
+ NodeTypeErrorType,
};
struct AstNodeRoot {
@@ -315,6 +315,7 @@ enum CastOp {
CastOpToUnknownSizeArray,
CastOpMaybeWrap,
CastOpErrorWrap,
+ CastOpPureErrorWrap,
CastOpPointerReinterpret,
CastOpErrToInt,
};
@@ -584,13 +585,6 @@ struct AstNodeNumberLiteral {
Expr resolved_expr;
};
-struct AstNodeErrorLiteral {
- Buf symbol;
-
- // populated by semantic analyzer
- Expr resolved_expr;
-};
-
struct AstNodeStructValueField {
Buf name;
AstNode *expr;
@@ -663,6 +657,11 @@ struct AstNodeArrayType {
Expr resolved_expr;
};
+struct AstNodeErrorType {
+ // populated by semantic analyzer
+ Expr resolved_expr;
+};
+
struct AstNode {
enum NodeType type;
int line;
@@ -705,7 +704,6 @@ struct AstNode {
AstNodeStringLiteral string_literal;
AstNodeCharLiteral char_literal;
AstNodeNumberLiteral number_literal;
- AstNodeErrorLiteral error_literal;
AstNodeContainerInitExpr container_init_expr;
AstNodeStructValueField struct_val_field;
AstNodeNullLiteral null_literal;
@@ -715,6 +713,7 @@ struct AstNode {
AstNodeBreakExpr break_expr;
AstNodeContinueExpr continue_expr;
AstNodeArrayType array_type;
+ AstNodeErrorType error_type;
} data;
};
@@ -820,7 +819,8 @@ enum TypeTableEntryId {
TypeTableEntryIdNumLitInt,
TypeTableEntryIdUndefLit,
TypeTableEntryIdMaybe,
- TypeTableEntryIdError,
+ TypeTableEntryIdErrorUnion,
+ TypeTableEntryIdPureError,
TypeTableEntryIdEnum,
TypeTableEntryIdFn,
};
@@ -961,6 +961,7 @@ struct CodeGen {
TypeTableEntry *entry_num_lit_int;
TypeTableEntry *entry_num_lit_float;
TypeTableEntry *entry_undef;
+ TypeTableEntry *entry_pure_error;
} builtin_types;
LLVMTargetDataRef target_data_ref;
src/analyze.cpp
@@ -19,6 +19,8 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
static TypeTableEntry *unwrapped_node_type(AstNode *node);
static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node);
+static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
+ BlockContext *context, AstNode *node, Buf *err_name);
static AstNode *first_executing_node(AstNode *node) {
switch (node->type) {
@@ -47,7 +49,6 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeVariableDeclaration:
case NodeTypeErrorValueDecl:
case NodeTypeNumberLiteral:
- case NodeTypeErrorLiteral:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
case NodeTypeSymbol:
@@ -71,6 +72,7 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeSwitchExpr:
case NodeTypeSwitchProng:
case NodeTypeArrayType:
+ case NodeTypeErrorType:
case NodeTypeContainerInitExpr:
return node;
}
@@ -110,7 +112,8 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdFn:
- case TypeTableEntryIdError:
+ case TypeTableEntryIdErrorUnion:
+ case TypeTableEntryIdPureError:
case TypeTableEntryIdUndefLit:
// nothing to init
break;
@@ -200,7 +203,7 @@ static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
"val", di_file, line, child_type->size_in_bits, child_type->align_in_bits, 0, 0,
child_type->di_type),
LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
- "maybe", di_file, line, 8, 8, 8, 0,
+ "maybe", di_file, line, 8, 8, child_type->size_in_bits, 0,
child_type->di_type),
};
LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
@@ -223,7 +226,7 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
if (child_type->error_parent) {
return child_type->error_parent;
} else {
- TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdError);
+ TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdErrorUnion);
assert(child_type->type_ref);
assert(child_type->di_type);
@@ -239,7 +242,38 @@ static TypeTableEntry *get_error_type(CodeGen *g, TypeTableEntry *child_type) {
entry->di_type = g->err_tag_type->di_type;
} else {
- zig_panic("TODO get_error_type non-void");
+ LLVMTypeRef elem_types[] = {
+ g->err_tag_type->type_ref,
+ child_type->type_ref,
+ };
+ entry->type_ref = LLVMStructType(elem_types, 2, false);
+ entry->size_in_bits = g->err_tag_type->size_in_bits + child_type->size_in_bits;
+ entry->align_in_bits = g->err_tag_type->align_in_bits;
+
+ LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
+ LLVMZigDIFile *di_file = nullptr;
+ unsigned line = 0;
+ entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder,
+ LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name),
+ compile_unit_scope, di_file, line);
+
+ LLVMZigDIType *di_element_types[] = {
+ LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
+ "tag", di_file, line, g->err_tag_type->size_in_bits, g->err_tag_type->align_in_bits,
+ 0, 0, child_type->di_type),
+ LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
+ "value", di_file, line, child_type->size_in_bits, child_type->align_in_bits,
+ g->err_tag_type->size_in_bits, 0, child_type->di_type),
+ };
+
+ LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
+ compile_unit_scope,
+ buf_ptr(&entry->name),
+ di_file, line, entry->size_in_bits, entry->align_in_bits, 0,
+ nullptr, di_element_types, 2, 0, nullptr, "");
+
+ LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
+ entry->di_type = replacement_di_type;
}
child_type->error_parent = entry;
@@ -1012,7 +1046,6 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeArrayAccessExpr:
case NodeTypeSliceExpr:
case NodeTypeNumberLiteral:
- case NodeTypeErrorLiteral:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
case NodeTypeBoolLiteral:
@@ -1037,6 +1070,7 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeStructValueField:
case NodeTypeContainerInitExpr:
case NodeTypeArrayType:
+ case NodeTypeErrorType:
zig_unreachable();
}
}
@@ -1083,7 +1117,8 @@ static bool type_has_codegen_value(TypeTableEntryId id) {
case TypeTableEntryIdArray:
case TypeTableEntryIdStruct:
case TypeTableEntryIdMaybe:
- case TypeTableEntryIdError:
+ case TypeTableEntryIdErrorUnion:
+ case TypeTableEntryIdPureError:
case TypeTableEntryIdEnum:
case TypeTableEntryIdFn:
return true;
@@ -1166,8 +1201,8 @@ static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTable
}
// error
- if (expected_type->id == TypeTableEntryIdError &&
- actual_type->id == TypeTableEntryIdError)
+ if (expected_type->id == TypeTableEntryIdErrorUnion &&
+ actual_type->id == TypeTableEntryIdErrorUnion)
{
return types_match_const_cast_only(
expected_type->data.error.child_type,
@@ -1224,11 +1259,11 @@ static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *pa
prev_type = cur_type;
prev_node = cur_node;
}
- } else if (prev_type->id == TypeTableEntryIdError &&
+ } else if (prev_type->id == TypeTableEntryIdErrorUnion &&
types_match_const_cast_only(prev_type->data.error.child_type, cur_type))
{
continue;
- } else if (cur_type->id == TypeTableEntryIdError &&
+ } else if (cur_type->id == TypeTableEntryIdErrorUnion &&
types_match_const_cast_only(cur_type->data.error.child_type, prev_type))
{
prev_type = cur_type;
@@ -1287,13 +1322,20 @@ static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_
}
// implicit conversion from error child type to error type
- if (expected_type->id == TypeTableEntryIdError &&
+ if (expected_type->id == TypeTableEntryIdErrorUnion &&
types_match_with_implicit_cast(g, expected_type->data.error.child_type, actual_type,
literal_node, reported_err))
{
return true;
}
+ // implicit conversion from pure error to error union type
+ if (expected_type->id == TypeTableEntryIdErrorUnion &&
+ actual_type->id == TypeTableEntryIdPureError)
+ {
+ return true;
+ }
+
// implicit widening conversion
if (expected_type->id == TypeTableEntryIdInt &&
actual_type->id == TypeTableEntryIdInt &&
@@ -1695,12 +1737,11 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
AstNode *struct_expr_node = node->data.field_access_expr.struct_expr;
TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, struct_expr_node);
+ Buf *field_name = &node->data.field_access_expr.field_name;
if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer &&
struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct))
{
- Buf *field_name = &node->data.field_access_expr.field_name;
-
TypeTableEntry *bare_struct_type = (struct_type->id == TypeTableEntryIdStruct) ?
struct_type : struct_type->data.pointer.child_type;
@@ -1713,15 +1754,14 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
return g->builtin_types.entry_invalid;
}
} else if (struct_type->id == TypeTableEntryIdArray) {
- Buf *name = &node->data.field_access_expr.field_name;
- if (buf_eql_str(name, "len")) {
+ if (buf_eql_str(field_name, "len")) {
return g->builtin_types.entry_isize;
- } else if (buf_eql_str(name, "ptr")) {
+ } else if (buf_eql_str(field_name, "ptr")) {
// TODO determine whether the pointer should be const
return get_pointer_to_type(g, struct_type->data.array.child_type, false);
} else {
add_node_error(g, node,
- buf_sprintf("no member named '%s' in '%s'", buf_ptr(name),
+ buf_sprintf("no member named '%s' in '%s'", buf_ptr(field_name),
buf_ptr(&struct_type->name)));
return g->builtin_types.entry_invalid;
}
@@ -1731,8 +1771,9 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
if (enum_type->id == TypeTableEntryIdInvalid) {
return g->builtin_types.entry_invalid;
} else if (enum_type->id == TypeTableEntryIdEnum) {
- Buf *field_name = &node->data.field_access_expr.field_name;
return analyze_enum_value_expr(g, import, context, node, nullptr, enum_type, field_name);
+ } else if (enum_type->id == TypeTableEntryIdPureError) {
+ return analyze_error_literal_expr(g, import, context, node, field_name);
} else {
add_node_error(g, node,
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,
Expr *expr = get_resolved_expr(node);
expr->const_val.ok = true;
expr->const_val.data.x_err.err = err;
- return get_error_type(g, g->builtin_types.entry_void);
+ return g->builtin_types.entry_pure_error;
}
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 *
return resolved_type;
}
+static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
+ BlockContext *context, AstNode *node, Buf *err_name)
+{
+ auto err_table_entry = import->block_context->error_table.maybe_get(err_name);
+
+ if (err_table_entry) {
+ return resolve_expr_const_val_as_err(g, node, err_table_entry->value);
+ }
+
+ add_node_error(g, node,
+ buf_sprintf("use of undeclared error value '%s'", buf_ptr(err_name)));
+
+ return get_error_type(g, g->builtin_types.entry_void);
+}
+
static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
@@ -2564,23 +2620,6 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry
}
}
-static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
- BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node)
-{
- Buf *err_name = &node->data.error_literal.symbol;
-
- auto err_table_entry = import->block_context->error_table.maybe_get(err_name);
-
- if (err_table_entry) {
- return resolve_expr_const_val_as_err(g, node, err_table_entry->value);
- }
-
- add_node_error(g, node,
- buf_sprintf("use of undeclared error value '%s'", buf_ptr(err_name)));
-
- return get_error_type(g, g->builtin_types.entry_void);
-}
-
static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
@@ -2906,6 +2945,10 @@ static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *ex
const_val->data.x_err.payload = other_val;
const_val->ok = true;
break;
+ case CastOpPureErrorWrap:
+ const_val->data.x_err.err = other_val->data.x_err.err;
+ const_val->ok = true;
+ break;
case CastOpErrToInt:
{
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
}
// explicit cast from child type of error type to error type
- if (wanted_type->id == TypeTableEntryIdError) {
+ if (wanted_type->id == TypeTableEntryIdErrorUnion) {
if (types_match_const_cast_only(wanted_type->data.error.child_type, actual_type)) {
node->data.fn_call_expr.cast_op = CastOpErrorWrap;
eval_const_expr_implicit_cast(g, node, expr_node);
@@ -3025,6 +3068,15 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
}
}
+ // explicit cast from pure error to error union type
+ if (wanted_type->id == TypeTableEntryIdErrorUnion &&
+ actual_type->id == TypeTableEntryIdPureError)
+ {
+ node->data.fn_call_expr.cast_op = CastOpPureErrorWrap;
+ eval_const_expr_implicit_cast(g, node, expr_node);
+ return wanted_type;
+ }
+
// explicit cast from number literal to another type
if (actual_type->id == TypeTableEntryIdNumLitFloat ||
actual_type->id == TypeTableEntryIdNumLitInt)
@@ -3039,8 +3091,10 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
}
// explicit cast from %void to integer type which can fit it
- if (actual_type->id == TypeTableEntryIdError &&
- actual_type->data.error.child_type->size_in_bits == 0 &&
+ bool actual_type_is_void_err = actual_type->id == TypeTableEntryIdErrorUnion &&
+ actual_type->data.error.child_type->size_in_bits == 0;
+ bool actual_type_is_pure_err = actual_type->id == TypeTableEntryIdPureError;
+ if ((actual_type_is_void_err || actual_type_is_pure_err) &&
wanted_type->id == TypeTableEntryIdInt)
{
BigNum bn;
@@ -3754,9 +3808,6 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeNumberLiteral:
return_type = analyze_number_literal_expr(g, import, context, expected_type, node);
break;
- case NodeTypeErrorLiteral:
- return_type = analyze_error_literal_expr(g, import, context, expected_type, node);
- break;
case NodeTypeStringLiteral:
return_type = analyze_string_literal_expr(g, import, context, expected_type, node);
break;
@@ -3794,6 +3845,9 @@ static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeArrayType:
return_type = analyze_array_type(g, import, context, expected_type, node);
break;
+ case NodeTypeErrorType:
+ return_type = resolve_expr_const_val_as_type(g, node, g->builtin_types.entry_pure_error);
+ break;
case NodeTypeSwitchExpr:
return_type = analyze_switch_expr(g, import, context, expected_type, node);
break;
@@ -3933,7 +3987,6 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeArrayAccessExpr:
case NodeTypeSliceExpr:
case NodeTypeNumberLiteral:
- case NodeTypeErrorLiteral:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
case NodeTypeBoolLiteral:
@@ -3958,6 +4011,7 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeStructValueField:
case NodeTypeContainerInitExpr:
case NodeTypeArrayType:
+ case NodeTypeErrorType:
zig_unreachable();
}
}
@@ -3967,7 +4021,6 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
{
switch (node->type) {
case NodeTypeNumberLiteral:
- case NodeTypeErrorLiteral:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
case NodeTypeBoolLiteral:
@@ -3977,6 +4030,7 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeBreak:
case NodeTypeContinue:
case NodeTypeErrorValueDecl:
+ case NodeTypeErrorType:
// no dependencies on other top level declarations
break;
case NodeTypeSymbol:
@@ -4286,7 +4340,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
case NodeTypeArrayAccessExpr:
case NodeTypeSliceExpr:
case NodeTypeNumberLiteral:
- case NodeTypeErrorLiteral:
case NodeTypeStringLiteral:
case NodeTypeCharLiteral:
case NodeTypeBoolLiteral:
@@ -4311,6 +4364,7 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
case NodeTypeContainerInitExpr:
case NodeTypeStructValueField:
case NodeTypeArrayType:
+ case NodeTypeErrorType:
zig_unreachable();
}
}
@@ -4419,7 +4473,14 @@ void semantic_analyze(CodeGen *g) {
}
}
- g->err_tag_type = get_smallest_unsigned_int_type(g, g->error_value_count);
+ {
+ g->err_tag_type = get_smallest_unsigned_int_type(g, g->error_value_count);
+
+ g->builtin_types.entry_pure_error->type_ref = g->err_tag_type->type_ref;
+ g->builtin_types.entry_pure_error->size_in_bits = g->err_tag_type->size_in_bits;
+ g->builtin_types.entry_pure_error->align_in_bits = g->err_tag_type->align_in_bits;
+ g->builtin_types.entry_pure_error->di_type = g->err_tag_type->di_type;
+ }
{
auto it = g->import_table.entry_iterator();
@@ -4493,8 +4554,6 @@ Expr *get_resolved_expr(AstNode *node) {
return &node->data.container_init_expr.resolved_expr;
case NodeTypeNumberLiteral:
return &node->data.number_literal.resolved_expr;
- case NodeTypeErrorLiteral:
- return &node->data.error_literal.resolved_expr;
case NodeTypeStringLiteral:
return &node->data.string_literal.resolved_expr;
case NodeTypeBlock:
@@ -4521,6 +4580,8 @@ Expr *get_resolved_expr(AstNode *node) {
return &node->data.label.resolved_expr;
case NodeTypeArrayType:
return &node->data.array_type.resolved_expr;
+ case NodeTypeErrorType:
+ return &node->data.error_type.resolved_expr;
case NodeTypeSwitchExpr:
return &node->data.switch_expr.resolved_expr;
case NodeTypeSwitchProng:
@@ -4554,7 +4615,6 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
case NodeTypeErrorValueDecl:
return &node->data.error_value_decl.top_level_decl;
case NodeTypeNumberLiteral:
- case NodeTypeErrorLiteral:
case NodeTypeReturnExpr:
case NodeTypeBinOpExpr:
case NodeTypePrefixOpExpr:
@@ -4593,6 +4653,7 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
case NodeTypeStructField:
case NodeTypeStructValueField:
case NodeTypeArrayType:
+ case NodeTypeErrorType:
zig_unreachable();
}
zig_unreachable();
src/codegen.cpp
@@ -306,7 +306,7 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
case CastOpNoop:
return expr_val;
case CastOpErrToInt:
- assert(actual_type->id == TypeTableEntryIdError);
+ assert(actual_type->id == TypeTableEntryIdErrorUnion);
if (actual_type->data.error.child_type->size_in_bits == 0) {
return gen_widen_or_shorten(g, node, g->err_tag_type, wanted_type, expr_val);
} else {
@@ -330,12 +330,19 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
return cast_expr->tmp_ptr;
}
case CastOpErrorWrap:
- assert(wanted_type->id == TypeTableEntryIdError);
+ assert(wanted_type->id == TypeTableEntryIdErrorUnion);
if (wanted_type->data.error.child_type->size_in_bits == 0) {
return LLVMConstNull(g->err_tag_type->type_ref);
} else {
zig_panic("TODO");
}
+ case CastOpPureErrorWrap:
+ assert(wanted_type->id == TypeTableEntryIdErrorUnion);
+ if (wanted_type->data.error.child_type->size_in_bits == 0) {
+ return expr_val;
+ } else {
+ zig_panic("TODO");
+ }
case CastOpPtrToInt:
add_debug_source_node(g, node);
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
return nullptr;
}
- assert(!use_expr_value || then_type->id == TypeTableEntryIdError);
+ assert(!use_expr_value || then_type->id == TypeTableEntryIdErrorUnion);
LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
LLVMBasicBlockRef endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
@@ -2011,7 +2018,6 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
return gen_container_init_expr(g, node);
case NodeTypeSwitchExpr:
return gen_switch_expr(g, node);
- case NodeTypeErrorLiteral:
case NodeTypeNumberLiteral:
case NodeTypeBoolLiteral:
case NodeTypeStringLiteral:
@@ -2033,6 +2039,7 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
case NodeTypeStructField:
case NodeTypeStructValueField:
case NodeTypeArrayType:
+ case NodeTypeErrorType:
case NodeTypeSwitchProng:
case NodeTypeSwitchRange:
case NodeTypeErrorValueDecl:
@@ -2063,6 +2070,9 @@ static LLVMValueRef gen_const_val(CodeGen *g, TypeTableEntry *type_entry, ConstE
if (type_entry->id == TypeTableEntryIdInt) {
return LLVMConstInt(type_entry->type_ref, bignum_to_twos_complement(&const_val->data.x_bignum), false);
+ } else if (type_entry->id == TypeTableEntryIdPureError) {
+ assert(const_val->data.x_err.err);
+ return LLVMConstInt(g->builtin_types.entry_pure_error->type_ref, const_val->data.x_err.err->value, false);
} else if (type_entry->id == TypeTableEntryIdFloat) {
if (const_val->data.x_bignum.kind == BigNumKindFloat) {
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
} else {
return global_value;
}
- } else if (type_entry->id == TypeTableEntryIdError) {
- if (type_entry->data.error.child_type->size_in_bits == 0) {
+ } else if (type_entry->id == TypeTableEntryIdErrorUnion) {
+ TypeTableEntry *child_type = type_entry->data.error.child_type;
+ if (child_type->size_in_bits == 0) {
uint64_t value = const_val->data.x_err.err ? const_val->data.x_err.err->value : 0;
return LLVMConstInt(g->err_tag_type->type_ref, value, false);
} else {
- zig_panic("TODO");
+ LLVMValueRef err_tag_value;
+ LLVMValueRef err_payload_value;
+ if (const_val->data.x_err.err) {
+ err_tag_value = LLVMConstInt(g->err_tag_type->type_ref, const_val->data.x_err.err->value, false);
+ err_payload_value = LLVMConstNull(child_type->type_ref);
+ } else {
+ err_tag_value = LLVMConstNull(g->err_tag_type->type_ref);
+ err_payload_value = gen_const_val(g, child_type, const_val->data.x_err.payload);
+ }
+ LLVMValueRef fields[] = {
+ err_tag_value,
+ err_payload_value,
+ };
+ return LLVMConstStruct(fields, 2, false);
}
} else {
zig_unreachable();
@@ -2557,6 +2581,14 @@ static void define_builtin_types(CodeGen *g) {
g->builtin_types.entry_type = entry;
g->primitive_type_table.put(&entry->name, entry);
}
+ {
+ // partially complete the error type. we complete it later after we know
+ // error_value_count.
+ TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdPureError);
+ buf_init_from_str(&entry->name, "error");
+ g->builtin_types.entry_pure_error = entry;
+ g->primitive_type_table.put(&entry->name, entry);
+ }
g->builtin_types.entry_u8 = get_int_type(g, false, 8);
g->builtin_types.entry_u16 = get_int_type(g, false, 16);
src/parser.cpp
@@ -113,8 +113,6 @@ const char *node_type_str(NodeType node_type) {
return "ErrorValueDecl";
case NodeTypeNumberLiteral:
return "NumberLiteral";
- case NodeTypeErrorLiteral:
- return "ErrorLiteral";
case NodeTypeStringLiteral:
return "StringLiteral";
case NodeTypeCharLiteral:
@@ -167,6 +165,8 @@ const char *node_type_str(NodeType node_type) {
return "ContainerInitExpr";
case NodeTypeArrayType:
return "ArrayType";
+ case NodeTypeErrorType:
+ return "ErrorType";
}
zig_unreachable();
}
@@ -313,11 +313,6 @@ void ast_print(AstNode *node, int indent) {
}
break;
}
- case NodeTypeErrorLiteral:
- {
- fprintf(stderr, "%s '%s'", node_type_str(node->type), buf_ptr(&node->data.error_literal.symbol));
- break;
- }
case NodeTypeStringLiteral:
{
const char *c = node->data.string_literal.c ? "c" : "";
@@ -465,6 +460,9 @@ void ast_print(AstNode *node, int indent) {
ast_print(node->data.array_type.child_type, indent + 2);
break;
}
+ case NodeTypeErrorType:
+ fprintf(stderr, "%s\n", node_type_str(node->type));
+ break;
}
}
@@ -1372,8 +1370,8 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
}
/*
-PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("%." "Symbol")
-KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined"
+PrimaryExpression : "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | AsmExpression | ("error" "." "Symbol")
+KeywordLiteral : "true" | "false" | "null" | "break" | "continue" | "undefined" | "error"
*/
static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
@@ -1419,6 +1417,10 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
AstNode *node = ast_create_node(pc, NodeTypeUndefinedLiteral, token);
*token_index += 1;
return node;
+ } else if (token->id == TokenIdKeywordError) {
+ AstNode *node = ast_create_node(pc, NodeTypeErrorType, token);
+ *token_index += 1;
+ return node;
} else if (token->id == TokenIdAtSign) {
*token_index += 1;
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
ast_buf_from_token(pc, dest_symbol, &node->data.goto_expr.name);
return node;
- } else if (token->id == TokenIdPercentDot) {
- *token_index += 1;
- Token *symbol_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
- AstNode *node = ast_create_node(pc, NodeTypeErrorLiteral, token);
- ast_buf_from_token(pc, symbol_tok, &node->data.error_literal.symbol);
- return node;
}
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) {
}
/*
-ErrorValueDecl : option(FnVisibleMod) "%." "Symbol"
+ErrorValueDecl : option(FnVisibleMod) "error" "Symbol"
*/
static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index, bool mandatory) {
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
if (first_token->id == TokenIdKeywordPub) {
Token *next_token = &pc->tokens->at(*token_index + 1);
- if (next_token->id == TokenIdPercentDot) {
+ if (next_token->id == TokenIdKeywordError) {
visib_mod = VisibModPub;
*token_index += 2;
} else if (mandatory) {
@@ -2988,7 +2984,7 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index, b
}
} else if (first_token->id == TokenIdKeywordExport) {
Token *next_token = &pc->tokens->at(*token_index + 1);
- if (next_token->id == TokenIdPercentDot) {
+ if (next_token->id == TokenIdKeywordError) {
visib_mod = VisibModExport;
*token_index += 2;
} else if (mandatory) {
@@ -2996,7 +2992,7 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index, b
} else {
return nullptr;
}
- } else if (first_token->id == TokenIdPercentDot) {
+ } else if (first_token->id == TokenIdKeywordError) {
visib_mod = VisibModPrivate;
*token_index += 1;
} else if (mandatory) {
@@ -3177,9 +3173,6 @@ void normalize_parent_ptrs(AstNode *node) {
case NodeTypeCharLiteral:
// none
break;
- case NodeTypeErrorLiteral:
- // none
- break;
case NodeTypeSymbol:
// none
break;
@@ -3290,5 +3283,8 @@ void normalize_parent_ptrs(AstNode *node) {
set_field(&node->data.array_type.size);
set_field(&node->data.array_type.child_type);
break;
+ case NodeTypeErrorType:
+ // none
+ break;
}
}
src/tokenizer.cpp
@@ -247,6 +247,8 @@ static void end_token(Tokenize *t) {
t->cur_tok->id = TokenIdKeywordSwitch;
} else if (mem_eql_str(token_mem, token_len, "undefined")) {
t->cur_tok->id = TokenIdKeywordUndefined;
+ } else if (mem_eql_str(token_mem, token_len, "error")) {
+ t->cur_tok->id = TokenIdKeywordError;
}
t->cur_tok = nullptr;
@@ -1046,6 +1048,7 @@ const char * token_name(TokenId id) {
case TokenIdKeywordNoAlias: return "noalias";
case TokenIdKeywordSwitch: return "switch";
case TokenIdKeywordUndefined: return "undefined";
+ case TokenIdKeywordError: return "error";
case TokenIdLParen: return "(";
case TokenIdRParen: return ")";
case TokenIdComma: return ",";
src/tokenizer.hpp
@@ -38,6 +38,7 @@ enum TokenId {
TokenIdKeywordNoAlias,
TokenIdKeywordSwitch,
TokenIdKeywordUndefined,
+ TokenIdKeywordError,
TokenIdLParen,
TokenIdRParen,
TokenIdComma,
std/std.zig
@@ -25,15 +25,15 @@ pub var stderr = OutStream {
};
*/
-pub %.Unexpected;
-pub %.DiskQuota;
-pub %.FileTooBig;
-pub %.SigInterrupt;
-pub %.Io;
-pub %.NoSpaceLeft;
-pub %.BadPerm;
-pub %.PipeFail;
-pub %.Invalid;
+pub error Unexpected;
+pub error DiskQuota;
+pub error FileTooBig;
+pub error SigInterrupt;
+pub error Io;
+pub error NoSpaceLeft;
+pub error BadPerm;
+pub error PipeFail;
+pub error Invalid;
const buffer_size = 4 * 1024;
const max_u64_base10_digits = 20;
@@ -100,14 +100,14 @@ pub struct OutStream {
os.index = 0;
switch (write(os.fd, os.buffer.ptr, amt_to_write)) {
EINVAL => unreachable{},
- EDQUOT => %.DiskQuota,
- EFBIG => %.FileTooBig,
- EINTR => %.SigInterrupt,
- EIO => %.Io,
- ENOSPC => %.NoSpaceLeft,
- EPERM => %.BadPerm,
- EPIPE => %.PipeFail,
- else => %.Unexpected,
+ EDQUOT => error.DiskQuota,
+ EFBIG => error.FileTooBig,
+ EINTR => error.SigInterrupt,
+ EIO => error.Io,
+ ENOSPC => error.NoSpaceLeft,
+ EPERM => error.BadPerm,
+ EPIPE => error.PipeFail,
+ else => error.Unexpected,
}
}
}
@@ -121,10 +121,10 @@ pub struct InStream {
switch (-amt_read) {
EINVAL => unreachable{},
EFAULT => unreachable{},
- EBADF => %.BadFd,
- EINTR => %.SigInterrupt,
- EIO => %.Io,
- else => %.Unexpected,
+ EBADF => error.BadFd,
+ EINTR => error.SigInterrupt,
+ EIO => error.Io,
+ else => error.Unexpected,
}
}
return amt_read;
@@ -136,8 +136,8 @@ pub fn os_get_random_bytes(buf: []u8) %void => {
switch (getrandom(buf.ptr, buf.len, 0)) {
EINVAL => unreachable{},
EFAULT => unreachable{},
- EINTR => %.SigInterrupt,
- else => %.Unexpected,
+ EINTR => error.SigInterrupt,
+ else => error.Unexpected,
}
}
*/
test/run_tests.cpp
@@ -1213,11 +1213,11 @@ pub fn main(args: [][]u8) %void => {
add_simple_case("error values", R"SOURCE(
import "std.zig";
-%.err1;
-%.err2;
+error err1;
+error err2;
pub fn main(args: [][]u8) %void => {
- const a = i32(%.err1);
- const b = i32(%.err2);
+ const a = i32(error.err1);
+ const b = i32(error.err2);
if (a == b) {
print_str("BAD\n");
}
@@ -1467,8 +1467,8 @@ enum A {}
)SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of 'A'");
add_compile_fail_case("redefinition of error values", R"SOURCE(
-%.A;
-%.A;
+error A;
+error A;
)SOURCE", 1, ".tmp_source.zig:3:1: error: redefinition of error 'A'");
add_compile_fail_case("redefinition of global variables", R"SOURCE(