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).
* 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

View File

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

View File

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

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

View File

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

View File

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

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,
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:

View File

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

View File

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

View File

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

View File

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

View File

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

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 => {
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)))
}

View File

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