introduce the error keyword and type

See #23
This commit is contained in:
Andrew Kelley 2016-01-24 01:34:48 -07:00
parent 37aae53009
commit 5c18826240
12 changed files with 223 additions and 128 deletions

View File

@ -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

View File

@ -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

View File

@ -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 => {

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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);

View File

@ -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;
}
}

View File

@ -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 ",";

View File

@ -38,6 +38,7 @@ enum TokenId {
TokenIdKeywordNoAlias,
TokenIdKeywordSwitch,
TokenIdKeywordUndefined,
TokenIdKeywordError,
TokenIdLParen,
TokenIdRParen,
TokenIdComma,

View File

@ -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,
}
}
*/

View File

@ -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(