add #typeof() compiler function

This commit is contained in:
Andrew Kelley 2016-01-03 18:17:50 -07:00
parent b453345554
commit fa6e3eec46
8 changed files with 148 additions and 29 deletions

View File

@ -60,7 +60,9 @@ ParamDeclList : token(LParen) list(ParamDecl, token(Comma)) token(RParen)
ParamDecl : token(Symbol) token(Colon) Type | token(Ellipsis) ParamDecl : token(Symbol) token(Colon) Type | token(Ellipsis)
Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompileTimeFnCall
CompileTimeFnCall : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen)
PointerType : token(Ampersand) option(token(Const)) Type PointerType : token(Ampersand) option(token(Const)) Type

View File

@ -2,7 +2,7 @@
const ARRAY_SIZE : u16 = 624; const ARRAY_SIZE : u16 = 624;
/// Use `rand_init` to initialize this state. /// Use `rand_init` to initialize this state.
pub struct Rand { struct Rand {
array: [u32; ARRAY_SIZE], array: [u32; ARRAY_SIZE],
index: #typeof(ARRAY_SIZE), index: #typeof(ARRAY_SIZE),

View File

@ -59,6 +59,7 @@ static AstNode *first_executing_node(AstNode *node) {
case NodeTypeStructValueExpr: case NodeTypeStructValueExpr:
case NodeTypeStructValueField: case NodeTypeStructValueField:
case NodeTypeWhileExpr: case NodeTypeWhileExpr:
case NodeTypeCompilerFnCall:
return node; return node;
} }
zig_panic("unreachable"); zig_panic("unreachable");
@ -208,7 +209,7 @@ static TypeTableEntry *get_array_type(CodeGen *g, TypeTableEntry *child_type, ui
} }
} }
static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) { static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node, ImportTableEntry *import, BlockContext *context) {
assert(node->type == NodeTypeType); assert(node->type == NodeTypeType);
alloc_codegen_node(node); alloc_codegen_node(node);
TypeNode *type_node = &node->codegen_node->data.type_node; TypeNode *type_node = &node->codegen_node->data.type_node;
@ -228,7 +229,7 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
} }
case AstNodeTypeTypePointer: case AstNodeTypeTypePointer:
{ {
resolve_type(g, node->data.type.child_type); resolve_type(g, node->data.type.child_type, import, context);
TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;
assert(child_type); assert(child_type);
if (child_type->id == TypeTableEntryIdUnreachable) { if (child_type->id == TypeTableEntryIdUnreachable) {
@ -242,7 +243,7 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
} }
case AstNodeTypeTypeArray: case AstNodeTypeTypeArray:
{ {
resolve_type(g, node->data.type.child_type); resolve_type(g, node->data.type.child_type, import, context);
TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;
if (child_type->id == TypeTableEntryIdUnreachable) { if (child_type->id == TypeTableEntryIdUnreachable) {
add_node_error(g, node, add_node_error(g, node,
@ -263,7 +264,7 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
} }
case AstNodeTypeTypeMaybe: case AstNodeTypeTypeMaybe:
{ {
resolve_type(g, node->data.type.child_type); resolve_type(g, node->data.type.child_type, import, context);
TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry; TypeTableEntry *child_type = node->data.type.child_type->codegen_node->data.type_node.entry;
assert(child_type); assert(child_type);
if (child_type->id == TypeTableEntryIdUnreachable) { if (child_type->id == TypeTableEntryIdUnreachable) {
@ -275,11 +276,26 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
type_node->entry = get_maybe_type(g, child_type); type_node->entry = get_maybe_type(g, child_type);
return type_node->entry; return type_node->entry;
} }
case AstNodeTypeTypeCompilerExpr:
{
AstNode *compiler_expr_node = node->data.type.compiler_expr;
Buf *fn_name = &compiler_expr_node->data.compiler_fn_call.name;
if (buf_eql_str(fn_name, "typeof")) {
return analyze_expression(g, import, context, nullptr,
compiler_expr_node->data.compiler_fn_call.expr);
} else {
add_node_error(g, node,
buf_sprintf("invalid compiler function: '%s'", buf_ptr(fn_name)));
return g->builtin_types.entry_invalid;
}
}
} }
zig_unreachable(); zig_unreachable();
} }
static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) { static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,
ImportTableEntry *import)
{
assert(node->type == NodeTypeFnProto); assert(node->type == NodeTypeFnProto);
for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) { for (int i = 0; i < node->data.fn_proto.directives->length; i += 1) {
@ -310,7 +326,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
for (int i = 0; i < node->data.fn_proto.params.length; i += 1) { for (int i = 0; i < node->data.fn_proto.params.length; i += 1) {
AstNode *child = node->data.fn_proto.params.at(i); AstNode *child = node->data.fn_proto.params.at(i);
assert(child->type == NodeTypeParamDecl); assert(child->type == NodeTypeParamDecl);
TypeTableEntry *type_entry = resolve_type(g, child->data.param_decl.type); TypeTableEntry *type_entry = resolve_type(g, child->data.param_decl.type, import, import->block_context);
if (type_entry->id == TypeTableEntryIdUnreachable) { if (type_entry->id == TypeTableEntryIdUnreachable) {
add_node_error(g, child->data.param_decl.type, add_node_error(g, child->data.param_decl.type,
buf_sprintf("parameter of type 'unreachable' not allowed")); buf_sprintf("parameter of type 'unreachable' not allowed"));
@ -322,7 +338,7 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
} }
} }
resolve_type(g, node->data.fn_proto.return_type); resolve_type(g, node->data.fn_proto.return_type, import, import->block_context);
} }
static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) { static void preview_function_labels(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry) {
@ -383,7 +399,7 @@ static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableE
AstNode *field_node = decl_node->data.struct_decl.fields.at(i); AstNode *field_node = decl_node->data.struct_decl.fields.at(i);
TypeStructField *type_struct_field = &struct_type->data.structure.fields[i]; TypeStructField *type_struct_field = &struct_type->data.structure.fields[i];
type_struct_field->name = &field_node->data.struct_field.name; type_struct_field->name = &field_node->data.struct_field.name;
type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type); type_struct_field->type_entry = resolve_type(g, field_node->data.struct_field.type, import, import->block_context);
if (type_struct_field->type_entry->id == TypeTableEntryIdStruct) { if (type_struct_field->type_entry->id == TypeTableEntryIdStruct) {
resolve_struct_type(g, import, type_struct_field->type_entry); resolve_struct_type(g, import, type_struct_field->type_entry);
@ -453,7 +469,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
fn_table_entry->import_entry = import; fn_table_entry->import_entry = import;
fn_table_entry->label_table.init(8); fn_table_entry->label_table.init(8);
resolve_function_proto(g, fn_proto, fn_table_entry); resolve_function_proto(g, fn_proto, fn_table_entry, import);
Buf *name = &fn_proto->data.fn_proto.name; Buf *name = &fn_proto->data.fn_proto.name;
g->fn_protos.append(fn_table_entry); g->fn_protos.append(fn_table_entry);
@ -512,7 +528,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
g->fn_table.put(proto_name, fn_table_entry); g->fn_table.put(proto_name, fn_table_entry);
} }
resolve_function_proto(g, proto_node, fn_table_entry); resolve_function_proto(g, proto_node, fn_table_entry, import);
alloc_codegen_node(proto_node); alloc_codegen_node(proto_node);
@ -609,6 +625,7 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
case NodeTypeStructField: case NodeTypeStructField:
case NodeTypeStructValueExpr: case NodeTypeStructValueExpr:
case NodeTypeStructValueField: case NodeTypeStructValueField:
case NodeTypeCompilerFnCall:
zig_unreachable(); zig_unreachable();
} }
} }
@ -681,6 +698,7 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
case NodeTypeStructField: case NodeTypeStructField:
case NodeTypeStructValueExpr: case NodeTypeStructValueExpr:
case NodeTypeStructValueField: case NodeTypeStructValueField:
case NodeTypeCompilerFnCall:
zig_unreachable(); zig_unreachable();
} }
} }
@ -1132,7 +1150,7 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {
static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node) TypeTableEntry *expected_type, AstNode *node)
{ {
TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type); TypeTableEntry *wanted_type = resolve_type(g, node->data.cast_expr.type, import, context);
TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr); TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr);
if (wanted_type->id == TypeTableEntryIdInvalid || if (wanted_type->id == TypeTableEntryIdInvalid ||
@ -1328,7 +1346,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
{ {
TypeTableEntry *explicit_type = nullptr; TypeTableEntry *explicit_type = nullptr;
if (variable_declaration->type != nullptr) { if (variable_declaration->type != nullptr) {
explicit_type = resolve_type(g, variable_declaration->type); explicit_type = resolve_type(g, variable_declaration->type, import, context);
if (explicit_type->id == TypeTableEntryIdUnreachable) { if (explicit_type->id == TypeTableEntryIdUnreachable) {
add_node_error(g, variable_declaration->type, add_node_error(g, variable_declaration->type,
buf_sprintf("variable of type 'unreachable' not allowed")); buf_sprintf("variable of type 'unreachable' not allowed"));
@ -1428,7 +1446,7 @@ static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *imp
AstNodeStructValueExpr *struct_val_expr = &node->data.struct_val_expr; AstNodeStructValueExpr *struct_val_expr = &node->data.struct_val_expr;
TypeTableEntry *type_entry = resolve_type(g, struct_val_expr->type); TypeTableEntry *type_entry = resolve_type(g, struct_val_expr->type, import, context);
if (type_entry->id == TypeTableEntryIdInvalid) { if (type_entry->id == TypeTableEntryIdInvalid) {
return g->builtin_types.entry_invalid; return g->builtin_types.entry_invalid;
@ -1655,7 +1673,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
if (asm_output->return_type) { if (asm_output->return_type) {
node->data.asm_expr.return_count += 1; node->data.asm_expr.return_count += 1;
return_type = resolve_type(g, asm_output->return_type); return_type = resolve_type(g, asm_output->return_type, import, context);
if (node->data.asm_expr.return_count > 1) { if (node->data.asm_expr.return_count > 1) {
add_node_error(g, node, add_node_error(g, node,
buf_sprintf("inline assembly allows up to one output value")); buf_sprintf("inline assembly allows up to one output value"));
@ -1848,6 +1866,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeStructDecl: case NodeTypeStructDecl:
case NodeTypeStructField: case NodeTypeStructField:
case NodeTypeStructValueField: case NodeTypeStructValueField:
case NodeTypeCompilerFnCall:
zig_unreachable(); zig_unreachable();
} }
assert(return_type); assert(return_type);
@ -1996,6 +2015,7 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
case NodeTypeStructField: case NodeTypeStructField:
case NodeTypeStructValueExpr: case NodeTypeStructValueExpr:
case NodeTypeStructValueField: case NodeTypeStructValueField:
case NodeTypeCompilerFnCall:
zig_unreachable(); zig_unreachable();
} }
} }

View File

@ -159,9 +159,11 @@ struct CodeGen {
struct { struct {
TypeTableEntry *entry_bool; TypeTableEntry *entry_bool;
TypeTableEntry *entry_u8; TypeTableEntry *entry_u8;
TypeTableEntry *entry_u16;
TypeTableEntry *entry_u32; TypeTableEntry *entry_u32;
TypeTableEntry *entry_u64; TypeTableEntry *entry_u64;
TypeTableEntry *entry_i8; TypeTableEntry *entry_i8;
TypeTableEntry *entry_i16;
TypeTableEntry *entry_i32; TypeTableEntry *entry_i32;
TypeTableEntry *entry_i64; TypeTableEntry *entry_i64;
TypeTableEntry *entry_isize; TypeTableEntry *entry_isize;

View File

@ -1326,6 +1326,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
case NodeTypeStructDecl: case NodeTypeStructDecl:
case NodeTypeStructField: case NodeTypeStructField:
case NodeTypeStructValueField: case NodeTypeStructValueField:
case NodeTypeCompilerFnCall:
zig_unreachable(); zig_unreachable();
} }
zig_unreachable(); zig_unreachable();
@ -1685,6 +1686,19 @@ static void define_builtin_types(CodeGen *g) {
g->type_table.put(&entry->name, entry); g->type_table.put(&entry->name, entry);
g->builtin_types.entry_u8 = entry; g->builtin_types.entry_u8 = entry;
} }
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->type_ref = LLVMInt16Type();
buf_init_from_str(&entry->name, "u16");
entry->size_in_bits = 16;
entry->align_in_bits = 16;
entry->data.integral.is_signed = false;
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_unsigned());
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_u16 = entry;
}
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->type_ref = LLVMInt32Type(); entry->type_ref = LLVMInt32Type();
@ -1725,6 +1739,19 @@ static void define_builtin_types(CodeGen *g) {
g->type_table.put(&entry->name, entry); g->type_table.put(&entry->name, entry);
g->builtin_types.entry_i8 = entry; g->builtin_types.entry_i8 = entry;
} }
{
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->type_ref = LLVMInt16Type();
buf_init_from_str(&entry->name, "i16");
entry->size_in_bits = 16;
entry->align_in_bits = 16;
entry->data.integral.is_signed = true;
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
entry->size_in_bits, entry->align_in_bits,
LLVMZigEncoding_DW_ATE_signed());
g->type_table.put(&entry->name, entry);
g->builtin_types.entry_i16 = entry;
}
{ {
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt); TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
entry->type_ref = LLVMInt32Type(); entry->type_ref = LLVMInt32Type();

View File

@ -142,6 +142,8 @@ const char *node_type_str(NodeType node_type) {
return "StructValueExpr"; return "StructValueExpr";
case NodeTypeStructValueField: case NodeTypeStructValueField:
return "StructValueField"; return "StructValueField";
case NodeTypeCompilerFnCall:
return "CompilerFnCall";
} }
zig_unreachable(); zig_unreachable();
} }
@ -233,6 +235,12 @@ void ast_print(AstNode *node, int indent) {
ast_print(node->data.type.child_type, indent + 2); ast_print(node->data.type.child_type, indent + 2);
break; break;
} }
case AstNodeTypeTypeCompilerExpr:
{
fprintf(stderr, "CompilerExprType\n");
ast_print(node->data.type.compiler_expr, indent + 2);
break;
}
} }
break; break;
case NodeTypeReturnExpr: case NodeTypeReturnExpr:
@ -402,6 +410,9 @@ void ast_print(AstNode *node, int indent) {
fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_val_field.name)); fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_val_field.name));
ast_print(node->data.struct_val_field.expr, indent + 2); ast_print(node->data.struct_val_field.expr, indent + 2);
break; break;
case NodeTypeCompilerFnCall:
fprintf(stderr, "%s\n", node_type_str(node->type));
break;
} }
} }
@ -985,16 +996,48 @@ static void ast_parse_type_assume_amp(ParseContext *pc, int *token_index, AstNod
} }
/* /*
Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType CompileTimeFnCall : token(NumberSign) token(Symbol) token(LParen) Expression token(RParen)
*/
static AstNode *ast_parse_compiler_fn_call(ParseContext *pc, int *token_index, bool mandatory) {
Token *token = &pc->tokens->at(*token_index);
if (token->id == TokenIdNumberSign) {
*token_index += 1;
} else if (mandatory) {
ast_invalid_token_error(pc, token);
} else {
return nullptr;
}
Token *name_symbol = ast_eat_token(pc, token_index, TokenIdSymbol);
ast_eat_token(pc, token_index, TokenIdLParen);
AstNode *node = ast_create_node(pc, NodeTypeCompilerFnCall, token);
ast_buf_from_token(pc, name_symbol, &node->data.compiler_fn_call.name);
node->data.compiler_fn_call.expr = ast_parse_expression(pc, token_index, true);
ast_eat_token(pc, token_index, TokenIdRParen);
return node;
}
/*
Type : token(Symbol) | token(Unreachable) | token(Void) | PointerType | ArrayType | MaybeType | CompileTimeFnCall
PointerType : token(Ampersand) option(token(Const)) Type PointerType : token(Ampersand) option(token(Const)) Type
ArrayType : token(LBracket) Type token(Semicolon) token(Number) token(RBracket) ArrayType : token(LBracket) Type token(Semicolon) token(Number) token(RBracket)
*/ */
static AstNode *ast_parse_type(ParseContext *pc, int *token_index) { static AstNode *ast_parse_type(ParseContext *pc, int *token_index) {
Token *token = &pc->tokens->at(*token_index); Token *token = &pc->tokens->at(*token_index);
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeType, token); AstNode *node = ast_create_node(pc, NodeTypeType, token);
AstNode *compiler_fn_call = ast_parse_compiler_fn_call(pc, token_index, false);
if (compiler_fn_call) {
node->data.type.type = AstNodeTypeTypeCompilerExpr;
node->data.type.compiler_expr = compiler_fn_call;
return node;
}
*token_index += 1;
if (token->id == TokenIdKeywordUnreachable) { if (token->id == TokenIdKeywordUnreachable) {
node->data.type.type = AstNodeTypeTypePrimitive; node->data.type.type = AstNodeTypeTypePrimitive;
buf_init_from_str(&node->data.type.primitive_name, "unreachable"); buf_init_from_str(&node->data.type.primitive_name, "unreachable");

View File

@ -57,6 +57,7 @@ enum NodeType {
NodeTypeStructField, NodeTypeStructField,
NodeTypeStructValueExpr, NodeTypeStructValueExpr,
NodeTypeStructValueField, NodeTypeStructValueField,
NodeTypeCompilerFnCall,
}; };
struct AstNodeRoot { struct AstNodeRoot {
@ -97,6 +98,7 @@ enum AstNodeTypeType {
AstNodeTypeTypePointer, AstNodeTypeTypePointer,
AstNodeTypeTypeArray, AstNodeTypeTypeArray,
AstNodeTypeTypeMaybe, AstNodeTypeTypeMaybe,
AstNodeTypeTypeCompilerExpr,
}; };
struct AstNodeType { struct AstNodeType {
@ -105,6 +107,7 @@ struct AstNodeType {
AstNode *child_type; AstNode *child_type;
AstNode *array_size; AstNode *array_size;
bool is_const; bool is_const;
AstNode *compiler_expr;
}; };
struct AstNodeBlock { struct AstNodeBlock {
@ -329,6 +332,11 @@ struct AstNodeStructValueExpr {
ZigList<AstNode *> fields; ZigList<AstNode *> fields;
}; };
struct AstNodeCompilerFnCall {
Buf name;
AstNode *expr;
};
struct AstNode { struct AstNode {
enum NodeType type; enum NodeType type;
int line; int line;
@ -368,6 +376,7 @@ struct AstNode {
AstNodeNumberLiteral number_literal; AstNodeNumberLiteral number_literal;
AstNodeStructValueExpr struct_val_expr; AstNodeStructValueExpr struct_val_expr;
AstNodeStructValueField struct_val_field; AstNodeStructValueField struct_val_field;
AstNodeCompilerFnCall compiler_fn_call;
Buf symbol; Buf symbol;
bool bool_literal; bool bool_literal;
} data; } data;

View File

@ -347,7 +347,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
add_simple_case("hello world without libc", R"SOURCE( add_simple_case("hello world without libc", R"SOURCE(
use "std.zig"; use "std.zig";
export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
print_str("Hello, world!\n"); print_str("Hello, world!\n");
return 0; return 0;
} }
@ -357,7 +357,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("a + b + c", R"SOURCE( add_simple_case("a + b + c", R"SOURCE(
use "std.zig"; use "std.zig";
export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
if (false || false || false) { print_str("BAD 1\n"); } if (false || false || false) { print_str("BAD 1\n"); }
if (true && true && false) { print_str("BAD 2\n"); } if (true && true && false) { print_str("BAD 2\n"); }
if (1 | 2 | 4 != 7) { print_str("BAD 3\n"); } if (1 | 2 | 4 != 7) { print_str("BAD 3\n"); }
@ -379,7 +379,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("short circuit", R"SOURCE( add_simple_case("short circuit", R"SOURCE(
use "std.zig"; use "std.zig";
export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
if (true || { print_str("BAD 1\n"); false }) { if (true || { print_str("BAD 1\n"); false }) {
print_str("OK 1\n"); print_str("OK 1\n");
} }
@ -402,7 +402,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("modify operators", R"SOURCE( add_simple_case("modify operators", R"SOURCE(
use "std.zig"; use "std.zig";
export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
var i : i32 = 0; var i : i32 = 0;
i += 5; if (i != 5) { print_str("BAD +=\n"); } i += 5; if (i != 5) { print_str("BAD +=\n"); }
i -= 2; if (i != 3) { print_str("BAD -=\n"); } i -= 2; if (i != 3) { print_str("BAD -=\n"); }
@ -554,7 +554,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("structs", R"SOURCE( add_simple_case("structs", R"SOURCE(
use "std.zig"; use "std.zig";
export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
var foo : Foo; var foo : Foo;
foo.a += 1; foo.a += 1;
foo.b = foo.a == 1; foo.b = foo.a == 1;
@ -628,7 +628,7 @@ use "std.zig";
const g1 : i32 = 1233 + 1; const g1 : i32 = 1233 + 1;
var g2 : i32; var g2 : i32;
export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
if (g2 != 0) { print_str("BAD\n"); } if (g2 != 0) { print_str("BAD\n"); }
g2 = g1; g2 = g1;
if (g2 != 1234) { print_str("BAD\n"); } if (g2 != 1234) { print_str("BAD\n"); }
@ -639,7 +639,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("while loop", R"SOURCE( add_simple_case("while loop", R"SOURCE(
use "std.zig"; use "std.zig";
export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
var i : i32 = 0; var i : i32 = 0;
while (i < 4) { while (i < 4) {
print_str("loop\n"); print_str("loop\n");
@ -651,7 +651,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("continue and break", R"SOURCE( add_simple_case("continue and break", R"SOURCE(
use "std.zig"; use "std.zig";
export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
var i : i32 = 0; var i : i32 = 0;
while (true) { while (true) {
print_str("loop\n"); print_str("loop\n");
@ -667,7 +667,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("maybe type", R"SOURCE( add_simple_case("maybe type", R"SOURCE(
use "std.zig"; use "std.zig";
export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
const x : ?bool = true; const x : ?bool = true;
if (const y ?= x) { if (const y ?= x) {
@ -685,7 +685,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
add_simple_case("implicit cast after unreachable", R"SOURCE( add_simple_case("implicit cast after unreachable", R"SOURCE(
use "std.zig"; use "std.zig";
export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 { pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
const x = outer(); const x = outer();
if (x == 1234) { if (x == 1234) {
print_str("OK\n"); print_str("OK\n");
@ -695,6 +695,17 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
fn inner() -> i32 { 1234 } fn inner() -> i32 { 1234 }
fn outer() -> isize { fn outer() -> isize {
return inner(); return inner();
}
)SOURCE", "OK\n");
add_simple_case("#typeof()", R"SOURCE(
use "std.zig";
const x: u16 = 13;
const z: #typeof(x) = 19;
pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
const y: #typeof(x) = 120;
print_str("OK\n");
return 0;
} }
)SOURCE", "OK\n"); )SOURCE", "OK\n");
} }
@ -999,6 +1010,11 @@ fn f() -> i32 {
(return 1) as i32 (return 1) as i32
} }
)SOURCE", 1, ".tmp_source.zig:3:16: error: invalid cast from type 'unreachable' to 'i32'"); )SOURCE", 1, ".tmp_source.zig:3:16: error: invalid cast from type 'unreachable' to 'i32'");
add_compile_fail_case("invalid compiler fn", R"SOURCE(
fn f() -> #bogus(foo) {
}
)SOURCE", 1, ".tmp_source.zig:2:11: error: invalid compiler function: 'bogus'");
} }
static void print_compiler_invocation(TestCase *test_case) { static void print_compiler_invocation(TestCase *test_case) {