mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 06:13:07 +00:00
instead of 'as' to cast, call type as function
This commit is contained in:
parent
d121ed961a
commit
5f9ecb8566
@ -41,6 +41,12 @@ compromises backward compatibility.
|
||||
provide a tag or sha1).
|
||||
* Include documentation generator.
|
||||
* 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
|
||||
|
||||
|
||||
@ -126,12 +126,10 @@ AdditionExpression : MultiplyExpression AdditionOperator AdditionExpression | Mu
|
||||
|
||||
AdditionOperator : token(Plus) | token(Minus)
|
||||
|
||||
MultiplyExpression : CastExpression MultiplyOperator MultiplyExpression | CastExpression
|
||||
MultiplyExpression : PrefixOpExpression MultiplyOperator MultiplyExpression | PrefixOpExpression
|
||||
|
||||
MultiplyOperator : token(Star) | token(Slash) | token(Percent)
|
||||
|
||||
CastExpression : CastExpression token(as) PrimaryExpression | PrefixOpExpression
|
||||
|
||||
PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression
|
||||
|
||||
SuffixOpExpression : PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | ContainerInitExpression)
|
||||
|
||||
@ -7,7 +7,6 @@ if exists("b:current_syntax")
|
||||
finish
|
||||
endif
|
||||
|
||||
syn keyword zigOperator as
|
||||
syn keyword zigStorage const var extern volatile export pub noalias
|
||||
syn keyword zigStructure struct enum type
|
||||
syn keyword zigStatement goto break return continue asm
|
||||
|
||||
@ -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");
|
||||
|
||||
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)) {
|
||||
// TODO full error message
|
||||
fprint_str(stderr_fileno, "unable to get random bytes\n");
|
||||
|
||||
@ -106,7 +106,6 @@ enum NodeType {
|
||||
NodeTypeReturnExpr,
|
||||
NodeTypeVariableDeclaration,
|
||||
NodeTypeBinOpExpr,
|
||||
NodeTypeCastExpr,
|
||||
NodeTypeNumberLiteral,
|
||||
NodeTypeStringLiteral,
|
||||
NodeTypeCharLiteral,
|
||||
@ -272,6 +271,8 @@ struct AstNodeFnCallExpr {
|
||||
BuiltinFnEntry *builtin_fn;
|
||||
Expr resolved_expr;
|
||||
NumLitCodeGen resolved_num_lit;
|
||||
Cast cast;
|
||||
FnTableEntry *fn_entry;
|
||||
};
|
||||
|
||||
struct AstNodeArrayAccessExpr {
|
||||
@ -320,15 +321,6 @@ struct AstNodeRootExportDecl {
|
||||
ZigList<AstNode *> *directives;
|
||||
};
|
||||
|
||||
struct AstNodeCastExpr {
|
||||
AstNode *expr;
|
||||
AstNode *type;
|
||||
|
||||
// populated by semantic analyzer
|
||||
Cast cast;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
enum PrefixOp {
|
||||
PrefixOpInvalid,
|
||||
PrefixOpBoolNot,
|
||||
@ -541,6 +533,9 @@ struct AstNodeSymbolExpr {
|
||||
|
||||
// populated by semantic analyzer
|
||||
Expr resolved_expr;
|
||||
VariableTableEntry *variable;
|
||||
TypeTableEntry *meta_type;
|
||||
FnTableEntry *fn_entry;
|
||||
};
|
||||
|
||||
struct AstNodeBoolLiteral {
|
||||
@ -588,7 +583,6 @@ struct AstNode {
|
||||
AstNodeBinOpExpr bin_op_expr;
|
||||
AstNodeExternBlock extern_block;
|
||||
AstNodeDirective directive;
|
||||
AstNodeCastExpr cast_expr;
|
||||
AstNodePrefixOpExpr prefix_op_expr;
|
||||
AstNodeFnCallExpr fn_call_expr;
|
||||
AstNodeArrayAccessExpr array_access_expr;
|
||||
@ -693,6 +687,12 @@ struct TypeTableEntryEnum {
|
||||
bool reported_infinite_err;
|
||||
};
|
||||
|
||||
struct TypeTableEntryFn {
|
||||
TypeTableEntry *return_type;
|
||||
TypeTableEntry **param_types;
|
||||
int param_count;
|
||||
};
|
||||
|
||||
enum TypeTableEntryId {
|
||||
TypeTableEntryIdInvalid,
|
||||
TypeTableEntryIdMetaType,
|
||||
@ -707,6 +707,7 @@ enum TypeTableEntryId {
|
||||
TypeTableEntryIdNumberLiteral,
|
||||
TypeTableEntryIdMaybe,
|
||||
TypeTableEntryIdEnum,
|
||||
TypeTableEntryIdFn,
|
||||
};
|
||||
|
||||
struct TypeTableEntry {
|
||||
@ -728,6 +729,7 @@ struct TypeTableEntry {
|
||||
TypeTableEntryMaybe maybe;
|
||||
TypeTableEntryEnum enumeration;
|
||||
TypeTableEntryMetaType meta_type;
|
||||
TypeTableEntryFn fn;
|
||||
} data;
|
||||
|
||||
// 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;
|
||||
TypeTableEntry *member_of_struct;
|
||||
Buf symbol_name;
|
||||
TypeTableEntry *type_entry; // function type
|
||||
|
||||
// reminder: hash tables must be initialized before use
|
||||
HashMap<Buf *, LabelTableEntry *, buf_hash, buf_eql_buf> label_table;
|
||||
@ -913,4 +916,22 @@ struct BlockContext {
|
||||
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
|
||||
|
||||
645
src/analyze.cpp
645
src/analyze.cpp
@ -13,8 +13,8 @@
|
||||
|
||||
static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
TypeTableEntry *expected_type, AstNode *node);
|
||||
static TypeTableEntry *eval_const_expr(CodeGen *g, BlockContext *context,
|
||||
AstNode *node, AstNodeNumberLiteral *out_number_literal);
|
||||
static void eval_const_expr(CodeGen *g, BlockContext *context,
|
||||
AstNode *node, ConstExprValue *out_val);
|
||||
static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableEntry *import,
|
||||
BlockContext *context, TypeTableEntry *expected_type, AstNode *node);
|
||||
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);
|
||||
case NodeTypeFieldAccessExpr:
|
||||
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 NodeTypeRootExportDecl:
|
||||
case NodeTypeFnProto:
|
||||
@ -125,6 +123,7 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
|
||||
case TypeTableEntryIdArray:
|
||||
case TypeTableEntryIdNumberLiteral:
|
||||
case TypeTableEntryIdMaybe:
|
||||
case TypeTableEntryIdFn:
|
||||
// nothing to init
|
||||
break;
|
||||
case TypeTableEntryIdStruct:
|
||||
@ -357,63 +356,74 @@ static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, B
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context,
|
||||
AstNode *node, AstNodeNumberLiteral *out_number_literal)
|
||||
static void eval_const_expr_bin_op(CodeGen *g, BlockContext *context,
|
||||
AstNode *node, ConstExprValue *out_val)
|
||||
{
|
||||
AstNodeNumberLiteral op1_lit;
|
||||
AstNodeNumberLiteral op2_lit;
|
||||
TypeTableEntry *op1_type = eval_const_expr(g, context, node->data.bin_op_expr.op1, &op1_lit);
|
||||
TypeTableEntry *op2_type = eval_const_expr(g, context, node->data.bin_op_expr.op1, &op2_lit);
|
||||
AstNode *op1_node = node->data.bin_op_expr.op1;
|
||||
AstNode *op2_node = node->data.bin_op_expr.op2;
|
||||
ConstExprValue op1_val = {0};
|
||||
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 ||
|
||||
op2_type->id == TypeTableEntryIdInvalid)
|
||||
{
|
||||
return g->builtin_types.entry_invalid;
|
||||
if (!op1_val.ok || !op2_val.ok) {
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
// returning invalid makes the "unable to evaluate constant expression" error
|
||||
|
||||
switch (node->data.bin_op_expr.bin_op) {
|
||||
case BinOpTypeCmpNotEq:
|
||||
{
|
||||
if (is_num_lit_unsigned(op1_lit.kind) &&
|
||||
is_num_lit_unsigned(op2_lit.kind))
|
||||
if (op1_type->id == TypeTableEntryIdInt &&
|
||||
op2_type->id == TypeTableEntryIdInt)
|
||||
{
|
||||
out_number_literal->kind = NumLitU8;
|
||||
out_number_literal->overflow = false;
|
||||
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;
|
||||
out_val->data.x_bool = (op1_val.data.x_uint == op2_val.data.x_uint);
|
||||
out_val->ok = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BinOpTypeCmpLessThan:
|
||||
{
|
||||
if (is_num_lit_unsigned(op1_lit.kind) &&
|
||||
is_num_lit_unsigned(op2_lit.kind))
|
||||
if (op1_type->id == TypeTableEntryIdInt &&
|
||||
op2_type->id == TypeTableEntryIdInt)
|
||||
{
|
||||
out_number_literal->kind = NumLitU8;
|
||||
out_number_literal->overflow = false;
|
||||
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;
|
||||
if (op1_type->data.integral.is_signed &&
|
||||
op2_type->data.integral.is_signed)
|
||||
{
|
||||
out_val->data.x_bool = (op1_val.data.x_int < op2_val.data.x_int);
|
||||
out_val->ok = true;
|
||||
} 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:
|
||||
{
|
||||
if (is_num_lit_unsigned(op1_lit.kind) &&
|
||||
is_num_lit_unsigned(op2_lit.kind))
|
||||
if (op1_type->id == TypeTableEntryIdInt &&
|
||||
op2_type->id == TypeTableEntryIdInt)
|
||||
{
|
||||
out_number_literal->kind = NumLitU64;
|
||||
out_number_literal->overflow = false;
|
||||
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;
|
||||
if (op1_type->data.integral.is_signed &&
|
||||
op2_type->data.integral.is_signed)
|
||||
{
|
||||
out_val->data.x_int = op1_val.data.x_int % op2_val.data.x_int;
|
||||
out_val->ok = true;
|
||||
} 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 BinOpTypeBoolAnd:
|
||||
@ -431,7 +441,7 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context,
|
||||
case BinOpTypeMult:
|
||||
case BinOpTypeDiv:
|
||||
case BinOpTypeUnwrapMaybe:
|
||||
return g->builtin_types.entry_invalid;
|
||||
break;
|
||||
case BinOpTypeInvalid:
|
||||
case BinOpTypeAssign:
|
||||
case BinOpTypeAssignTimes:
|
||||
@ -448,31 +458,23 @@ static TypeTableEntry *eval_const_expr_bin_op(CodeGen *g, BlockContext *context,
|
||||
case BinOpTypeAssignBoolOr:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static TypeTableEntry *eval_const_expr_fn_call(CodeGen *g, BlockContext *context,
|
||||
AstNode *node, AstNodeNumberLiteral *out_number_literal)
|
||||
{
|
||||
if (!node->data.fn_call_expr.is_builtin) {
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
static void eval_const_expr_builtin(CodeGen *g, BlockContext *context, AstNode *node, ConstExprValue *out_val) {
|
||||
switch (node->data.fn_call_expr.builtin_fn->id) {
|
||||
case BuiltinFnIdInvalid:
|
||||
zig_unreachable();
|
||||
case BuiltinFnIdArithmeticWithOverflow:
|
||||
case BuiltinFnIdMemcpy:
|
||||
case BuiltinFnIdMemset:
|
||||
return g->builtin_types.entry_invalid;
|
||||
break;
|
||||
case BuiltinFnIdSizeof:
|
||||
{
|
||||
AstNode *type_node = node->data.fn_call_expr.params.at(0);
|
||||
TypeTableEntry *target_type = unwrapped_node_type(type_node);
|
||||
out_number_literal->overflow = false;
|
||||
out_number_literal->data.x_uint = target_type->size_in_bits / 8;
|
||||
out_number_literal->kind = get_number_literal_kind_unsigned(out_number_literal->data.x_uint);
|
||||
return get_resolved_expr(node)->type_entry;
|
||||
out_val->data.x_uint = target_type->size_in_bits / 8;
|
||||
out_val->ok = true;
|
||||
break;
|
||||
}
|
||||
case BuiltinFnIdMaxValue:
|
||||
case BuiltinFnIdMinValue:
|
||||
@ -480,43 +482,154 @@ static TypeTableEntry *eval_const_expr_fn_call(CodeGen *g, BlockContext *context
|
||||
case BuiltinFnIdValueCount:
|
||||
zig_panic("TODO eval_const_expr_fn_call value_count");
|
||||
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,
|
||||
AstNode *node, AstNodeNumberLiteral *out_number_literal)
|
||||
static void eval_const_expr_fn_call_known(CodeGen *g, BlockContext *context,
|
||||
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) {
|
||||
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:
|
||||
out_number_literal->data.x_uint = node->data.bool_literal.value ? 1 : 0;
|
||||
return get_resolved_expr(node)->type_entry;
|
||||
out_val->data.x_uint = node->data.bool_literal.value ? 1 : 0;
|
||||
out_val->ok = true;
|
||||
break;
|
||||
case NodeTypeNullLiteral:
|
||||
return get_resolved_expr(node)->type_entry;
|
||||
out_val->data.x_maybe.is_null = true;
|
||||
out_val->ok = true;
|
||||
break;
|
||||
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:
|
||||
{
|
||||
VariableTableEntry *var = find_variable(context, &node->data.symbol_expr.symbol);
|
||||
assert(var);
|
||||
AstNode *decl_node = var->decl_node;
|
||||
AstNode *expr_node = decl_node->data.variable_declaration.expr;
|
||||
if (expr_node) {
|
||||
BlockContext *next_context = get_resolved_expr(expr_node)->block_context;
|
||||
return eval_const_expr(g, next_context, expr_node, out_number_literal);
|
||||
VariableTableEntry *var = node->data.symbol_expr.variable;
|
||||
if (var) {
|
||||
if (var->is_const) {
|
||||
AstNode *decl_node = var->decl_node;
|
||||
if (decl_node->type == NodeTypeVariableDeclaration) {
|
||||
AstNode *expr_node = decl_node->data.variable_declaration.expr;
|
||||
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 {
|
||||
// can't eval it
|
||||
return g->builtin_types.entry_invalid;
|
||||
zig_unreachable();
|
||||
}
|
||||
break;
|
||||
}
|
||||
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:
|
||||
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);
|
||||
assert(child->type == NodeTypeParamDecl);
|
||||
TypeTableEntry *type_entry = analyze_type_expr(g, import, import->block_context,
|
||||
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) {
|
||||
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) {
|
||||
@ -1058,7 +1197,6 @@ static void resolve_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
|
||||
case NodeTypeBoolLiteral:
|
||||
case NodeTypeNullLiteral:
|
||||
case NodeTypeSymbol:
|
||||
case NodeTypeCastExpr:
|
||||
case NodeTypePrefixOpExpr:
|
||||
case NodeTypeIfBoolExpr:
|
||||
case NodeTypeIfVarExpr:
|
||||
@ -1116,6 +1254,7 @@ static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type,
|
||||
case TypeTableEntryIdStruct:
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdFn:
|
||||
return false;
|
||||
case TypeTableEntryIdInt:
|
||||
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);
|
||||
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);
|
||||
if (var) {
|
||||
node->data.symbol_expr.variable = var;
|
||||
return var->type;
|
||||
}
|
||||
|
||||
TypeTableEntry *container_type = find_container(context, variable_name);
|
||||
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)));
|
||||
@ -1781,65 +1931,6 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {
|
||||
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 {
|
||||
LValPurposeAssign,
|
||||
LValPurposeAddressOf,
|
||||
@ -2153,17 +2244,11 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import,
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
AstNodeNumberLiteral number_literal;
|
||||
TypeTableEntry *resolved_type = eval_const_expr(g, context, size_node, &number_literal);
|
||||
ConstExprValue const_val = {0};
|
||||
eval_const_expr(g, context, size_node, &const_val);
|
||||
|
||||
if (resolved_type->id == TypeTableEntryIdInt) {
|
||||
if (resolved_type->data.integral.is_signed) {
|
||||
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));
|
||||
}
|
||||
if (const_val.ok) {
|
||||
return get_meta_type(g, get_array_type(g, import, child_type, const_val.data.x_uint));
|
||||
} else {
|
||||
add_node_error(g, size_node,
|
||||
buf_create_from_str("unable to resolve constant expression"));
|
||||
@ -2195,12 +2280,11 @@ static TypeTableEntry *analyze_while_expr(CodeGen *g, ImportTableEntry *import,
|
||||
} else {
|
||||
// if the condition is a simple constant expression and there are no break statements
|
||||
// then the return type is unreachable
|
||||
AstNodeNumberLiteral number_literal;
|
||||
TypeTableEntry *resolved_type = eval_const_expr(g, context, condition_node, &number_literal);
|
||||
if (resolved_type->id != TypeTableEntryIdInvalid) {
|
||||
assert(resolved_type->id == TypeTableEntryIdBool);
|
||||
bool constant_cond_value = number_literal.data.x_uint;
|
||||
if (constant_cond_value) {
|
||||
ConstExprValue const_val = {0};
|
||||
eval_const_expr(g, context, condition_node, &const_val);
|
||||
|
||||
if (const_val.ok) {
|
||||
if (const_val.data.x_bool) {
|
||||
node->data.while_expr.condition_always_true = true;
|
||||
if (!node->data.while_expr.contains_break) {
|
||||
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,
|
||||
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,
|
||||
TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
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;
|
||||
AstNode *first_param_expr = nullptr;
|
||||
Buf *name;
|
||||
|
||||
if (node->data.fn_call_expr.is_builtin) {
|
||||
return analyze_builtin_fn_call_expr(g, import, context, expected_type, node);
|
||||
}
|
||||
|
||||
if (fn_ref_expr->type == NodeTypeFieldAccessExpr) {
|
||||
first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr;
|
||||
struct_type = analyze_expression(g, import, context, nullptr, first_param_expr);
|
||||
name = &fn_ref_expr->data.field_access_expr.field_name;
|
||||
if (struct_type->id == TypeTableEntryIdStruct) {
|
||||
fn_table = &struct_type->data.structure.fn_table;
|
||||
} else if (struct_type->id == TypeTableEntryIdPointer &&
|
||||
struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct)
|
||||
AstNode *first_param_expr = fn_ref_expr->data.field_access_expr.struct_expr;
|
||||
TypeTableEntry *struct_type = analyze_expression(g, import, context, nullptr, first_param_expr);
|
||||
Buf *name = &fn_ref_expr->data.field_access_expr.field_name;
|
||||
if (struct_type->id == TypeTableEntryIdStruct ||
|
||||
(struct_type->id == TypeTableEntryIdPointer &&
|
||||
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) {
|
||||
return struct_type;
|
||||
} 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"));
|
||||
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);
|
||||
}
|
||||
name = &fn_ref_expr->data.symbol_expr.symbol;
|
||||
} else {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("function pointers not yet supported"));
|
||||
}
|
||||
|
||||
TypeTableEntry *invoke_type_entry = analyze_expression(g, import, context, nullptr, fn_ref_expr);
|
||||
if (invoke_type_entry->id == TypeTableEntryIdInvalid) {
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
auto entry = fn_table->maybe_get(name);
|
||||
|
||||
if (!entry) {
|
||||
add_node_error(g, fn_ref_expr,
|
||||
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);
|
||||
}
|
||||
// use constant expression evaluator to figure out the function at compile time.
|
||||
// otherwise we treat this as a function pointer.
|
||||
ConstExprValue const_val = {0};
|
||||
eval_const_expr(g, context, fn_ref_expr, &const_val);
|
||||
|
||||
if (!const_val.ok) {
|
||||
add_node_error(g, node, buf_sprintf("function pointers not yet supported"));
|
||||
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 {
|
||||
FnTableEntry *fn_table_entry = entry->value;
|
||||
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);
|
||||
add_node_error(g, fn_ref_expr,
|
||||
buf_sprintf("type '%s' not a function", buf_ptr(&invoke_type_entry->name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
@ -2847,9 +3023,6 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
|
||||
case NodeTypeSymbol:
|
||||
return_type = analyze_symbol_expr(g, import, context, expected_type, node);
|
||||
break;
|
||||
case NodeTypeCastExpr:
|
||||
return_type = analyze_cast_expr(g, import, context, expected_type, node);
|
||||
break;
|
||||
case NodeTypePrefixOpExpr:
|
||||
return_type = analyze_prefix_op_expr(g, import, context, expected_type, node);
|
||||
break;
|
||||
@ -3008,7 +3181,6 @@ static void analyze_top_level_decl(CodeGen *g, ImportTableEntry *import, AstNode
|
||||
case NodeTypeBoolLiteral:
|
||||
case NodeTypeNullLiteral:
|
||||
case NodeTypeSymbol:
|
||||
case NodeTypeCastExpr:
|
||||
case NodeTypePrefixOpExpr:
|
||||
case NodeTypeIfBoolExpr:
|
||||
case NodeTypeIfVarExpr:
|
||||
@ -3060,10 +3232,6 @@ static void collect_expr_decl_deps(CodeGen *g, ImportTableEntry *import, AstNode
|
||||
case NodeTypeReturnExpr:
|
||||
collect_expr_decl_deps(g, import, node->data.return_expr.expr, decl_node);
|
||||
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:
|
||||
collect_expr_decl_deps(g, import, node->data.prefix_op_expr.primary_expr, decl_node);
|
||||
break;
|
||||
@ -3331,7 +3499,6 @@ static void detect_top_level_decl_deps(CodeGen *g, ImportTableEntry *import, Ast
|
||||
case NodeTypeBoolLiteral:
|
||||
case NodeTypeNullLiteral:
|
||||
case NodeTypeSymbol:
|
||||
case NodeTypeCastExpr:
|
||||
case NodeTypePrefixOpExpr:
|
||||
case NodeTypeIfBoolExpr:
|
||||
case NodeTypeIfVarExpr:
|
||||
@ -3504,8 +3671,6 @@ Expr *get_resolved_expr(AstNode *node) {
|
||||
return &node->data.return_expr.resolved_expr;
|
||||
case NodeTypeBinOpExpr:
|
||||
return &node->data.bin_op_expr.resolved_expr;
|
||||
case NodeTypeCastExpr:
|
||||
return &node->data.cast_expr.resolved_expr;
|
||||
case NodeTypePrefixOpExpr:
|
||||
return &node->data.prefix_op_expr.resolved_expr;
|
||||
case NodeTypeFnCallExpr:
|
||||
@ -3577,7 +3742,6 @@ NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
|
||||
return &node->data.fn_call_expr.resolved_num_lit;
|
||||
case NodeTypeReturnExpr:
|
||||
case NodeTypeBinOpExpr:
|
||||
case NodeTypeCastExpr:
|
||||
case NodeTypePrefixOpExpr:
|
||||
case NodeTypeArrayAccessExpr:
|
||||
case NodeTypeSliceExpr:
|
||||
@ -3627,7 +3791,6 @@ TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
|
||||
case NodeTypeNumberLiteral:
|
||||
case NodeTypeReturnExpr:
|
||||
case NodeTypeBinOpExpr:
|
||||
case NodeTypeCastExpr:
|
||||
case NodeTypePrefixOpExpr:
|
||||
case NodeTypeFnCallExpr:
|
||||
case NodeTypeArrayAccessExpr:
|
||||
|
||||
@ -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,
|
||||
LLVMValueRef target_ref, LLVMValueRef value,
|
||||
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) {
|
||||
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) {
|
||||
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;
|
||||
TypeTableEntry *struct_type;
|
||||
AstNode *first_param_expr;
|
||||
TypeTableEntry *struct_type = nullptr;
|
||||
AstNode *first_param_expr = nullptr;
|
||||
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;
|
||||
struct_type = get_expr_type(first_param_expr);
|
||||
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) {
|
||||
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 &&
|
||||
struct_type->data.meta_type.child_type->id == TypeTableEntryIdEnum)
|
||||
{
|
||||
@ -414,24 +436,8 @@ static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
|
||||
} else {
|
||||
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);
|
||||
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();
|
||||
}
|
||||
|
||||
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,
|
||||
LLVMValueRef val1, LLVMValueRef val2,
|
||||
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);
|
||||
case NodeTypeVariableDeclaration:
|
||||
return gen_var_decl_expr(g, node);
|
||||
case NodeTypeCastExpr:
|
||||
return gen_cast_expr(g, node);
|
||||
case NodeTypePrefixOpExpr:
|
||||
return gen_prefix_op_expr(g, node);
|
||||
case NodeTypeFnCallExpr:
|
||||
|
||||
@ -99,8 +99,6 @@ const char *node_type_str(NodeType node_type) {
|
||||
return "ReturnExpr";
|
||||
case NodeTypeVariableDeclaration:
|
||||
return "VariableDeclaration";
|
||||
case NodeTypeCastExpr:
|
||||
return "CastExpr";
|
||||
case NodeTypeNumberLiteral:
|
||||
return "NumberLiteral";
|
||||
case NodeTypeStringLiteral:
|
||||
@ -265,12 +263,6 @@ void ast_print(AstNode *node, int indent) {
|
||||
case NodeTypeDirective:
|
||||
fprintf(stderr, "%s\n", node_type_str(node->type));
|
||||
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:
|
||||
fprintf(stderr, "%s %s\n", node_type_str(node->type),
|
||||
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) {
|
||||
switch (token->id) {
|
||||
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) {
|
||||
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)
|
||||
return nullptr;
|
||||
|
||||
@ -1667,7 +1636,7 @@ static AstNode *ast_parse_mult_expr(ParseContext *pc, int *token_index, bool man
|
||||
if (mult_op == BinOpTypeInvalid)
|
||||
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);
|
||||
node->data.bin_op_expr.op1 = operand_1;
|
||||
|
||||
@ -211,8 +211,6 @@ static void end_token(Tokenize *t) {
|
||||
t->cur_tok->id = TokenIdKeywordPub;
|
||||
} else if (mem_eql_str(token_mem, token_len, "export")) {
|
||||
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")) {
|
||||
t->cur_tok->id = TokenIdKeywordUse;
|
||||
} 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 TokenIdKeywordPub: return "pub";
|
||||
case TokenIdKeywordExport: return "export";
|
||||
case TokenIdKeywordAs: return "as";
|
||||
case TokenIdKeywordUse: return "use";
|
||||
case TokenIdKeywordTrue: return "true";
|
||||
case TokenIdKeywordFalse: return "false";
|
||||
|
||||
@ -20,7 +20,6 @@ enum TokenId {
|
||||
TokenIdKeywordExtern,
|
||||
TokenIdKeywordPub,
|
||||
TokenIdKeywordExport,
|
||||
TokenIdKeywordAs,
|
||||
TokenIdKeywordUse,
|
||||
TokenIdKeywordTrue,
|
||||
TokenIdKeywordFalse,
|
||||
|
||||
@ -13,7 +13,7 @@ pub struct Rand {
|
||||
var i : @typeof(ARRAY_SIZE) = 1;
|
||||
while (i < ARRAY_SIZE) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
@ -41,7 +41,7 @@ pub struct Rand {
|
||||
var bytes_left = r.get_bytes_aligned(buf);
|
||||
if (bytes_left > 0) {
|
||||
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) {
|
||||
buf[buf.len - bytes_left] = rand_val_array[@sizeof(u32) - bytes_left];
|
||||
bytes_left -= 1;
|
||||
@ -59,7 +59,7 @@ pub struct Rand {
|
||||
|
||||
while (true) {
|
||||
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) {
|
||||
return start + (rand_val % range);
|
||||
}
|
||||
@ -85,7 +85,7 @@ pub struct Rand {
|
||||
fn get_bytes_aligned(r: &Rand, buf: []u8) usize => {
|
||||
var bytes_left = buf.len;
|
||||
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);
|
||||
}
|
||||
return bytes_left;
|
||||
|
||||
@ -43,7 +43,7 @@ pub fn readline(buf: []u8, out_len: &usize) bool => {
|
||||
if (amt_read < 0) {
|
||||
return true;
|
||||
}
|
||||
*out_len = amt_read as usize;
|
||||
*out_len = usize(amt_read);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -94,9 +94,9 @@ const max_u64_base10_digits: usize = 20;
|
||||
fn buf_print_i64(out_buf: []u8, x: i64) usize => {
|
||||
if (x < 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 {
|
||||
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) {
|
||||
const digit = a % 10;
|
||||
index -= 1;
|
||||
buf[index] = '0' + (digit as u8);
|
||||
buf[index] = '0' + u8(digit);
|
||||
a /= 10;
|
||||
if (a == 0)
|
||||
break;
|
||||
|
||||
@ -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 => {
|
||||
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 => {
|
||||
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 => {
|
||||
syscall1(SYS_exit, status as usize);
|
||||
syscall1(SYS_exit, usize(status));
|
||||
unreachable{}
|
||||
}
|
||||
|
||||
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)))
|
||||
}
|
||||
|
||||
|
||||
@ -272,7 +272,7 @@ use "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
const a : i32 = 1;
|
||||
const b = 2 as i32;
|
||||
const b = i32(2);
|
||||
if (a + b == 3) {
|
||||
print_str("OK\n");
|
||||
}
|
||||
@ -302,7 +302,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
}
|
||||
|
||||
const c = {
|
||||
const no_conflict = 10 as i32;
|
||||
const no_conflict = i32(10);
|
||||
no_conflict
|
||||
};
|
||||
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;
|
||||
if (zero == 0) { print_str("zero\n"); }
|
||||
|
||||
var i = 0 as i32;
|
||||
var i = i32(0);
|
||||
loop_start:
|
||||
if (i == 3) {
|
||||
goto done;
|
||||
@ -384,7 +384,7 @@ pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
}
|
||||
|
||||
i = 0;
|
||||
var accumulator = 0 as u32;
|
||||
var accumulator = u32(0);
|
||||
while (i < 5) {
|
||||
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 (100 - 1 + 1000 != 1099) { print_str("BAD 8\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 (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");
|
||||
return 0;
|
||||
@ -495,82 +495,82 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
printf(c"\n");
|
||||
|
||||
printf(c"0: %llu\n",
|
||||
0 as u64);
|
||||
u64(0));
|
||||
printf(c"320402575052271: %llu\n",
|
||||
320402575052271 as u64);
|
||||
u64(320402575052271));
|
||||
printf(c"0x01236789abcdef: %llu\n",
|
||||
0x01236789abcdef as u64);
|
||||
u64(0x01236789abcdef));
|
||||
printf(c"0xffffffffffffffff: %llu\n",
|
||||
0xffffffffffffffff as u64);
|
||||
u64(0xffffffffffffffff));
|
||||
printf(c"0x000000ffffffffffffffff: %llu\n",
|
||||
0x000000ffffffffffffffff as u64);
|
||||
u64(0x000000ffffffffffffffff));
|
||||
printf(c"0o1777777777777777777777: %llu\n",
|
||||
0o1777777777777777777777 as u64);
|
||||
u64(0o1777777777777777777777));
|
||||
printf(c"0o0000001777777777777777777777: %llu\n",
|
||||
0o0000001777777777777777777777 as u64);
|
||||
u64(0o0000001777777777777777777777));
|
||||
printf(c"0b1111111111111111111111111111111111111111111111111111111111111111: %llu\n",
|
||||
0b1111111111111111111111111111111111111111111111111111111111111111 as u64);
|
||||
u64(0b1111111111111111111111111111111111111111111111111111111111111111));
|
||||
printf(c"0b0000001111111111111111111111111111111111111111111111111111111111111111: %llu\n",
|
||||
0b0000001111111111111111111111111111111111111111111111111111111111111111 as u64);
|
||||
u64(0b0000001111111111111111111111111111111111111111111111111111111111111111));
|
||||
|
||||
printf(c"\n");
|
||||
|
||||
printf(c"0.0: %a\n",
|
||||
0.0 as f64);
|
||||
f64(0.0));
|
||||
printf(c"0e0: %a\n",
|
||||
0e0 as f64);
|
||||
f64(0e0));
|
||||
printf(c"0.0e0: %a\n",
|
||||
0.0e0 as f64);
|
||||
f64(0.0e0));
|
||||
printf(c"000000000000000000000000000000000000000000000000000000000.0e0: %a\n",
|
||||
000000000000000000000000000000000000000000000000000000000.0e0 as f64);
|
||||
f64(000000000000000000000000000000000000000000000000000000000.0e0));
|
||||
printf(c"0.000000000000000000000000000000000000000000000000000000000e0: %a\n",
|
||||
0.000000000000000000000000000000000000000000000000000000000e0 as f64);
|
||||
f64(0.000000000000000000000000000000000000000000000000000000000e0));
|
||||
printf(c"0.0e000000000000000000000000000000000000000000000000000000000: %a\n",
|
||||
0.0e000000000000000000000000000000000000000000000000000000000 as f64);
|
||||
f64(0.0e000000000000000000000000000000000000000000000000000000000));
|
||||
printf(c"1.0: %a\n",
|
||||
1.0 as f64);
|
||||
f64(1.0));
|
||||
printf(c"10.0: %a\n",
|
||||
10.0 as f64);
|
||||
f64(10.0));
|
||||
printf(c"10.5: %a\n",
|
||||
10.5 as f64);
|
||||
f64(10.5));
|
||||
printf(c"10.5e5: %a\n",
|
||||
10.5e5 as f64);
|
||||
f64(10.5e5));
|
||||
printf(c"10.5e+5: %a\n",
|
||||
10.5e+5 as f64);
|
||||
f64(10.5e+5));
|
||||
printf(c"50.0e-2: %a\n",
|
||||
50.0e-2 as f64);
|
||||
f64(50.0e-2));
|
||||
printf(c"50e-2: %a\n",
|
||||
50e-2 as f64);
|
||||
f64(50e-2));
|
||||
|
||||
printf(c"\n");
|
||||
|
||||
printf(c"0x1.0: %a\n",
|
||||
0x1.0 as f64);
|
||||
f64(0x1.0));
|
||||
printf(c"0x10.0: %a\n",
|
||||
0x10.0 as f64);
|
||||
f64(0x10.0));
|
||||
printf(c"0x100.0: %a\n",
|
||||
0x100.0 as f64);
|
||||
f64(0x100.0));
|
||||
printf(c"0x103.0: %a\n",
|
||||
0x103.0 as f64);
|
||||
f64(0x103.0));
|
||||
printf(c"0x103.7: %a\n",
|
||||
0x103.7 as f64);
|
||||
f64(0x103.7));
|
||||
printf(c"0x103.70: %a\n",
|
||||
0x103.70 as f64);
|
||||
f64(0x103.70));
|
||||
printf(c"0x103.70p4: %a\n",
|
||||
0x103.70p4 as f64);
|
||||
f64(0x103.70p4));
|
||||
printf(c"0x103.70p5: %a\n",
|
||||
0x103.70p5 as f64);
|
||||
f64(0x103.70p5));
|
||||
printf(c"0x103.70p+5: %a\n",
|
||||
0x103.70p+5 as f64);
|
||||
f64(0x103.70p+5));
|
||||
printf(c"0x103.70p-5: %a\n",
|
||||
0x103.70p-5 as f64);
|
||||
f64(0x103.70p-5));
|
||||
|
||||
printf(c"\n");
|
||||
|
||||
printf(c"0b10100.00010e0: %a\n",
|
||||
0b10100.00010e0 as f64);
|
||||
f64(0b10100.00010e0));
|
||||
printf(c"0o10700.00010e0: %a\n",
|
||||
0o10700.00010e0 as f64);
|
||||
f64(0o10700.00010e0));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -818,7 +818,7 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) i32 => {
|
||||
use "std.zig";
|
||||
|
||||
pub fn main(argc: isize, argv: &&u8, env: &&u8) i32 => {
|
||||
var x = 3 as i32;
|
||||
var x = i32(3);
|
||||
const y = &x;
|
||||
|
||||
*y += 1;
|
||||
@ -1116,7 +1116,7 @@ fn a() i32 => {}
|
||||
fn a() => {
|
||||
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(
|
||||
fn a() => {
|
||||
@ -1282,7 +1282,7 @@ fn f() => {
|
||||
add_compile_fail_case("missing else clause", R"SOURCE(
|
||||
fn f() => {
|
||||
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'",
|
||||
".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(
|
||||
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(
|
||||
fn f() @bogus(foo) => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user