instead of 'as' to cast, call type as function

This commit is contained in:
Andrew Kelley 2016-01-14 02:52:33 -07:00
parent d121ed961a
commit 5f9ecb8566
14 changed files with 532 additions and 391 deletions

View File

@ -41,6 +41,12 @@ compromises backward compatibility.
provide a tag or sha1). provide a tag or sha1).
* Include documentation generator. * Include documentation generator.
* Shebang line OK so language can be used for "scripting" as well. * Shebang line OK so language can be used for "scripting" as well.
* Have the compiler run continuously, watching the file system for source
changes and automatically perform multithreaded compilation to build projects
quickly.
* Hot code swapping. When integrated with the previous feature, you could
press "save" in your editor and see the change immediately in your running
software.
### Current Status ### Current Status

View File

@ -126,12 +126,10 @@ AdditionExpression : MultiplyExpression AdditionOperator AdditionExpression | Mu
AdditionOperator : token(Plus) | token(Minus) AdditionOperator : token(Plus) | token(Minus)
MultiplyExpression : CastExpression MultiplyOperator MultiplyExpression | CastExpression MultiplyExpression : PrefixOpExpression MultiplyOperator MultiplyExpression | PrefixOpExpression
MultiplyOperator : token(Star) | token(Slash) | token(Percent) MultiplyOperator : token(Star) | token(Slash) | token(Percent)
CastExpression : CastExpression token(as) PrimaryExpression | PrefixOpExpression
PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression
SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ContainerInitExpression) SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ContainerInitExpression)

View File

@ -7,7 +7,6 @@ if exists("b:current_syntax")
finish finish
endif endif
syn keyword zigOperator as
syn keyword zigStorage const var extern volatile export pub noalias syn keyword zigStorage const var extern volatile export pub noalias
syn keyword zigStructure struct enum type syn keyword zigStructure struct enum type
syn keyword zigStatement goto break return continue asm syn keyword zigStatement goto break return continue asm

View File

