diff --git a/README.md b/README.md index 47bf4beb4e..1b7ec0c9bd 100644 --- a/README.md +++ b/README.md @@ -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 diff --git a/doc/langref.md b/doc/langref.md index b2a8f26205..abd4a7b44a 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -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) diff --git a/doc/vim/syntax/zig.vim b/doc/vim/syntax/zig.vim index c7024e7910..5fc8157e6b 100644 --- a/doc/vim/syntax/zig.vim +++ b/doc/vim/syntax/zig.vim @@ -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 diff --git a/example/guess_number/main.zig b/example/guess_number/main.zig index 1212def80e..4f469d47b2 100644 --- a/example/guess_number/main.zig +++ b/example/guess_number/main.zig @@ -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"); diff --git a/src/all_types.hpp b/src/all_types.hpp index a914fcb001..d1e59ab79f 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -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 *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 all_block_contexts; TypeTableEntry *member_of_struct; Buf symbol_name; + TypeTableEntry *type_entry; // function type // reminder: hash tables must be initialized before use HashMap 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 diff --git a/src/analyze.cpp b/src/analyze.cpp index c60e6481b8..0d3fa6c392 100644 --- a/src/analyze.cpp +++ b/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(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(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 *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: diff --git a/src/codegen.cpp b/src/codegen.cpp index 2503548c51..4d52dd2d2e 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -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: diff --git a/src/parser.cpp b/src/parser.cpp index d910189e7e..9962999516 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -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; diff --git a/src/tokenizer.cpp b/src/tokenizer.cpp index f792f80a40..941126c0a8 100644 --- a/src/tokenizer.cpp +++ b/src/tokenizer.cpp @@ -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"; diff --git a/src/tokenizer.hpp b/src/tokenizer.hpp index efbe1c3fe1..32b5c8e754 100644 --- a/src/tokenizer.hpp +++ b/src/tokenizer.hpp @@ -20,7 +20,6 @@ enum TokenId { TokenIdKeywordExtern, TokenIdKeywordPub, TokenIdKeywordExport, - TokenIdKeywordAs, TokenIdKeywordUse, TokenIdKeywordTrue, TokenIdKeywordFalse, diff --git a/std/rand.zig b/std/rand.zig index d014a746b5..7dab688d29 100644 --- a/std/rand.zig +++ b/std/rand.zig @@ -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; diff --git a/std/std.zig b/std/std.zig index 667210f433..f19578aba0 100644 --- a/std/std.zig +++ b/std/std.zig @@ -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; diff --git a/std/syscall.zig b/std/syscall.zig index 436194778c..134a24f287 100644 --- a/std/syscall.zig +++ b/std/syscall.zig @@ -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))) } - diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 71bef5309c..1a7d35d4f9 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -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) => {