Commit 5f9ecb8566
Changed files (14)
doc
vim
syntax
example
guess_number
test
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
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)
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");
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<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
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);
-
- if (op1_type->id == TypeTableEntryIdInvalid ||
- op2_type->id == TypeTableEntryIdInvalid)
- {
- return g->builtin_types.entry_invalid;
+ 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_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"));
- 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);
- }
-
+ 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;
- } 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));
- }
+ // 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);
- // 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);
- }
+ if (!const_val.ok) {
+ add_node_error(g, node, buf_sprintf("function pointers not yet supported"));
+ return g->builtin_types.entry_invalid;
+ }
- return unwrapped_node_type(fn_proto->return_type);
+ 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 {
+ 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:
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:
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;
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";
src/tokenizer.hpp
@@ -20,7 +20,6 @@ enum TokenId {
TokenIdKeywordExtern,
TokenIdKeywordPub,
TokenIdKeywordExport,
- TokenIdKeywordAs,
TokenIdKeywordUse,
TokenIdKeywordTrue,
TokenIdKeywordFalse,
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;
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;
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)))
}
-
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) => {
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