@ -7,7 +7,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
print_str("Welcome to the Guess Number Game in Zig.\n"); print_str("Welcome to the Guess Number Game in Zig.\n");
var seed : u32; var seed : u32;
const err = os_get_random_bytes(&seed as (&u8), @sizeof(u32)); const err = os_get_random_bytes((&u8)(&seed), @sizeof(u32));
if (err != @sizeof(u32)) { if (err != @sizeof(u32)) {
// TODO full error message // TODO full error message
fprint_str(stderr_fileno, "unable to get random bytes\n"); fprint_str(stderr_fileno, "unable to get random bytes\n");

View File

@ -106,7 +106,6 @@ enum NodeType {
NodeTypeReturnExpr, NodeTypeReturnExpr,
NodeTypeVariableDeclaration, NodeTypeVariableDeclaration,
NodeTypeBinOpExpr, NodeTypeBinOpExpr,
NodeTypeCastExpr,
NodeTypeNumberLiteral, NodeTypeNumberLiteral,
NodeTypeStringLiteral, NodeTypeStringLiteral,
NodeTypeCharLiteral, NodeTypeCharLiteral,
@ -272,6 +271,8 @@ struct AstNodeFnCallExpr {
BuiltinFnEntry *builtin_fn; BuiltinFnEntry *builtin_fn;
Expr resolved_expr; Expr resolved_expr;
NumLitCodeGen resolved_num_lit; NumLitCodeGen resolved_num_lit;
Cast cast;
FnTableEntry *fn_entry;
}; };
struct AstNodeArrayAccessExpr { struct AstNodeArrayAccessExpr {
@ -320,15 +321,6 @@ struct AstNodeRootExportDecl {
ZigList<AstNode *> *directives; ZigList<AstNode *> *directives;
}; };
struct AstNodeCastExpr {
AstNode *expr;
AstNode *type;
// populated by semantic analyzer
Cast cast;
Expr resolved_expr;
};
enum PrefixOp { enum PrefixOp {
PrefixOpInvalid, PrefixOpInvalid,
PrefixOpBoolNot, PrefixOpBoolNot,
@ -541,6 +533,9 @@ struct AstNodeSymbolExpr {
// populated by semantic analyzer // populated by semantic analyzer
Expr resolved_expr; Expr resolved_expr;
VariableTableEntry *variable;
TypeTableEntry *meta_type;
FnTableEntry *fn_entry;
}; };
struct AstNodeBoolLiteral { struct AstNodeBoolLiteral {
@ -588,7 +583,6 @@ struct AstNode {
AstNodeBinOpExpr bin_op_expr; AstNodeBinOpExpr bin_op_expr;
AstNodeExternBlock extern_block; AstNodeExternBlock extern_block;
AstNodeDirective directive; AstNodeDirective directive;
AstNodeCastExpr cast_expr;
AstNodePrefixOpExpr prefix_op_expr; AstNodePrefixOpExpr prefix_op_expr;
AstNodeFnCallExpr fn_call_expr; AstNodeFnCallExpr fn_call_expr;
AstNodeArrayAccessExpr array_access_expr; AstNodeArrayAccessExpr array_access_expr;
@ -693,6 +687,12 @@ struct TypeTableEntryEnum {
bool reported_infinite_err; bool reported_infinite_err;
}; };
struct TypeTableEntryFn {
TypeTableEntry *return_type;
TypeTableEntry **param_types;
int param_count;
};
enum TypeTableEntryId { enum TypeTableEntryId {
TypeTableEntryIdInvalid, TypeTableEntryIdInvalid,
TypeTableEntryIdMetaType, TypeTableEntryIdMetaType,
@ -707,6 +707,7 @@ enum TypeTableEntryId {
TypeTableEntryIdNumberLiteral, TypeTableEntryIdNumberLiteral,
TypeTableEntryIdMaybe, TypeTableEntryIdMaybe,
TypeTableEntryIdEnum, TypeTableEntryIdEnum,
TypeTableEntryIdFn,
}; };
struct TypeTableEntry { struct TypeTableEntry {
@ -728,6 +729,7 @@ struct TypeTableEntry {
TypeTableEntryMaybe maybe; TypeTableEntryMaybe maybe;
TypeTableEntryEnum enumeration; TypeTableEntryEnum enumeration;
TypeTableEntryMetaType meta_type; TypeTableEntryMetaType meta_type;
TypeTableEntryFn fn;
} data; } data;
// use these fields to make sure we don't duplicate type table entries for the same type // use these fields to make sure we don't duplicate type table entries for the same type
@ -781,6 +783,7 @@ struct FnTableEntry {
ZigList<BlockContext *> all_block_contexts; ZigList<BlockContext *> all_block_contexts;
TypeTableEntry *member_of_struct; TypeTableEntry *member_of_struct;
Buf symbol_name; Buf symbol_name;
TypeTableEntry *type_entry; // function type
// reminder: hash tables must be initialized before use // reminder: hash tables must be initialized before use
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table; HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
@ -913,4 +916,22 @@ struct BlockContext {
LLVMZigDIScope *di_scope; LLVMZigDIScope *di_scope;
}; };
struct ConstExprValue {
bool ok; // true if constant expression evalution worked
bool depends_on_compile_var;
union {
uint64_t x_uint;
int64_t x_int;
double x_float;
bool x_bool;
FnTableEntry *x_fn;
TypeTableEntry *x_type;
struct {
bool is_null;
ConstExprValue *child_val;
} x_maybe;
} data;
};
#endif #endif

View File

@ -13,8 +13,8 @@
static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node); TypeTableEntry *expected_type, AstNode *node);
static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, static void eval_const_expr(CodeGen *g, BlockContext *context,
AstNode *node, AstNodeNumberLiteral *out_number_literal); AstNode *node, ConstExprValue *out_val);
static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import, static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import,
BlockContext *context, TypeTableEntry *expected_type, AstNode *node); BlockContext *context, TypeTableEntry *expected_type, AstNode *node);
static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type); static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type);
@ -32,8 +32,6 @@ static AstNode *first_executing_node(AstNode *node) {
return first_executing_node(node->data.slice_expr.array_ref_expr); return first_executing_node(node->data.slice_expr.array_ref_expr);
case NodeTypeFieldAccessExpr: case NodeTypeFieldAccessExpr:
return first_executing_node(node->data.field_access_expr.struct_expr); return first_executing_node(node->data.field_access_expr.struct_expr);
case NodeTypeCastExpr:
return first_executing_node(node->data.cast_expr.expr);
case NodeTypeRoot: case NodeTypeRoot:
case NodeTypeRootExportDecl: case NodeTypeRootExportDecl:
case NodeTypeFnProto: case NodeTypeFnProto:
@ -125,6 +123,7 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
case TypeTableEntryIdArray: case TypeTableEntryIdArray:
case TypeTableEntryIdNumberLiteral: case TypeTableEntryIdNumberLiteral:
case TypeTableEntryIdMaybe: case TypeTableEntryIdMaybe:
case TypeTableEntryIdFn:
// nothing to init // nothing to init
break; break;
case TypeTableEntryIdStruct: case TypeTableEntryIdStruct:
@ -357,63 +356,74 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B
} }
} }
static void eval_const_expr_bin_op(CodeGen *g, BlockContext *context,
static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context, AstNode *node, ConstExprValue *out_val)
AstNode *node, AstNodeNumberLiteral *out_number_literal)
{ {
AstNodeNumberLiteral op1_lit; AstNode *op1_node = node->data.bin_op_expr.op1;
AstNodeNumberLiteral op2_lit; AstNode *op2_node = node->data.bin_op_expr.op2;
TypeTableEntry *op1_type = eval_const_expr(g, context, node->data.bin_op_expr.op1, &op1_lit); ConstExprValue op1_val = {0};
TypeTableEntry *op2_type = eval_const_expr(g, context, node->data.bin_op_expr.op1, &op2_lit); ConstExprValue op2_val = {0};
eval_const_expr(g, context, op1_node, &op1_val);
eval_const_expr(g, context, op2_node, &op2_val);
if (op1_type->id == TypeTableEntryIdInvalid || if (!op1_val.ok || !op2_val.ok) {
op2_type->id == TypeTableEntryIdInvalid) return;
{
return g->builtin_types.entry_invalid;
} }
TypeTableEntry *op1_type = get_resolved_expr(op1_node)->type_entry;
TypeTableEntry *op2_type = get_resolved_expr(op2_node)->type_entry;
// TODO complete more of this function instead of returning invalid // TODO complete more of this function instead of returning invalid
// returning invalid makes the "unable to evaluate constant expression" error // returning invalid makes the "unable to evaluate constant expression" error
switch (node->data.bin_op_expr.bin_op) { switch (node->data.bin_op_expr.bin_op) {
case BinOpTypeCmpNotEq: case BinOpTypeCmpNotEq:
{ {
if (is_num_lit_unsigned(op1_lit.kind) && if (op1_type->id == TypeTableEntryIdInt &&
is_num_lit_unsigned(op2_lit.kind)) op2_type->id == TypeTableEntryIdInt)
{ {
out_number_literal->kind = NumLitU8; out_val->data.x_bool = (op1_val.data.x_uint == op2_val.data.x_uint);
out_number_literal->overflow = false; out_val->ok = true;
out_number_literal->data.x_uint = (op1_lit.data.x_uint != op2_lit.data.x_uint);
return get_resolved_expr(node)->type_entry;
} else {
return g->builtin_types.entry_invalid;
} }
break;
} }
case BinOpTypeCmpLessThan: case BinOpTypeCmpLessThan:
{ {
if (is_num_lit_unsigned(op1_lit.kind) && if (op1_type->id == TypeTableEntryIdInt &&
is_num_lit_unsigned(op2_lit.kind)) op2_type->id == TypeTableEntryIdInt)
{ {
out_number_literal->kind = NumLitU8; if (op1_type->data.integral.is_signed &&
out_number_literal->overflow = false; op2_type->data.integral.is_signed)
out_number_literal->data.x_uint = (op1_lit.data.x_uint < op2_lit.data.x_uint); {
return get_resolved_expr(node)->type_entry; out_val->data.x_bool = (op1_val.data.x_int < op2_val.data.x_int);
} else { out_val->ok = true;
return g->builtin_types.entry_invalid; } else if (!op1_type->data.integral.is_signed &&
!op2_type->data.integral.is_signed)
{
out_val->data.x_bool = (op1_val.data.x_uint < op2_val.data.x_uint);
out_val->ok = true;
}
} }
break;
} }
case BinOpTypeMod: case BinOpTypeMod:
{ {
if (is_num_lit_unsigned(op1_lit.kind) && if (op1_type->id == TypeTableEntryIdInt &&
is_num_lit_unsigned(op2_lit.kind)) op2_type->id == TypeTableEntryIdInt)
{ {
out_number_literal->kind = NumLitU64; if (op1_type->data.integral.is_signed &&
out_number_literal->overflow = false; op2_type->data.integral.is_signed)
out_number_literal->data.x_uint = (op1_lit.data.x_uint % op2_lit.data.x_uint); {
return get_resolved_expr(node)->type_entry; out_val->data.x_int = op1_val.data.x_int % op2_val.data.x_int;
} else { out_val->ok = true;
return g->builtin_types.entry_invalid; } else if (!op1_type->data.integral.is_signed &&
!op2_type->data.integral.is_signed)
{
out_val->data.x_uint = op1_val.data.x_uint % op2_val.data.x_uint;
out_val->ok = true;
}
} }
break;
} }
case BinOpTypeBoolOr: case BinOpTypeBoolOr:
case BinOpTypeBoolAnd: case BinOpTypeBoolAnd:
@ -431,7 +441,7 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context,
case BinOpTypeMult: case BinOpTypeMult:
case BinOpTypeDiv: case BinOpTypeDiv:
case BinOpTypeUnwrapMaybe: case BinOpTypeUnwrapMaybe:
return g->builtin_types.entry_invalid; break;
case BinOpTypeInvalid: case BinOpTypeInvalid:
case BinOpTypeAssign: case BinOpTypeAssign:
case BinOpTypeAssignTimes: case BinOpTypeAssignTimes:
@ -448,31 +458,23 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context,
case BinOpTypeAssignBoolOr: case BinOpTypeAssignBoolOr:
zig_unreachable(); zig_unreachable();
} }
zig_unreachable();
} }
static TypeTableEntry *eval_const_expr_fn_call(CodeGen *g, BlockContext *context, static void eval_const_expr_builtin(CodeGen *g, BlockContext *context, AstNode *node, ConstExprValue *out_val) {
AstNode *node, AstNodeNumberLiteral *out_number_literal)
{
if (!node->data.fn_call_expr.is_builtin) {
return g->builtin_types.entry_invalid;
}
switch (node->data.fn_call_expr.builtin_fn->id) { switch (node->data.fn_call_expr.builtin_fn->id) {
case BuiltinFnIdInvalid: case BuiltinFnIdInvalid:
zig_unreachable(); zig_unreachable();
case BuiltinFnIdArithmeticWithOverflow: case BuiltinFnIdArithmeticWithOverflow:
case BuiltinFnIdMemcpy: case BuiltinFnIdMemcpy:
case BuiltinFnIdMemset: case BuiltinFnIdMemset:
return g->builtin_types.entry_invalid; break;
case BuiltinFnIdSizeof: case BuiltinFnIdSizeof:
{ {
AstNode *type_node = node->data.fn_call_expr.params.at(0); AstNode *type_node = node->data.fn_call_expr.params.at(0);
TypeTableEntry *target_type = unwrapped_node_type(type_node); TypeTableEntry *target_type = unwrapped_node_type(type_node);
out_number_literal->overflow = false; out_val->data.x_uint = target_type->size_in_bits / 8;
out_number_literal->data.x_uint = target_type->size_in_bits / 8; out_val->ok = true;
out_number_literal->kind = get_number_literal_kind_unsigned(out_number_literal->data.x_uint); break;
return get_resolved_expr(node)->type_entry;
} }
case BuiltinFnIdMaxValue: case BuiltinFnIdMaxValue:
case BuiltinFnIdMinValue: case BuiltinFnIdMinValue:
@ -480,43 +482,154 @@ static TypeTableEntry *eval_const_expr_fn_call(CodeGen *g, BlockContext *context
case BuiltinFnIdValueCount: case BuiltinFnIdValueCount:
zig_panic("TODO eval_const_expr_fn_call value_count"); zig_panic("TODO eval_const_expr_fn_call value_count");
case BuiltinFnIdTypeof: case BuiltinFnIdTypeof:
return get_resolved_expr(node)->type_entry; // TODO
out_val->ok = true;
break;
} }
zig_unreachable();
} }
static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context, static void eval_const_expr_fn_call_known(CodeGen *g, BlockContext *context,
AstNode *node, AstNodeNumberLiteral *out_number_literal) AstNode *node, ConstExprValue *out_val)
{ {
// currently no functions can be constant expression evaluated,
// so we do nothing
}
static void eval_const_expr_fn_call_cast(CodeGen *g, BlockContext *context,
AstNode *node, ConstExprValue *out_val)
{
assert(node->type == NodeTypeFnCallExpr);
AstNode *expr_node = node->data.fn_call_expr.params.at(0);
Cast *cast = &node->data.fn_call_expr.cast;
switch (cast->op) {
case CastOpNothing:
case CastOpPtrToInt:
case CastOpPointerReinterpret:
case CastOpIntWidenOrShorten:
{
eval_const_expr(g, context, expr_node, out_val);
break;
}
case CastOpMaybeWrap:
{
ConstExprValue *child_val = allocate<ConstExprValue>(1);
eval_const_expr(g, context, expr_node, child_val);
if (!child_val->ok) {
return;
}
out_val->data.x_maybe.child_val = child_val;
out_val->data.x_maybe.is_null = false;
out_val->ok = true;
break;
}
case CastOpToUnknownSizeArray:
zig_panic("TODO eval_const_expr CastOpToUnknownSizeArray");
}
}
static void eval_const_expr_fn_call(CodeGen *g, BlockContext *context,
AstNode *node, ConstExprValue *out_val)
{
if (node->data.fn_call_expr.is_builtin) {
return eval_const_expr_builtin(g, context, node, out_val);
}
if (node->data.fn_call_expr.fn_entry) {
return eval_const_expr_fn_call_known(g, context, node, out_val);
}
return eval_const_expr_fn_call_cast(g, context, node, out_val);
}
static void eval_const_expr_prefix_op_expr(CodeGen *g, BlockContext *context, AstNode *node,
ConstExprValue *out_val)
{
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
switch (node->data.prefix_op_expr.prefix_op) {
case PrefixOpInvalid:
zig_unreachable();
case PrefixOpBoolNot:
{
eval_const_expr(g, context, expr_node, out_val);
if (out_val->ok) {
out_val->data.x_bool = !out_val->data.x_bool;
}
break;
}
case PrefixOpBinNot:
break;
case PrefixOpNegation:
break;
case PrefixOpAddressOf:
{
if (get_resolved_expr(node)->type_entry->id == TypeTableEntryIdMetaType) {
eval_const_expr(g, context, expr_node, out_val);
}
break;
}
case PrefixOpConstAddressOf:
break;
case PrefixOpDereference:
break;
case PrefixOpMaybe:
break;
}
}
static void eval_const_expr(CodeGen *g, BlockContext *context, AstNode *node, ConstExprValue *out_val) {
switch (node->type) { switch (node->type) {
case NodeTypeNumberLiteral: case NodeTypeNumberLiteral:
*out_number_literal = node->data.number_literal; {
return get_resolved_expr(node)->type_entry; if (is_num_lit_unsigned(node->data.number_literal.kind)) {
out_val->data.x_uint = node->data.number_literal.data.x_uint;
out_val->ok = true;
} else if (is_num_lit_float(node->data.number_literal.kind)) {
out_val->data.x_uint = node->data.number_literal.data.x_float;
out_val->ok = true;
}
break;
}
case NodeTypeBoolLiteral: case NodeTypeBoolLiteral:
out_number_literal->data.x_uint = node->data.bool_literal.value ? 1 : 0; out_val->data.x_uint = node->data.bool_literal.value ? 1 : 0;
return get_resolved_expr(node)->type_entry; out_val->ok = true;
break;
case NodeTypeNullLiteral: case NodeTypeNullLiteral:
return get_resolved_expr(node)->type_entry; out_val->data.x_maybe.is_null = true;
out_val->ok = true;
break;
case NodeTypeBinOpExpr: case NodeTypeBinOpExpr:
return eval_const_expr_bin_op(g, context, node, out_number_literal); eval_const_expr_bin_op(g, context, node, out_val);
break;
case NodeTypeSymbol: case NodeTypeSymbol:
{ {
VariableTableEntry *var = find_variable(context, &node->data.symbol_expr.symbol); VariableTableEntry *var = node->data.symbol_expr.variable;
assert(var); if (var) {
AstNode *decl_node = var->decl_node; if (var->is_const) {
AstNode *expr_node = decl_node->data.variable_declaration.expr; AstNode *decl_node = var->decl_node;
if (expr_node) { if (decl_node->type == NodeTypeVariableDeclaration) {
BlockContext *next_context = get_resolved_expr(expr_node)->block_context; AstNode *expr_node = decl_node->data.variable_declaration.expr;
return eval_const_expr(g, next_context, expr_node, out_number_literal); if (expr_node) {
BlockContext *next_context = get_resolved_expr(expr_node)->block_context;
eval_const_expr(g, next_context, expr_node, out_val);
}
}
}
} else if (node->data.symbol_expr.meta_type) {
out_val->ok = true;
} else if (node->data.symbol_expr.fn_entry) {
out_val->ok = true;
out_val->data.x_fn = node->data.symbol_expr.fn_entry;
} else { } else {
// can't eval it zig_unreachable();
return g->builtin_types.entry_invalid;
} }
break;
} }
case NodeTypeFnCallExpr: case NodeTypeFnCallExpr:
return eval_const_expr_fn_call(g, context, node, out_number_literal); eval_const_expr_fn_call(g, context, node, out_val);
break;
case NodeTypePrefixOpExpr:
eval_const_expr_prefix_op_expr(g, context, node, out_val);
break;
default: default:
return g->builtin_types.entry_invalid; break;
} }
} }
@ -550,11 +663,30 @@ 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) { int param_count = node->data.fn_proto.params.length;
TypeTableEntry *fn_type = new_type_table_entry(TypeTableEntryIdFn);
fn_type->data.fn.param_count = param_count;
fn_type->data.fn.param_types = allocate<TypeTableEntry*>(param_count);
fn_table_entry->type_entry = fn_type;
Buf *name = &node->data.fn_proto.name;
buf_resize(&fn_type->name, 0);
buf_appendf(&fn_type->name, "fn %s(", buf_ptr(name));
for (int i = 0; i < param_count; 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 = analyze_type_expr(g, import, import->block_context, TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context,
child->data.param_decl.type); child->data.param_decl.type);
fn_table_entry->type_entry->data.fn.param_types[i] = type_entry;
buf_appendf(&fn_type->name, "%s : %s",
buf_ptr(&child->data.param_decl.name), buf_ptr(&type_entry->name));
if (i + 1 < param_count) {
buf_appendf(&fn_type->name, ", ");
}
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,
@ -567,7 +699,14 @@ static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_t
} }
} }
analyze_type_expr(g, import, import->block_context, node->data.fn_proto.return_type); TypeTableEntry *return_type = analyze_type_expr(g, import, import->block_context,
node->data.fn_proto.return_type);
fn_table_entry->type_entry->data.fn.return_type = return_type;
buf_appendf(&fn_type->name, ")");
if (return_type->id != TypeTableEntryIdVoid) {
buf_appendf(&fn_type->name, " %s", buf_ptr(&return_type->name));
}
} }
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) {
@ -1058,7 +1197,6 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeBoolLiteral: case NodeTypeBoolLiteral:
case NodeTypeNullLiteral: case NodeTypeNullLiteral:
case NodeTypeSymbol: case NodeTypeSymbol:
case NodeTypeCastExpr:
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
case NodeTypeIfBoolExpr: case NodeTypeIfBoolExpr:
case NodeTypeIfVarExpr: case NodeTypeIfVarExpr:
@ -1116,6 +1254,7 @@ static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type,
case TypeTableEntryIdStruct: case TypeTableEntryIdStruct:
case TypeTableEntryIdEnum: case TypeTableEntryIdEnum:
case TypeTableEntryIdMetaType: case TypeTableEntryIdMetaType:
case TypeTableEntryIdFn:
return false; return false;
case TypeTableEntryIdInt: case TypeTableEntryIdInt:
if (is_num_lit_unsigned(num_lit)) { if (is_num_lit_unsigned(num_lit)) {
@ -1703,17 +1842,28 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name); auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name);
if (primitive_table_entry) { if (primitive_table_entry) {
return get_meta_type(g, primitive_table_entry->value); TypeTableEntry *meta_type = get_meta_type(g, primitive_table_entry->value);
node->data.symbol_expr.meta_type = meta_type;
return meta_type;
} }
VariableTableEntry *var = find_variable(context, variable_name); VariableTableEntry *var = find_variable(context, variable_name);
if (var) { if (var) {
node->data.symbol_expr.variable = var;
return var->type; return var->type;
} }
TypeTableEntry *container_type = find_container(context, variable_name); TypeTableEntry *container_type = find_container(context, variable_name);
if (container_type) { if (container_type) {
return get_meta_type(g, container_type); TypeTableEntry *meta_type = get_meta_type(g, container_type);
node->data.symbol_expr.meta_type = meta_type;
return meta_type;
}
auto fn_table_entry = import->fn_table.maybe_get(variable_name);
if (fn_table_entry) {
node->data.symbol_expr.fn_entry = fn_table_entry->value;
return node->data.symbol_expr.fn_entry->type_entry;
} }
add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); add_node_error(g, node, buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name)));
@ -1781,65 +1931,6 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {
zig_unreachable(); zig_unreachable();
} }
static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node)
{
assert(node->type == NodeTypeCastExpr);
TypeTableEntry *wanted_type = analyze_type_expr(g, import, context, node->data.cast_expr.type);
TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, node->data.cast_expr.expr);
if (wanted_type->id == TypeTableEntryIdInvalid ||
actual_type->id == TypeTableEntryIdInvalid)
{
return g->builtin_types.entry_invalid;
}
Cast *cast = &node->data.cast_expr.cast;
cast->source_node = node;
cast->after_type = wanted_type;
if ((wanted_type == g->builtin_types.entry_isize || wanted_type == g->builtin_types.entry_usize) &&
actual_type->id == TypeTableEntryIdPointer)
{
cast->op = CastOpPtrToInt;
return wanted_type;
} else if (wanted_type->id == TypeTableEntryIdInt &&
actual_type->id == TypeTableEntryIdInt)
{
cast->op = CastOpIntWidenOrShorten;
return wanted_type;
} else if (wanted_type->id == TypeTableEntryIdStruct &&
wanted_type->data.structure.is_unknown_size_array &&
actual_type->id == TypeTableEntryIdArray &&
actual_type->data.array.child_type == wanted_type->data.structure.fields[0].type_entry)
{
cast->op = CastOpToUnknownSizeArray;
context->cast_expr_alloca_list.append(cast);
return wanted_type;
} else if (actual_type->id == TypeTableEntryIdNumberLiteral &&
num_lit_fits_in_other_type(g, actual_type, wanted_type))
{
AstNode *literal_node = node->data.cast_expr.expr;
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(literal_node);
assert(!codegen_num_lit->resolved_type);
codegen_num_lit->resolved_type = wanted_type;
cast->op = CastOpNothing;
return wanted_type;
} else if (actual_type->id == TypeTableEntryIdPointer &&
wanted_type->id == TypeTableEntryIdPointer)
{
cast->op = CastOpPointerReinterpret;
return wanted_type;
} else {
add_node_error(g, node,
buf_sprintf("invalid cast from type '%s' to '%s'",
buf_ptr(&actual_type->name),
buf_ptr(&wanted_type->name)));
return g->builtin_types.entry_invalid;
}
}
enum LValPurpose { enum LValPurpose {
LValPurposeAssign, LValPurposeAssign,
LValPurposeAddressOf, LValPurposeAddressOf,
@ -2153,17 +2244,11 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import,
return g->builtin_types.entry_invalid; return g->builtin_types.entry_invalid;
} }
AstNodeNumberLiteral number_literal; ConstExprValue const_val = {0};
TypeTableEntry *resolved_type = eval_const_expr(g, context, size_node, &number_literal); eval_const_expr(g, context, size_node, &const_val);
if (resolved_type->id == TypeTableEntryIdInt) { if (const_val.ok) {
if (resolved_type->data.integral.is_signed) { return get_meta_type(g, get_array_type(g, import, child_type, const_val.data.x_uint));
add_node_error(g, size_node,
buf_create_from_str("array size must be unsigned integer"));
return g->builtin_types.entry_invalid;
} else {
return get_meta_type(g, get_array_type(g, import, child_type, number_literal.data.x_uint));
}
} else { } else {
add_node_error(g, size_node, add_node_error(g, size_node,
buf_create_from_str("unable to resolve constant expression")); buf_create_from_str("unable to resolve constant expression"));
@ -2195,12 +2280,11 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,
} else { } else {
// if the condition is a simple constant expression and there are no break statements // if the condition is a simple constant expression and there are no break statements
// then the return type is unreachable // then the return type is unreachable
AstNodeNumberLiteral number_literal; ConstExprValue const_val = {0};
TypeTableEntry *resolved_type = eval_const_expr(g, context, condition_node, &number_literal); eval_const_expr(g, context, condition_node, &const_val);
if (resolved_type->id != TypeTableEntryIdInvalid) {
assert(resolved_type->id == TypeTableEntryIdBool); if (const_val.ok) {
bool constant_cond_value = number_literal.data.x_uint; if (const_val.data.x_bool) {
if (constant_cond_value) {
node->data.while_expr.condition_always_true = true; node->data.while_expr.condition_always_true = true;
if (!node->data.while_expr.contains_break) { if (!node->data.while_expr.contains_break) {
expr_return_type = g->builtin_types.entry_unreachable; expr_return_type = g->builtin_types.entry_unreachable;
@ -2305,6 +2389,73 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
} }
} }
static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node, TypeTableEntry *invoke_type_entry)
{
assert(node->type == NodeTypeFnCallExpr);
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
int actual_param_count = node->data.fn_call_expr.params.length;
if (actual_param_count != 1) {
add_node_error(g, fn_ref_expr, buf_sprintf("cast expression expects exactly one parameter"));
return g->builtin_types.entry_invalid;
}
AstNode *expr_node = node->data.fn_call_expr.params.at(0);
TypeTableEntry *wanted_type = invoke_type_entry->data.meta_type.child_type;
TypeTableEntry *actual_type = analyze_expression(g, import, context, nullptr, expr_node);
if (wanted_type->id == TypeTableEntryIdInvalid ||
actual_type->id == TypeTableEntryIdInvalid)
{
return g->builtin_types.entry_invalid;
}
Cast *cast = &node->data.fn_call_expr.cast;
cast->source_node = node;
cast->after_type = wanted_type;
if ((wanted_type == g->builtin_types.entry_isize || wanted_type == g->builtin_types.entry_usize) &&
actual_type->id == TypeTableEntryIdPointer)
{
cast->op = CastOpPtrToInt;
return wanted_type;
} else if (wanted_type->id == TypeTableEntryIdInt &&
actual_type->id == TypeTableEntryIdInt)
{
cast->op = CastOpIntWidenOrShorten;
return wanted_type;
} else if (wanted_type->id == TypeTableEntryIdStruct &&
wanted_type->data.structure.is_unknown_size_array &&
actual_type->id == TypeTableEntryIdArray &&
actual_type->data.array.child_type == wanted_type->data.structure.fields[0].type_entry)
{
cast->op = CastOpToUnknownSizeArray;
context->cast_expr_alloca_list.append(cast);
return wanted_type;
} else if (actual_type->id == TypeTableEntryIdNumberLiteral &&
num_lit_fits_in_other_type(g, actual_type, wanted_type))
{
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(expr_node);
assert(!codegen_num_lit->resolved_type);
codegen_num_lit->resolved_type = wanted_type;
cast->op = CastOpNothing;
return wanted_type;
} else if (actual_type->id == TypeTableEntryIdPointer &&
wanted_type->id == TypeTableEntryIdPointer)
{
cast->op = CastOpPointerReinterpret;
return wanted_type;
} else {
add_node_error(g, node,
buf_sprintf("invalid cast from type '%s' to '%s'",
buf_ptr(&actual_type->name),
buf_ptr(&wanted_type->name)));
return g->builtin_types.entry_invalid;
}
}
static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node) TypeTableEntry *expected_type, AstNode *node)
{ {
@ -2458,25 +2609,93 @@ static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry
} }
} }
static TypeTableEntry *analyze_fn_call_raw(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node, FnTableEntry *fn_table_entry, TypeTableEntry *struct_type)
{
assert(node->type == NodeTypeFnCallExpr);
node->data.fn_call_expr.fn_entry = fn_table_entry;
assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto;
// count parameters
int expected_param_count = fn_proto->params.length;
int actual_param_count = node->data.fn_call_expr.params.length;
if (struct_type) {
actual_param_count += 1;
}
if (fn_proto->is_var_args) {
if (actual_param_count < expected_param_count) {
add_node_error(g, node,
buf_sprintf("expected at least %d arguments, got %d",
expected_param_count, actual_param_count));
}
} else if (expected_param_count != actual_param_count) {
add_node_error(g, node,
buf_sprintf("expected %d arguments, got %d",
expected_param_count, actual_param_count));
}
// analyze each parameter. in the case of a method, we already analyzed the
// first parameter in order to figure out which struct we were calling a method on.
for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
AstNode *child = node->data.fn_call_expr.params.at(i);
// determine the expected type for each parameter
TypeTableEntry *expected_param_type = nullptr;
int fn_proto_i = i + (struct_type ? 1 : 0);
if (fn_proto_i < fn_proto->params.length) {
AstNode *param_decl_node = fn_proto->params.at(fn_proto_i);
assert(param_decl_node->type == NodeTypeParamDecl);
AstNode *param_type_node = param_decl_node->data.param_decl.type;
TypeTableEntry *param_type_entry = get_resolved_expr(param_type_node)->type_entry;
if (param_type_entry) {
expected_param_type = unwrapped_node_type(param_type_node);
}
}
analyze_expression(g, import, context, expected_param_type, child);
}
return unwrapped_node_type(fn_proto->return_type);
}
static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node) TypeTableEntry *expected_type, AstNode *node)
{ {
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
TypeTableEntry *struct_type = nullptr;
HashMap<Buf *, FnTableEntry *, buf_hash, buf_eql_buf> *fn_table = &import->fn_table; if (node->data.fn_call_expr.is_builtin) {
AstNode *first_param_expr = nullptr; return analyze_builtin_fn_call_expr(g, import, context, expected_type, node);
Buf *name; }
if (fn_ref_expr->type == NodeTypeFieldAccessExpr) { if (fn_ref_expr->type == NodeTypeFieldAccessExpr) {
first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr; AstNode *first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr;
struct_type = analyze_expression(g, import, context, nullptr, first_param_expr); TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, first_param_expr);
name = &fn_ref_expr->data.field_access_expr.field_name; Buf *name = &fn_ref_expr->data.field_access_expr.field_name;
if (struct_type->id == TypeTableEntryIdStruct) { if (struct_type->id == TypeTableEntryIdStruct ||
fn_table = &struct_type->data.structure.fn_table; (struct_type->id == TypeTableEntryIdPointer &&
} else if (struct_type->id == TypeTableEntryIdPointer && struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct))
struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)
{ {
fn_table = &struct_type->data.pointer.child_type->data.structure.fn_table; TypeTableEntry *bare_struct_type = (struct_type->id == TypeTableEntryIdStruct) ?
struct_type : struct_type->data.pointer.child_type;
auto table_entry = bare_struct_type->data.structure.fn_table.maybe_get(name);
if (table_entry) {
return analyze_fn_call_raw(g, import, context, expected_type, node,
table_entry->value, bare_struct_type);
} else {
add_node_error(g, fn_ref_expr,
buf_sprintf("no function named '%s' in '%s'",
buf_ptr(name), buf_ptr(&bare_struct_type->name)));
// still analyze the parameters, even though we don't know what to expect
for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
AstNode *child = node->data.fn_call_expr.params.at(i);
analyze_expression(g, import, context, nullptr, child);
}
return g->builtin_types.entry_invalid;
}
} else if (struct_type->id == TypeTableEntryIdInvalid) { } else if (struct_type->id == TypeTableEntryIdInvalid) {
return struct_type; return struct_type;
} else if (struct_type->id == TypeTableEntryIdMetaType && } else if (struct_type->id == TypeTableEntryIdMetaType &&
@ -2505,74 +2724,31 @@ static TypeTableEntry *analyze_fn_call_expr(CodeGen *g, ImportTableEntry *import
buf_sprintf("member reference base type not struct or enum")); buf_sprintf("member reference base type not struct or enum"));
return g->builtin_types.entry_invalid; return g->builtin_types.entry_invalid;
} }
} else if (fn_ref_expr->type == NodeTypeSymbol) { }
if (node->data.fn_call_expr.is_builtin) {
return analyze_builtin_fn_call_expr(g, import, context, expected_type, node); TypeTableEntry *invoke_type_entry = analyze_expression(g, import, context, nullptr, fn_ref_expr);
} if (invoke_type_entry->id == TypeTableEntryIdInvalid) {
name = &fn_ref_expr->data.symbol_expr.symbol;
} else {
add_node_error(g, node,
buf_sprintf("function pointers not yet supported"));
return g->builtin_types.entry_invalid; return g->builtin_types.entry_invalid;
} }
auto entry = fn_table->maybe_get(name); // use constant expression evaluator to figure out the function at compile time.
// otherwise we treat this as a function pointer.
if (!entry) { ConstExprValue const_val = {0};
add_node_error(g, fn_ref_expr, eval_const_expr(g, context, fn_ref_expr, &const_val);
buf_sprintf("undefined function: '%s'", buf_ptr(name)));
// still analyze the parameters, even though we don't know what to expect
for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
AstNode *child = node->data.fn_call_expr.params.at(i);
analyze_expression(g, import, context, nullptr, child);
}
if (!const_val.ok) {
add_node_error(g, node, buf_sprintf("function pointers not yet supported"));
return g->builtin_types.entry_invalid; return g->builtin_types.entry_invalid;
}
if (invoke_type_entry->id == TypeTableEntryIdMetaType) {
return analyze_cast_expr(g, import, context, node, invoke_type_entry);
} else if (invoke_type_entry->id == TypeTableEntryIdFn) {
return analyze_fn_call_raw(g, import, context, expected_type, node, const_val.data.x_fn, nullptr);
} else { } else {
FnTableEntry *fn_table_entry = entry->value; add_node_error(g, fn_ref_expr,
assert(fn_table_entry->proto_node->type == NodeTypeFnProto); buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));
AstNodeFnProto *fn_proto = &fn_table_entry->proto_node->data.fn_proto; return g->builtin_types.entry_invalid;
// count parameters
int expected_param_count = fn_proto->params.length;
int actual_param_count = node->data.fn_call_expr.params.length;
if (struct_type) {
actual_param_count += 1;
}
if (fn_proto->is_var_args) {
if (actual_param_count < expected_param_count) {
add_node_error(g, node,
buf_sprintf("expected at least %d arguments, got %d",
expected_param_count, actual_param_count));
}
} else if (expected_param_count != actual_param_count) {
add_node_error(g, node,
buf_sprintf("expected %d arguments, got %d",
expected_param_count, actual_param_count));
}
// analyze each parameter. in the case of a method, we already analyzed the
// first parameter in order to figure out which struct we were calling a method on.
for (int i = 0; i < node->data.fn_call_expr.params.length; i += 1) {
AstNode *child = node->data.fn_call_expr.params.at(i);
// determine the expected type for each parameter
TypeTableEntry *expected_param_type = nullptr;
int fn_proto_i = i + (struct_type ? 1 : 0);
if (fn_proto_i < fn_proto->params.length) {
AstNode *param_decl_node = fn_proto->params.at(fn_proto_i);
assert(param_decl_node->type == NodeTypeParamDecl);
AstNode *param_type_node = param_decl_node->data.param_decl.type;
TypeTableEntry *param_type_entry = get_resolved_expr(param_type_node)->type_entry;
if (param_type_entry) {
expected_param_type = unwrapped_node_type(param_type_node);
}
}
analyze_expression(g, import, context, expected_param_type, child);
}
return unwrapped_node_type(fn_proto->return_type);
} }
} }
@ -2847,9 +3023,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
case NodeTypeSymbol: case NodeTypeSymbol:
return_type = analyze_symbol_expr(g, import, context, expected_type, node); return_type = analyze_symbol_expr(g, import, context, expected_type, node);
break; break;
case NodeTypeCastExpr:
return_type = analyze_cast_expr(g, import, context, expected_type, node);
break;
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
return_type = analyze_prefix_op_expr(g, import, context, expected_type, node); return_type = analyze_prefix_op_expr(g, import, context, expected_type, node);
break; break;
@ -3008,7 +3181,6 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeBoolLiteral: case NodeTypeBoolLiteral:
case NodeTypeNullLiteral: case NodeTypeNullLiteral:
case NodeTypeSymbol: case NodeTypeSymbol:
case NodeTypeCastExpr:
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
case NodeTypeIfBoolExpr: case NodeTypeIfBoolExpr:
case NodeTypeIfVarExpr: case NodeTypeIfVarExpr:
@ -3060,10 +3232,6 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
case NodeTypeReturnExpr: case NodeTypeReturnExpr:
collect_expr_decl_deps(g, import, node->data.return_expr.expr, decl_node); collect_expr_decl_deps(g, import, node->data.return_expr.expr, decl_node);
break; break;
case NodeTypeCastExpr:
collect_expr_decl_deps(g, import, node->data.cast_expr.expr, decl_node);
collect_expr_decl_deps(g, import, node->data.cast_expr.type, decl_node);
break;
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
collect_expr_decl_deps(g, import, node->data.prefix_op_expr.primary_expr, decl_node); collect_expr_decl_deps(g, import, node->data.prefix_op_expr.primary_expr, decl_node);
break; break;
@ -3331,7 +3499,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
case NodeTypeBoolLiteral: case NodeTypeBoolLiteral:
case NodeTypeNullLiteral: case NodeTypeNullLiteral:
case NodeTypeSymbol: case NodeTypeSymbol:
case NodeTypeCastExpr:
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
case NodeTypeIfBoolExpr: case NodeTypeIfBoolExpr:
case NodeTypeIfVarExpr: case NodeTypeIfVarExpr:
@ -3504,8 +3671,6 @@ Expr *get_resolved_expr(AstNode *node) {
return &node->data.return_expr.resolved_expr; return &node->data.return_expr.resolved_expr;
case NodeTypeBinOpExpr: case NodeTypeBinOpExpr:
return &node->data.bin_op_expr.resolved_expr; return &node->data.bin_op_expr.resolved_expr;
case NodeTypeCastExpr:
return &node->data.cast_expr.resolved_expr;
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
return &node->data.prefix_op_expr.resolved_expr; return &node->data.prefix_op_expr.resolved_expr;
case NodeTypeFnCallExpr: case NodeTypeFnCallExpr:
@ -3577,7 +3742,6 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
return &node->data.fn_call_expr.resolved_num_lit; return &node->data.fn_call_expr.resolved_num_lit;
case NodeTypeReturnExpr: case NodeTypeReturnExpr:
case NodeTypeBinOpExpr: case NodeTypeBinOpExpr:
case NodeTypeCastExpr:
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
case NodeTypeArrayAccessExpr: case NodeTypeArrayAccessExpr:
case NodeTypeSliceExpr: case NodeTypeSliceExpr:
@ -3627,7 +3791,6 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
case NodeTypeNumberLiteral: case NodeTypeNumberLiteral:
case NodeTypeReturnExpr: case NodeTypeReturnExpr:
case NodeTypeBinOpExpr: case NodeTypeBinOpExpr:
case NodeTypeCastExpr:
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
case NodeTypeFnCallExpr: case NodeTypeFnCallExpr:
case NodeTypeArrayAccessExpr: case NodeTypeArrayAccessExpr:

View File

@ -71,6 +71,8 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op, static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,
LLVMValueRef target_ref, LLVMValueRef value, LLVMValueRef target_ref, LLVMValueRef value,
TypeTableEntry *op1_type, TypeTableEntry *op2_type); TypeTableEntry *op1_type, TypeTableEntry *op2_type);
static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_val,
TypeTableEntry *actual_type, TypeTableEntry *wanted_type, Cast *cast_node);
static TypeTableEntry *get_type_for_type_node(AstNode *node) { static TypeTableEntry *get_type_for_type_node(AstNode *node) {
TypeTableEntry *meta_type_entry = get_resolved_expr(node)->type_entry; TypeTableEntry *meta_type_entry = get_resolved_expr(node)->type_entry;
@ -381,23 +383,43 @@ static LLVMValueRef gen_enum_value_expr(CodeGen *g, AstNode *node, TypeTableEntr
} }
} }
static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeFnCallExpr);
AstNode *expr_node = node->data.fn_call_expr.params.at(0);
LLVMValueRef expr_val = gen_expr(g, expr_node);
TypeTableEntry *actual_type = get_expr_type(expr_node);
TypeTableEntry *wanted_type = get_expr_type(node);
Cast *cast_node = &node->data.fn_call_expr.cast;
return gen_bare_cast(g, node, expr_val, actual_type, wanted_type, cast_node);
}
static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeFnCallExpr); assert(node->type == NodeTypeFnCallExpr);
FnTableEntry *fn_table_entry; if (node->data.fn_call_expr.is_builtin) {
return gen_builtin_fn_call_expr(g, node);
} else if (node->data.fn_call_expr.cast.after_type) {
return gen_cast_expr(g, node);
}
FnTableEntry *fn_table_entry = node->data.fn_call_expr.fn_entry;
AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr; AstNode *fn_ref_expr = node->data.fn_call_expr.fn_ref_expr;
TypeTableEntry *struct_type; TypeTableEntry *struct_type = nullptr;
AstNode *first_param_expr; AstNode *first_param_expr = nullptr;
if (fn_ref_expr->type == NodeTypeFieldAccessExpr) { if (fn_ref_expr->type == NodeTypeFieldAccessExpr) {
Buf *name = &fn_ref_expr->data.field_access_expr.field_name;
first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr; first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr;
struct_type = get_expr_type(first_param_expr); struct_type = get_expr_type(first_param_expr);
if (struct_type->id == TypeTableEntryIdStruct) { if (struct_type->id == TypeTableEntryIdStruct) {
fn_table_entry = struct_type->data.structure.fn_table.get(name); fn_table_entry = node->data.fn_call_expr.fn_entry;
} else if (struct_type->id == TypeTableEntryIdPointer) { } else if (struct_type->id == TypeTableEntryIdPointer) {
assert(struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct); assert(struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct);
fn_table_entry = struct_type->data.pointer.child_type->data.structure.fn_table.get(name); fn_table_entry = node->data.fn_call_expr.fn_entry;
} else if (struct_type->id == TypeTableEntryIdMetaType && } else if (struct_type->id == TypeTableEntryIdMetaType &&
struct_type->data.meta_type.child_type->id == TypeTableEntryIdEnum) struct_type->data.meta_type.child_type->id == TypeTableEntryIdEnum)
{ {
@ -414,24 +436,8 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
} else { } else {
zig_unreachable(); zig_unreachable();
} }
} else if (fn_ref_expr->type == NodeTypeSymbol) {
if (node->data.fn_call_expr.is_builtin) {
return gen_builtin_fn_call_expr(g, node);
}
// Assume that the expression evaluates to a simple name and return the buf
// TODO after we support function pointers we can make this generic
assert(fn_ref_expr->type == NodeTypeSymbol);
Buf *name = &fn_ref_expr->data.symbol_expr.symbol;
struct_type = nullptr;
first_param_expr = nullptr;
fn_table_entry = g->cur_fn->import_entry->fn_table.get(name);
} else {
zig_unreachable();
} }
assert(fn_table_entry->proto_node->type == NodeTypeFnProto); assert(fn_table_entry->proto_node->type == NodeTypeFnProto);
AstNodeFnProto *fn_proto_data = &fn_table_entry->proto_node->data.fn_proto; AstNodeFnProto *fn_proto_data = &fn_table_entry->proto_node->data.fn_proto;
@ -863,20 +869,6 @@ static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_v
zig_unreachable(); zig_unreachable();
} }
static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeCastExpr);
LLVMValueRef expr_val = gen_expr(g, node->data.cast_expr.expr);
TypeTableEntry *actual_type = get_expr_type(node->data.cast_expr.expr);
TypeTableEntry *wanted_type = get_expr_type(node);
Cast *cast_node = &node->data.cast_expr.cast;
return gen_bare_cast(g, node, expr_val, actual_type, wanted_type, cast_node);
}
static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node, static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
LLVMValueRef val1, LLVMValueRef val2, LLVMValueRef val1, LLVMValueRef val2,
TypeTableEntry *op1_type, TypeTableEntry *op2_type, TypeTableEntry *op1_type, TypeTableEntry *op2_type,
@ -1810,8 +1802,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
return gen_return_expr(g, node); return gen_return_expr(g, node);
case NodeTypeVariableDeclaration: case NodeTypeVariableDeclaration:
return gen_var_decl_expr(g, node); return gen_var_decl_expr(g, node);
case NodeTypeCastExpr:
return gen_cast_expr(g, node);
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
return gen_prefix_op_expr(g, node); return gen_prefix_op_expr(g, node);
case NodeTypeFnCallExpr: case NodeTypeFnCallExpr:

View File

@ -99,8 +99,6 @@ const char *node_type_str(NodeType node_type) {
return "ReturnExpr"; return "ReturnExpr";
case NodeTypeVariableDeclaration: case NodeTypeVariableDeclaration:
return "VariableDeclaration"; return "VariableDeclaration";
case NodeTypeCastExpr:
return "CastExpr";
case NodeTypeNumberLiteral: case NodeTypeNumberLiteral:
return "NumberLiteral"; return "NumberLiteral";
case NodeTypeStringLiteral: case NodeTypeStringLiteral:
@ -265,12 +263,6 @@ void ast_print(AstNode *node, int indent) {
case NodeTypeDirective: case NodeTypeDirective:
fprintf(stderr, "%s\n", node_type_str(node->type)); fprintf(stderr, "%s\n", node_type_str(node->type));
break; break;
case NodeTypeCastExpr:
fprintf(stderr, "%s\n", node_type_str(node->type));
ast_print(node->data.cast_expr.expr, indent + 2);
if (node->data.cast_expr.type)
ast_print(node->data.cast_expr.type, indent + 2);
break;
case NodeTypePrefixOpExpr: case NodeTypePrefixOpExpr:
fprintf(stderr, "%s %s\n", node_type_str(node->type), fprintf(stderr, "%s %s\n", node_type_str(node->type),
prefix_op_str(node->data.prefix_op_expr.prefix_op)); prefix_op_str(node->data.prefix_op_expr.prefix_op));
@ -1604,29 +1596,6 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo
} }
/*
CastExpression : CastExpression token(as) PrimaryExpression | PrefixOpExpression
*/
static AstNode *ast_parse_cast_expression(ParseContext *pc, int *token_index, bool mandatory) {
AstNode *operand_1 = ast_parse_prefix_op_expr(pc, token_index, mandatory);
if (!operand_1)
return nullptr;
while (true) {
Token *as_kw = &pc->tokens->at(*token_index);
if (as_kw->id != TokenIdKeywordAs)
return operand_1;
*token_index += 1;
AstNode *node = ast_create_node(pc, NodeTypeCastExpr, as_kw);
node->data.cast_expr.expr = operand_1;
node->data.cast_expr.type = ast_parse_primary_expr(pc, token_index, true);
operand_1 = node;
}
}
static BinOpType tok_to_mult_op(Token *token) { static BinOpType tok_to_mult_op(Token *token) {
switch (token->id) { switch (token->id) {
case TokenIdStar: return BinOpTypeMult; case TokenIdStar: return BinOpTypeMult;
@ -1654,10 +1623,10 @@ static BinOpType ast_parse_mult_op(ParseContext *pc, int *token_index, bool mand
} }
/* /*
MultiplyExpression : CastExpression MultiplyOperator MultiplyExpression | CastExpression MultiplyExpression : PrefixOpExpression MultiplyOperator MultiplyExpression | PrefixOpExpression
*/ */
static AstNode *ast_parse_mult_expr(ParseContext *pc, int *token_index, bool mandatory) { static AstNode *ast_parse_mult_expr(ParseContext *pc, int *token_index, bool mandatory) {
AstNode *operand_1 = ast_parse_cast_expression(pc, token_index, mandatory); AstNode *operand_1 = ast_parse_prefix_op_expr(pc, token_index, mandatory);
if (!operand_1) if (!operand_1)
return nullptr; return nullptr;
@ -1667,7 +1636,7 @@ static AstNode *ast_parse_mult_expr(ParseContext *pc, int *token_index, bool man
if (mult_op == BinOpTypeInvalid) if (mult_op == BinOpTypeInvalid)
return operand_1; return operand_1;
AstNode *operand_2 = ast_parse_cast_expression(pc, token_index, true); AstNode *operand_2 = ast_parse_prefix_op_expr(pc, token_index, true);
AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token); AstNode *node = ast_create_node(pc, NodeTypeBinOpExpr, token);
node->data.bin_op_expr.op1 = operand_1; node->data.bin_op_expr.op1 = operand_1;

View File

@ -211,8 +211,6 @@ static void end_token(Tokenize *t) {
t->cur_tok->id = TokenIdKeywordPub; t->cur_tok->id = TokenIdKeywordPub;
} else if (mem_eql_str(token_mem, token_len, "export")) { } else if (mem_eql_str(token_mem, token_len, "export")) {
t->cur_tok->id = TokenIdKeywordExport; t->cur_tok->id = TokenIdKeywordExport;
} else if (mem_eql_str(token_mem, token_len, "as")) {
t->cur_tok->id = TokenIdKeywordAs;
} else if (mem_eql_str(token_mem, token_len, "use")) { } else if (mem_eql_str(token_mem, token_len, "use")) {
t->cur_tok->id = TokenIdKeywordUse; t->cur_tok->id = TokenIdKeywordUse;
} else if (mem_eql_str(token_mem, token_len, "true")) { } else if (mem_eql_str(token_mem, token_len, "true")) {
@ -1019,7 +1017,6 @@ const char * token_name(TokenId id) {
case TokenIdKeywordExtern: return "extern"; case TokenIdKeywordExtern: return "extern";
case TokenIdKeywordPub: return "pub"; case TokenIdKeywordPub: return "pub";
case TokenIdKeywordExport: return "export"; case TokenIdKeywordExport: return "export";
case TokenIdKeywordAs: return "as";
case TokenIdKeywordUse: return "use"; case TokenIdKeywordUse: return "use";
case TokenIdKeywordTrue: return "true"; case TokenIdKeywordTrue: return "true";
case TokenIdKeywordFalse: return "false"; case TokenIdKeywordFalse: return "false";

View File

@ -20,7 +20,6 @@ enum TokenId {
TokenIdKeywordExtern, TokenIdKeywordExtern,
TokenIdKeywordPub, TokenIdKeywordPub,
TokenIdKeywordExport, TokenIdKeywordExport,
TokenIdKeywordAs,
TokenIdKeywordUse, TokenIdKeywordUse,
TokenIdKeywordTrue, TokenIdKeywordTrue,
TokenIdKeywordFalse, TokenIdKeywordFalse,

View File

@ -13,7 +13,7 @@ pub struct Rand {
var i : @typeof(ARRAY_SIZE) = 1; var i : @typeof(ARRAY_SIZE) = 1;
while (i < ARRAY_SIZE) { while (i < ARRAY_SIZE) {
const prev_value : u64 = r.array[i - 1]; const prev_value : u64 = r.array[i - 1];
r.array[i] = ((prev_value ^ (prev_value << 30)) * 0x6c078965 + i) as u32; r.array[i] = u32((prev_value ^ (prev_value << 30)) * 0x6c078965 + i);
i += 1; i += 1;
} }
} }
@ -41,7 +41,7 @@ pub struct Rand {
var bytes_left = r.get_bytes_aligned(buf); var bytes_left = r.get_bytes_aligned(buf);
if (bytes_left > 0) { if (bytes_left > 0) {
var rand_val_array : [@sizeof(u32)]u8; var rand_val_array : [@sizeof(u32)]u8;
*(rand_val_array.ptr as (&u32)) = r.get_u32(); *((&u32)(rand_val_array.ptr)) = r.get_u32();
while (bytes_left > 0) { while (bytes_left > 0) {
buf[buf.len - bytes_left] = rand_val_array[@sizeof(u32) - bytes_left]; buf[buf.len - bytes_left] = rand_val_array[@sizeof(u32) - bytes_left];
bytes_left -= 1; bytes_left -= 1;
@ -59,7 +59,7 @@ pub struct Rand {
while (true) { while (true) {
r.get_bytes_aligned(rand_val_array); r.get_bytes_aligned(rand_val_array);
const rand_val = *(rand_val_array.ptr as (&u64)); const rand_val = *((&u64)(rand_val_array.ptr));
if (rand_val < upper_bound) { if (rand_val < upper_bound) {
return start + (rand_val % range); return start + (rand_val % range);
} }
@ -85,7 +85,7 @@ pub struct Rand {
fn get_bytes_aligned(r: &Rand, buf: []u8) usize => { fn get_bytes_aligned(r: &Rand, buf: []u8) usize => {
var bytes_left = buf.len; var bytes_left = buf.len;
while (bytes_left >= 4) { while (bytes_left >= 4) {
*(&buf[buf.len - bytes_left] as (&u32)) = r.get_u32(); *((&u32)(&buf[buf.len - bytes_left])) = r.get_u32();
bytes_left -= @sizeof(u32); bytes_left -= @sizeof(u32);
} }
return bytes_left; return bytes_left;

View File

@ -43,7 +43,7 @@ pub fn readline(buf: []u8, out_len: &usize) bool => {
if (amt_read < 0) { if (amt_read < 0) {
return true; return true;
} }
*out_len = amt_read as usize; *out_len = usize(amt_read);
return false; return false;
} }
@ -94,9 +94,9 @@ const max_u64_base10_digits: usize = 20;
fn buf_print_i64(out_buf: []u8, x: i64) usize => { fn buf_print_i64(out_buf: []u8, x: i64) usize => {
if (x < 0) { if (x < 0) {
out_buf[0] = '-'; out_buf[0] = '-';
return 1 + buf_print_u64(out_buf[1...], ((-(x + 1)) as u64) + 1); return 1 + buf_print_u64(out_buf[1...], u64(-(x + 1)) + 1);
} else { } else {
return buf_print_u64(out_buf, x as u64); return buf_print_u64(out_buf, u64(x));
} }
} }
@ -108,7 +108,7 @@ fn buf_print_u64(out_buf: []u8, x: u64) usize => {
while (true) { while (true) {
const digit = a % 10; const digit = a % 10;
index -= 1; index -= 1;
buf[index] = '0' + (digit as u8); buf[index] = '0' + u8(digit);
a /= 10; a /= 10;
if (a == 0) if (a == 0)
break; break;

View File

@ -18,19 +18,18 @@ fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize => {
} }
pub fn read(fd: isize, buf: &u8, count: usize) isize => { pub fn read(fd: isize, buf: &u8, count: usize) isize => {
syscall3(SYS_read, fd as usize, buf as usize, count) as isize isize(syscall3(SYS_read, usize(fd), usize(buf), count))
} }
pub fn write(fd: isize, buf: &const u8, count: usize) isize => { pub fn write(fd: isize, buf: &const u8, count: usize) isize => {
syscall3(SYS_write, fd as usize, buf as usize, count) as isize isize(syscall3(SYS_write, usize(fd), usize(buf), count))
} }
pub fn exit(status: i32) unreachable => { pub fn exit(status: i32) unreachable => {
syscall1(SYS_exit, status as usize); syscall1(SYS_exit, usize(status));
unreachable{} unreachable{}
} }
pub fn getrandom(buf: &u8, count: usize, flags: u32) isize => { pub fn getrandom(buf: &u8, count: usize, flags: u32) isize => {
syscall3(SYS_getrandom, buf as usize, count, flags as usize) as isize isize(syscall3(SYS_getrandom, usize(buf), count, usize(flags)))
} }

View File

@ -272,7 +272,7 @@ use "std.zig";
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
const a : i32 = 1; const a : i32 = 1;
const b = 2 as i32; const b = i32(2);
if (a + b == 3) { if (a + b == 3) {
print_str("OK\n"); print_str("OK\n");
} }
@ -302,7 +302,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
} }
const c = { const c = {
const no_conflict = 10 as i32; const no_conflict = i32(10);
no_conflict no_conflict
}; };
if (c == 10) { print_str("OK 2\n"); } if (c == 10) { print_str("OK 2\n"); }
@ -358,7 +358,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
var zero : i32 = 0; var zero : i32 = 0;
if (zero == 0) { print_str("zero\n"); } if (zero == 0) { print_str("zero\n"); }
var i = 0 as i32; var i = i32(0);
loop_start: loop_start:
if (i == 3) { if (i == 3) {
goto done; goto done;
@ -384,7 +384,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
} }
i = 0; i = 0;
var accumulator = 0 as u32; var accumulator = u32(0);
while (i < 5) { while (i < 5) {
accumulator += array[i]; accumulator += array[i];
@ -430,9 +430,9 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
if (90 >> 1 >> 2 != 90 >> 3) { print_str("BAD 7\n"); } if (90 >> 1 >> 2 != 90 >> 3) { print_str("BAD 7\n"); }
if (100 - 1 + 1000 != 1099) { print_str("BAD 8\n"); } if (100 - 1 + 1000 != 1099) { print_str("BAD 8\n"); }
if (5 * 4 / 2 % 3 != 1) { print_str("BAD 9\n"); } if (5 * 4 / 2 % 3 != 1) { print_str("BAD 9\n"); }
if (5 as i32 as i32 != 5) { print_str("BAD 10\n"); } if (i32(i32(5)) != 5) { print_str("BAD 10\n"); }
if (!!false) { print_str("BAD 11\n"); } if (!!false) { print_str("BAD 11\n"); }
if (7 as i32 != --(7 as i32)) { print_str("BAD 12\n"); } if (i32(7) != --(i32(7))) { print_str("BAD 12\n"); }
print_str("OK\n"); print_str("OK\n");
return 0; return 0;
@ -495,82 +495,82 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
printf(c"\n"); printf(c"\n");
printf(c"0: %llu\n", printf(c"0: %llu\n",
0 as u64); u64(0));
printf(c"320402575052271: %llu\n", printf(c"320402575052271: %llu\n",
320402575052271 as u64); u64(320402575052271));
printf(c"0x01236789abcdef: %llu\n", printf(c"0x01236789abcdef: %llu\n",
0x01236789abcdef as u64); u64(0x01236789abcdef));
printf(c"0xffffffffffffffff: %llu\n", printf(c"0xffffffffffffffff: %llu\n",
0xffffffffffffffff as u64); u64(0xffffffffffffffff));
printf(c"0x000000ffffffffffffffff: %llu\n", printf(c"0x000000ffffffffffffffff: %llu\n",
0x000000ffffffffffffffff as u64); u64(0x000000ffffffffffffffff));
printf(c"0o1777777777777777777777: %llu\n", printf(c"0o1777777777777777777777: %llu\n",
0o1777777777777777777777 as u64); u64(0o1777777777777777777777));
printf(c"0o0000001777777777777777777777: %llu\n", printf(c"0o0000001777777777777777777777: %llu\n",
0o0000001777777777777777777777 as u64); u64(0o0000001777777777777777777777));
printf(c"0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n", printf(c"0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n",
0b1111111111111111111111111111111111111111111111111111111111111111 as u64); u64(0b1111111111111111111111111111111111111111111111111111111111111111));
printf(c"0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n", printf(c"0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n",
0b0000001111111111111111111111111111111111111111111111111111111111111111 as u64); u64(0b0000001111111111111111111111111111111111111111111111111111111111111111));
printf(c"\n"); printf(c"\n");
printf(c"0.0: %a\n", printf(c"0.0: %a\n",
0.0 as f64); f64(0.0));
printf(c"0e0: %a\n", printf(c"0e0: %a\n",
0e0 as f64); f64(0e0));
printf(c"0.0e0: %a\n", printf(c"0.0e0: %a\n",
0.0e0 as f64); f64(0.0e0));
printf(c"000000000000000000000000000000000000000000000000000000000.0e0: %a\n", printf(c"000000000000000000000000000000000000000000000000000000000.0e0: %a\n",
000000000000000000000000000000000000000000000000000000000.0e0 as f64); f64(000000000000000000000000000000000000000000000000000000000.0e0));
printf(c"0.000000000000000000000000000000000000000000000000000000000e0: %a\n", printf(c"0.000000000000000000000000000000000000000000000000000000000e0: %a\n",
0.000000000000000000000000000000000000000000000000000000000e0 as f64); f64(0.000000000000000000000000000000000000000000000000000000000e0));
printf(c"0.0e000000000000000000000000000000000000000000000000000000000: %a\n", printf(c"0.0e000000000000000000000000000000000000000000000000000000000: %a\n",
0.0e000000000000000000000000000000000000000000000000000000000 as f64); f64(0.0e000000000000000000000000000000000000000000000000000000000));
printf(c"1.0: %a\n", printf(c"1.0: %a\n",
1.0 as f64); f64(1.0));
printf(c"10.0: %a\n", printf(c"10.0: %a\n",
10.0 as f64); f64(10.0));
printf(c"10.5: %a\n", printf(c"10.5: %a\n",
10.5 as f64); f64(10.5));
printf(c"10.5e5: %a\n", printf(c"10.5e5: %a\n",
10.5e5 as f64); f64(10.5e5));
printf(c"10.5e+5: %a\n", printf(c"10.5e+5: %a\n",
10.5e+5 as f64); f64(10.5e+5));
printf(c"50.0e-2: %a\n", printf(c"50.0e-2: %a\n",
50.0e-2 as f64); f64(50.0e-2));
printf(c"50e-2: %a\n", printf(c"50e-2: %a\n",
50e-2 as f64); f64(50e-2));
printf(c"\n"); printf(c"\n");
printf(c"0x1.0: %a\n", printf(c"0x1.0: %a\n",
0x1.0 as f64); f64(0x1.0));
printf(c"0x10.0: %a\n", printf(c"0x10.0: %a\n",
0x10.0 as f64); f64(0x10.0));
printf(c"0x100.0: %a\n", printf(c"0x100.0: %a\n",
0x100.0 as f64); f64(0x100.0));
printf(c"0x103.0: %a\n", printf(c"0x103.0: %a\n",
0x103.0 as f64); f64(0x103.0));
printf(c"0x103.7: %a\n", printf(c"0x103.7: %a\n",
0x103.7 as f64); f64(0x103.7));
printf(c"0x103.70: %a\n", printf(c"0x103.70: %a\n",
0x103.70 as f64); f64(0x103.70));
printf(c"0x103.70p4: %a\n", printf(c"0x103.70p4: %a\n",
0x103.70p4 as f64); f64(0x103.70p4));
printf(c"0x103.70p5: %a\n", printf(c"0x103.70p5: %a\n",
0x103.70p5 as f64); f64(0x103.70p5));
printf(c"0x103.70p+5: %a\n", printf(c"0x103.70p+5: %a\n",
0x103.70p+5 as f64); f64(0x103.70p+5));
printf(c"0x103.70p-5: %a\n", printf(c"0x103.70p-5: %a\n",
0x103.70p-5 as f64); f64(0x103.70p-5));
printf(c"\n"); printf(c"\n");
printf(c"0b10100.00010e0: %a\n", printf(c"0b10100.00010e0: %a\n",
0b10100.00010e0 as f64); f64(0b10100.00010e0));
printf(c"0o10700.00010e0: %a\n", printf(c"0o10700.00010e0: %a\n",
0o10700.00010e0 as f64); f64(0o10700.00010e0));
return 0; return 0;
} }
@ -818,7 +818,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
use "std.zig"; use "std.zig";
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => { pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
var x = 3 as i32; var x = i32(3);
const y = &x; const y = &x;
*y += 1; *y += 1;
@ -1116,7 +1116,7 @@ fn a() i32 => {}
fn a() => { fn a() => {
b(); b();
} }
)SOURCE", 1, ".tmp_source.zig:3:5: error: undefined function: 'b'"); )SOURCE", 1, ".tmp_source.zig:3:5: error: use of undeclared identifier 'b'");
add_compile_fail_case("wrong number of arguments", R"SOURCE( add_compile_fail_case("wrong number of arguments", R"SOURCE(
fn a() => { fn a() => {
@ -1282,7 +1282,7 @@ fn f() => {
add_compile_fail_case("missing else clause", R"SOURCE( add_compile_fail_case("missing else clause", R"SOURCE(
fn f() => { fn f() => {
const x : i32 = if (true) { 1 }; const x : i32 = if (true) { 1 };
const y = if (true) { 1 as i32 }; const y = if (true) { i32(1) };
} }
)SOURCE", 2, ".tmp_source.zig:3:21: error: expected type 'i32', got 'void'", )SOURCE", 2, ".tmp_source.zig:3:21: error: expected type 'i32', got 'void'",
".tmp_source.zig:4:15: error: incompatible types: 'i32' and 'void'"); ".tmp_source.zig:4:15: error: incompatible types: 'i32' and 'void'");
@ -1383,9 +1383,9 @@ fn f() => {
add_compile_fail_case("cast unreachable", R"SOURCE( add_compile_fail_case("cast unreachable", R"SOURCE(
fn f() i32 => { fn f() i32 => {
(return 1) as i32 i32(return 1)
} }
)SOURCE", 1, ".tmp_source.zig:3:16: error: invalid cast from type 'unreachable' to 'i32'"); )SOURCE", 1, ".tmp_source.zig:3:8: error: invalid cast from type 'unreachable' to 'i32'");
add_compile_fail_case("invalid builtin fn", R"SOURCE( add_compile_fail_case("invalid builtin fn", R"SOURCE(
fn f() @bogus(foo) => { fn f() @bogus(foo) => {