implicit casts rewrite the AST

This commit is contained in:
Andrew Kelley 2016-01-22 15:31:35 -07:00
parent b09a0cd072
commit 272fe1c54c
6 changed files with 637 additions and 376 deletions

View File

@ -22,7 +22,6 @@ struct FnTableEntry;
struct BlockContext; struct BlockContext;
struct TypeTableEntry; struct TypeTableEntry;
struct VariableTableEntry; struct VariableTableEntry;
struct Cast;
struct BuiltinFnEntry; struct BuiltinFnEntry;
struct LabelTableEntry; struct LabelTableEntry;
struct TypeStructField; struct TypeStructField;
@ -41,15 +40,6 @@ enum CodeGenBuildType {
CodeGenBuildTypeRelease, CodeGenBuildTypeRelease,
}; };
enum CastOp {
CastOpNothing,
CastOpPtrToInt,
CastOpIntWidenOrShorten,
CastOpToUnknownSizeArray,
CastOpMaybeWrap,
CastOpPointerReinterpret,
};
struct ConstEnumValue { struct ConstEnumValue {
uint64_t tag; uint64_t tag;
ConstExprValue *payload; ConstExprValue *payload;
@ -69,29 +59,15 @@ struct ConstExprValue {
} data; } data;
}; };
struct Cast {
CastOp op;
// if op is CastOpArrayToString, this will be a pointer to
// the string struct on the stack
LLVMValueRef ptr;
TypeTableEntry *after_type;
AstNode *source_node;
ConstExprValue const_val;
};
struct Expr { struct Expr {
TypeTableEntry *type_entry; TypeTableEntry *type_entry;
TypeTableEntry *resolved_type;
// the context in which this expression is evaluated. // the context in which this expression is evaluated.
// for blocks, this points to the containing scope, not the block's own scope for its children. // for blocks, this points to the containing scope, not the block's own scope for its children.
BlockContext *block_context; BlockContext *block_context;
// may be null for no cast
Cast implicit_cast; // happens first
Cast implicit_maybe_cast; // happens second
LLVMValueRef const_llvm_val; LLVMValueRef const_llvm_val;
ConstExprValue const_val; ConstExprValue const_val;
bool has_global_const;
}; };
struct StructValExprCodeGen { struct StructValExprCodeGen {
@ -305,6 +281,16 @@ struct AstNodeBinOpExpr {
Expr resolved_expr; Expr resolved_expr;
}; };
enum CastOp {
CastOpNoCast, // signifies the function call expression is not a cast
CastOpNoop, // fn call expr is a cast, but does nothing
CastOpPtrToInt,
CastOpIntWidenOrShorten,
CastOpToUnknownSizeArray,
CastOpMaybeWrap,
CastOpPointerReinterpret,
};
struct AstNodeFnCallExpr { struct AstNodeFnCallExpr {
AstNode *fn_ref_expr; AstNode *fn_ref_expr;
ZigList<AstNode *> params; ZigList<AstNode *> params;
@ -313,8 +299,11 @@ struct AstNodeFnCallExpr {
// populated by semantic analyzer: // populated by semantic analyzer:
BuiltinFnEntry *builtin_fn; BuiltinFnEntry *builtin_fn;
Expr resolved_expr; Expr resolved_expr;
Cast cast;
FnTableEntry *fn_entry; FnTableEntry *fn_entry;
CastOp cast_op;
// if cast_op is CastOpArrayToString, this will be a pointer to
// the string struct on the stack
LLVMValueRef tmp_ptr;
}; };
struct AstNodeArrayAccessExpr { struct AstNodeArrayAccessExpr {
@ -610,6 +599,8 @@ struct AstNodeSymbolExpr {
Expr resolved_expr; Expr resolved_expr;
VariableTableEntry *variable; VariableTableEntry *variable;
FnTableEntry *fn_entry; FnTableEntry *fn_entry;
// set this to instead of analyzing the node, pretend it's a type entry and it's this one.
TypeTableEntry *override_type_entry;
}; };
struct AstNodeBoolLiteral { struct AstNodeBoolLiteral {
@ -644,6 +635,7 @@ struct AstNode {
int column; int column;
uint32_t create_index; // for determinism purposes uint32_t create_index; // for determinism purposes
ImportTableEntry *owner; ImportTableEntry *owner;
AstNode **parent_field; // for AST rewriting
union { union {
AstNodeRoot root; AstNodeRoot root;
AstNodeRootExportDecl root_export_decl; AstNodeRootExportDecl root_export_decl;
@ -997,7 +989,7 @@ struct BlockContext {
BlockContext *parent; // null when this is the root BlockContext *parent; // null when this is the root
HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table; HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table; HashMap<Buf *, TypeTableEntry *, buf_hash, buf_eql_buf> type_table;
ZigList<Cast *> cast_expr_alloca_list; ZigList<AstNode *> cast_alloca_list;
ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list; ZigList<StructValExprCodeGen *> struct_val_expr_alloca_list;
ZigList<VariableTableEntry *> variable_list; ZigList<VariableTableEntry *> variable_list;
AstNode *parent_loop_node; AstNode *parent_loop_node;

View File

@ -17,6 +17,8 @@ static VariableTableEntry *analyze_variable_declaration(CodeGen *g, ImportTableE
BlockContext *context, TypeTableEntry *expected_type, AstNode *node); BlockContext *context, TypeTableEntry *expected_type, AstNode *node);
static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type); static void resolve_struct_type(CodeGen *g, ImportTableEntry *import, TypeTableEntry *struct_type);
static TypeTableEntry *unwrapped_node_type(AstNode *node); static TypeTableEntry *unwrapped_node_type(AstNode *node);
static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node);
static AstNode *first_executing_node(AstNode *node) { static AstNode *first_executing_node(AstNode *node) {
switch (node->type) { switch (node->type) {
@ -369,6 +371,9 @@ static TypeTableEntry *get_unknown_size_array_type(CodeGen *g, TypeTableEntry *c
// and returns invalid type. Otherwise, returns the type of the constant expression value. // and returns invalid type. Otherwise, returns the type of the constant expression value.
// Must be called after analyze_expression on the same node. // Must be called after analyze_expression on the same node.
static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) { static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
if (node->type == NodeTypeSymbol && node->data.symbol_expr.override_type_entry) {
return node->data.symbol_expr.override_type_entry;
}
Expr *expr = get_resolved_expr(node); Expr *expr = get_resolved_expr(node);
assert(expr->type_entry); assert(expr->type_entry);
if (expr->type_entry->id == TypeTableEntryIdInvalid) { if (expr->type_entry->id == TypeTableEntryIdInvalid) {
@ -393,8 +398,9 @@ static TypeTableEntry *resolve_type(CodeGen *g, AstNode *node) {
static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, static TypeTableEntry *analyze_type_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node) AstNode *node)
{ {
analyze_expression(g, import, context, nullptr, node); AstNode **node_ptr = node->parent_field;
return resolve_type(g, node); analyze_expression(g, import, context, nullptr, *node_ptr);
return resolve_type(g, *node_ptr);
} }
static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry, static void resolve_function_proto(CodeGen *g, AstNode *node, FnTableEntry *fn_table_entry,
@ -1044,12 +1050,43 @@ static TypeTableEntry *get_return_type(BlockContext *context) {
return unwrapped_node_type(return_type_node); return unwrapped_node_type(return_type_node);
} }
static bool type_has_codegen_value(TypeTableEntryId id) {
switch (id) {
case TypeTableEntryIdInvalid:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdVoid:
case TypeTableEntryIdUnreachable:
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
return false;
case TypeTableEntryIdBool:
case TypeTableEntryIdInt:
case TypeTableEntryIdFloat:
case TypeTableEntryIdPointer:
case TypeTableEntryIdArray:
case TypeTableEntryIdStruct:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdError:
case TypeTableEntryIdEnum:
case TypeTableEntryIdFn:
return true;
}
zig_unreachable();
}
static void add_global_const_expr(CodeGen *g, Expr *expr) {
if (expr->const_val.ok && type_has_codegen_value(expr->type_entry->id) && !expr->has_global_const) {
g->global_const_list.append(expr);
expr->has_global_const = true;
}
}
static bool num_lit_fits_in_other_type(CodeGen *g, AstNode *literal_node, TypeTableEntry *other_type) { static bool num_lit_fits_in_other_type(CodeGen *g, AstNode *literal_node, TypeTableEntry *other_type) {
Expr *expr = get_resolved_expr(literal_node); Expr *expr = get_resolved_expr(literal_node);
ConstExprValue *const_val = &expr->const_val; ConstExprValue *const_val = &expr->const_val;
assert(const_val->ok); assert(const_val->ok);
if (other_type->id == TypeTableEntryIdFloat) { if (other_type->id == TypeTableEntryIdFloat) {
expr->resolved_type = other_type;
return true; return true;
} else if (other_type->id == TypeTableEntryIdInt && } else if (other_type->id == TypeTableEntryIdInt &&
const_val->data.x_bignum.kind == BigNumKindInt) const_val->data.x_bignum.kind == BigNumKindInt)
@ -1057,7 +1094,6 @@ static bool num_lit_fits_in_other_type(CodeGen *g, AstNode *literal_node, TypeTa
if (bignum_fits_in_bits(&const_val->data.x_bignum, other_type->size_in_bits, if (bignum_fits_in_bits(&const_val->data.x_bignum, other_type->size_in_bits,
other_type->data.integral.is_signed)) other_type->data.integral.is_signed))
{ {
expr->resolved_type = other_type;
return true; return true;
} }
} else if (other_type->id == TypeTableEntryIdNumLitFloat || } else if (other_type->id == TypeTableEntryIdNumLitFloat ||
@ -1145,39 +1181,74 @@ static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *pa
return prev_type; return prev_type;
} }
static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *context, AstNode *node, static bool types_match_const_cast_only(TypeTableEntry *expected_type, TypeTableEntry *actual_type) {
TypeTableEntry *expected_type, TypeTableEntry *actual_type)
{
if (expected_type == nullptr)
return actual_type; // anything will do
if (expected_type == actual_type) if (expected_type == actual_type)
return expected_type; // match return true;
if (expected_type->id == TypeTableEntryIdInvalid || actual_type->id == TypeTableEntryIdInvalid)
return expected_type; // already complained
if (actual_type->id == TypeTableEntryIdUnreachable)
return actual_type; // sorry toots; gotta run. good luck with that expected type.
// pointer const
if (expected_type->id == TypeTableEntryIdPointer &&
actual_type->id == TypeTableEntryIdPointer &&
(!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const))
{
return types_match_const_cast_only(expected_type->data.pointer.child_type,
actual_type->data.pointer.child_type);
}
// unknown size array const
if (expected_type->id == TypeTableEntryIdStruct &&
actual_type->id == TypeTableEntryIdStruct &&
expected_type->data.structure.is_unknown_size_array &&
actual_type->data.structure.is_unknown_size_array &&
(!actual_type->data.structure.fields[0].type_entry->data.pointer.is_const ||
expected_type->data.structure.fields[0].type_entry->data.pointer.is_const))
{
return types_match_const_cast_only(
expected_type->data.structure.fields[0].type_entry->data.pointer.child_type,
actual_type->data.structure.fields[0].type_entry->data.pointer.child_type);
}
// maybe
if (expected_type->id == TypeTableEntryIdMaybe && if (expected_type->id == TypeTableEntryIdMaybe &&
actual_type->id == TypeTableEntryIdMaybe) actual_type->id == TypeTableEntryIdMaybe)
{ {
TypeTableEntry *expected_child = expected_type->data.maybe.child_type; return types_match_const_cast_only(
TypeTableEntry *actual_child = actual_type->data.maybe.child_type; expected_type->data.maybe.child_type,
return resolve_type_compatibility(g, context, node, expected_child, actual_child); actual_type->data.maybe.child_type);
}
// error
if (expected_type->id == TypeTableEntryIdError &&
actual_type->id == TypeTableEntryIdError)
{
return types_match_const_cast_only(
expected_type->data.error.child_type,
actual_type->data.error.child_type);
}
// fn
if (expected_type->id == TypeTableEntryIdFn &&
actual_type->id == TypeTableEntryIdFn)
{
zig_panic("TODO types_match_const_cast_only for fns");
}
return false;
}
static bool types_match_with_implicit_cast(CodeGen *g, TypeTableEntry *expected_type,
TypeTableEntry *actual_type, AstNode *literal_node, bool *reported_err)
{
if (types_match_const_cast_only(expected_type, actual_type)) {
return true;
} }
// implicit conversion from non maybe type to maybe type // implicit conversion from non maybe type to maybe type
if (expected_type->id == TypeTableEntryIdMaybe) { if (expected_type->id == TypeTableEntryIdMaybe &&
TypeTableEntry *resolved_type = resolve_type_compatibility(g, context, node, types_match_with_implicit_cast(g, expected_type->data.maybe.child_type, actual_type,
expected_type->data.maybe.child_type, actual_type); literal_node, reported_err))
if (resolved_type->id == TypeTableEntryIdInvalid) { {
return resolved_type; return true;
}
Expr *expr = get_resolved_expr(node);
expr->implicit_maybe_cast.op = CastOpMaybeWrap;
expr->implicit_maybe_cast.after_type = expected_type;
expr->implicit_maybe_cast.source_node = node;
context->cast_expr_alloca_list.append(&expr->implicit_maybe_cast);
return expected_type;
} }
// implicit widening conversion // implicit widening conversion
@ -1186,78 +1257,94 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont
expected_type->data.integral.is_signed == actual_type->data.integral.is_signed && expected_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
expected_type->size_in_bits >= actual_type->size_in_bits) expected_type->size_in_bits >= actual_type->size_in_bits)
{ {
Expr *expr = get_resolved_expr(node); return true;
expr->implicit_cast.after_type = expected_type;
expr->implicit_cast.op = CastOpIntWidenOrShorten;
expr->implicit_cast.source_node = node;
return expected_type;
} }
// implicit constant sized array to unknown size array conversion // implicit constant sized array to unknown size array conversion
if (expected_type->id == TypeTableEntryIdStruct && if (expected_type->id == TypeTableEntryIdStruct &&
expected_type->data.structure.is_unknown_size_array && expected_type->data.structure.is_unknown_size_array &&
actual_type->id == TypeTableEntryIdArray && actual_type->id == TypeTableEntryIdArray &&
actual_type->data.array.child_type == expected_type->data.structure.fields[0].type_entry->data.pointer.child_type) types_match_const_cast_only(
{
Expr *expr = get_resolved_expr(node);
expr->implicit_cast.after_type = expected_type;
expr->implicit_cast.op = CastOpToUnknownSizeArray;
expr->implicit_cast.source_node = node;
context->cast_expr_alloca_list.append(&expr->implicit_cast);
return expected_type;
}
// implicit non-const to const for pointers
if (expected_type->id == TypeTableEntryIdPointer &&
actual_type->id == TypeTableEntryIdPointer &&
(!actual_type->data.pointer.is_const || expected_type->data.pointer.is_const))
{
TypeTableEntry *resolved_type = resolve_type_compatibility(g, context, node,
expected_type->data.pointer.child_type,
actual_type->data.pointer.child_type);
if (resolved_type->id == TypeTableEntryIdInvalid) {
return resolved_type;
}
return expected_type;
}
// implicit non-const to const for unknown size arrays
if (expected_type->id == TypeTableEntryIdStruct &&
actual_type->id == TypeTableEntryIdStruct &&
expected_type->data.structure.is_unknown_size_array &&
actual_type->data.structure.is_unknown_size_array &&
(!actual_type->data.structure.fields[0].type_entry->data.pointer.is_const ||
expected_type->data.structure.fields[0].type_entry->data.pointer.is_const))
{
TypeTableEntry *resolved_type = resolve_type_compatibility(g, context, node,
expected_type->data.structure.fields[0].type_entry->data.pointer.child_type, expected_type->data.structure.fields[0].type_entry->data.pointer.child_type,
actual_type->data.structure.fields[0].type_entry->data.pointer.child_type); actual_type->data.array.child_type))
if (resolved_type->id == TypeTableEntryIdInvalid) { {
return resolved_type; return true;
}
return expected_type;
} }
// implicit number literal to typed number
if ((actual_type->id == TypeTableEntryIdNumLitFloat || if ((actual_type->id == TypeTableEntryIdNumLitFloat ||
actual_type->id == TypeTableEntryIdNumLitInt)) actual_type->id == TypeTableEntryIdNumLitInt))
{ {
if (num_lit_fits_in_other_type(g, node, expected_type)) { if (num_lit_fits_in_other_type(g, literal_node, expected_type)) {
return expected_type; return true;
} else { } else {
return g->builtin_types.entry_invalid; *reported_err = true;
} }
} }
return false;
}
static AstNode *create_ast_node(CodeGen *g, ImportTableEntry *import, NodeType kind) {
AstNode *node = allocate<AstNode>(1);
node->type = kind;
node->owner = import;
node->create_index = g->next_node_index;
g->next_node_index += 1;
return node;
}
static AstNode *create_ast_type_node(CodeGen *g, ImportTableEntry *import, TypeTableEntry *type_entry) {
AstNode *node = create_ast_node(g, import, NodeTypeSymbol);
node->data.symbol_expr.override_type_entry = type_entry;
return node;
}
static TypeTableEntry *create_and_analyze_cast_node(CodeGen *g, ImportTableEntry *import,
BlockContext *context, TypeTableEntry *cast_to_type, AstNode *node)
{
AstNode *new_parent_node = create_ast_node(g, import, NodeTypeFnCallExpr);
*node->parent_field = new_parent_node;
new_parent_node->parent_field = node->parent_field;
new_parent_node->data.fn_call_expr.fn_ref_expr = create_ast_type_node(g, import, cast_to_type);
new_parent_node->data.fn_call_expr.params.append(node);
normalize_parent_ptrs(new_parent_node);
return analyze_expression(g, import, context, cast_to_type, new_parent_node);
}
static TypeTableEntry *resolve_type_compatibility(CodeGen *g, ImportTableEntry *import,
BlockContext *context, AstNode *node,
TypeTableEntry *expected_type, TypeTableEntry *actual_type)
{
if (expected_type == nullptr)
return actual_type; // anything will do
if (expected_type == actual_type)
return expected_type; // match
if (expected_type->id == TypeTableEntryIdInvalid || actual_type->id == TypeTableEntryIdInvalid)
return g->builtin_types.entry_invalid;
if (actual_type->id == TypeTableEntryIdUnreachable)
return actual_type;
bool reported_err = false;
if (types_match_with_implicit_cast(g, expected_type, actual_type, node, &reported_err)) {
return create_and_analyze_cast_node(g, import, context, expected_type, node);
}
if (!reported_err) {
add_node_error(g, first_executing_node(node), add_node_error(g, first_executing_node(node),
buf_sprintf("expected type '%s', got '%s'", buf_sprintf("expected type '%s', got '%s'",
buf_ptr(&expected_type->name), buf_ptr(&expected_type->name),
buf_ptr(&actual_type->name))); buf_ptr(&actual_type->name)));
}
return g->builtin_types.entry_invalid; return g->builtin_types.entry_invalid;
} }
static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, BlockContext *block_context, static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, ImportTableEntry *import,
AstNode *parent_source_node, BlockContext *block_context, AstNode *parent_source_node,
AstNode **child_nodes, TypeTableEntry **child_types, int child_count) AstNode **child_nodes, TypeTableEntry **child_types, int child_count)
{ {
assert(child_count > 0); assert(child_count > 0);
@ -1270,7 +1357,14 @@ static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, BlockContext
} }
for (int i = 0; i < child_count; i += 1) { for (int i = 0; i < child_count; i += 1) {
resolve_type_compatibility(g, block_context, child_nodes[i], expected_type, child_types[i]); if (!child_nodes[i]) {
continue;
}
Expr *expr = get_resolved_expr(child_nodes[i]);
TypeTableEntry *resolved_type = resolve_type_compatibility(g, import, block_context,
child_nodes[i], expected_type, child_types[i]);
expr->type_entry = resolved_type;
add_global_const_expr(g, expr);
} }
return expected_type; return expected_type;
@ -1667,13 +1761,7 @@ static TypeTableEntry *resolve_expr_const_val_as_type(CodeGen *g, AstNode *node,
static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode *node, AstNode *other) { static TypeTableEntry *resolve_expr_const_val_as_other_expr(CodeGen *g, AstNode *node, AstNode *other) {
Expr *expr = get_resolved_expr(node); Expr *expr = get_resolved_expr(node);
Expr *other_expr = get_resolved_expr(other); Expr *other_expr = get_resolved_expr(other);
ConstExprValue *other_const_val; expr->const_val = other_expr->const_val;
if (other_expr->implicit_maybe_cast.after_type) {
other_const_val = &other_expr->implicit_maybe_cast.const_val;
} else {
other_const_val = &other_expr->const_val;
}
expr->const_val = *other_const_val;
return other_expr->type_entry; return other_expr->type_entry;
} }
@ -1758,6 +1846,10 @@ static TypeTableEntry *resolve_expr_const_val_as_bignum_op(CodeGen *g, AstNode *
static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node) TypeTableEntry *expected_type, AstNode *node)
{ {
if (node->data.symbol_expr.override_type_entry) {
return resolve_expr_const_val_as_type(g, node, node->data.symbol_expr.override_type_entry);
}
Buf *variable_name = &node->data.symbol_expr.symbol; Buf *variable_name = &node->data.symbol_expr.symbol;
auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name); auto primitive_table_entry = g->primitive_type_table.maybe_get(variable_name);
@ -1772,13 +1864,7 @@ static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import,
AstNode *decl_node = var->decl_node; AstNode *decl_node = var->decl_node;
if (decl_node->type == NodeTypeVariableDeclaration) { if (decl_node->type == NodeTypeVariableDeclaration) {
AstNode *expr_node = decl_node->data.variable_declaration.expr; AstNode *expr_node = decl_node->data.variable_declaration.expr;
Expr *other_expr = get_resolved_expr(expr_node); ConstExprValue *other_const_val = &get_resolved_expr(expr_node)->const_val;
ConstExprValue *other_const_val;
if (other_expr->implicit_maybe_cast.after_type) {
other_const_val = &other_expr->implicit_maybe_cast.const_val;
} else {
other_const_val = &other_expr->const_val;
}
if (other_const_val->ok) { if (other_const_val->ok) {
return resolve_expr_const_val_as_other_expr(g, node, expr_node); return resolve_expr_const_val_as_other_expr(g, node, expr_node);
} }
@ -1955,7 +2041,7 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im
AstNode *op_nodes[] = {op1, op2}; AstNode *op_nodes[] = {op1, op2};
TypeTableEntry *op_types[] = {op1_type, op2_type}; TypeTableEntry *op_types[] = {op1_type, op2_type};
TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, context, node, TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node,
op_nodes, op_types, 2); op_nodes, op_types, 2);
if (resolved_type->id == TypeTableEntryIdInvalid) { if (resolved_type->id == TypeTableEntryIdInvalid) {
@ -2109,7 +2195,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
AstNode *op_nodes[] = {op1, op2}; AstNode *op_nodes[] = {op1, op2};
TypeTableEntry *op_types[] = {lhs_type, rhs_type}; TypeTableEntry *op_types[] = {lhs_type, rhs_type};
TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, context, node, TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, import, context, node,
op_nodes, op_types, 2); op_nodes, op_types, 2);
if (resolved_type->id == TypeTableEntryIdInvalid) { if (resolved_type->id == TypeTableEntryIdInvalid) {
@ -2162,6 +2248,7 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
add_node_error(g, op1, add_node_error(g, op1,
buf_sprintf("expected maybe type, got '%s'", buf_sprintf("expected maybe type, got '%s'",
buf_ptr(&lhs_type->name))); buf_ptr(&lhs_type->name)));
return g->builtin_types.entry_invalid;
} }
} }
case BinOpTypeInvalid: case BinOpTypeInvalid:
@ -2502,8 +2589,8 @@ static TypeTableEntry *analyze_if_then_else(CodeGen *g, ImportTableEntry *import
if (else_node) { if (else_node) {
else_type = analyze_expression(g, import, context, expected_type, else_node); else_type = analyze_expression(g, import, context, expected_type, else_node);
} else { } else {
else_type = g->builtin_types.entry_void; else_type = resolve_type_compatibility(g, import, context, parent_node, expected_type,
else_type = resolve_type_compatibility(g, context, parent_node, expected_type, else_type); g->builtin_types.entry_void);
} }
@ -2512,7 +2599,7 @@ static TypeTableEntry *analyze_if_then_else(CodeGen *g, ImportTableEntry *import
} else { } else {
AstNode *op_nodes[] = {then_block, else_node}; AstNode *op_nodes[] = {then_block, else_node};
TypeTableEntry *op_types[] = {then_type, else_type}; TypeTableEntry *op_types[] = {then_type, else_type};
return resolve_peer_type_compatibility(g, context, parent_node, op_nodes, op_types, 2); return resolve_peer_type_compatibility(g, import, context, parent_node, op_nodes, op_types, 2);
} }
} }
@ -2616,39 +2703,32 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
} }
} }
static void eval_const_expr_implicit_cast(CodeGen *g, ImportTableEntry *import, BlockContext *context, static void eval_const_expr_implicit_cast(CodeGen *g, AstNode *node, AstNode *expr_node) {
AstNode *node, Cast *cast, AstNode *expr_node) assert(node->type == NodeTypeFnCallExpr);
{ ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val;
switch (cast->op) { ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
case CastOpNothing: if (!other_val->ok) {
return;
}
assert(other_val != const_val);
switch (node->data.fn_call_expr.cast_op) {
case CastOpNoCast:
zig_unreachable();
case CastOpNoop:
case CastOpPtrToInt: case CastOpPtrToInt:
case CastOpIntWidenOrShorten: case CastOpIntWidenOrShorten:
case CastOpPointerReinterpret: case CastOpPointerReinterpret:
{
ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val;
ConstExprValue *const_val = &cast->const_val;
assert(const_val != other_val);
*const_val = *other_val; *const_val = *other_val;
break; break;
}
case CastOpToUnknownSizeArray: case CastOpToUnknownSizeArray:
// TODO eval const expr zig_panic("TODO CastOpToUnknownSizeArray");
break; break;
case CastOpMaybeWrap: case CastOpMaybeWrap:
{
ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val;
ConstExprValue *const_val = &cast->const_val;
if (!other_val->ok) {
break;
}
assert(const_val != other_val);
const_val->data.x_maybe = other_val; const_val->data.x_maybe = other_val;
const_val->ok = true; const_val->ok = true;
break; break;
} }
} }
}
static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
AstNode *node) AstNode *node)
@ -2673,52 +2753,92 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
return g->builtin_types.entry_invalid; return g->builtin_types.entry_invalid;
} }
Cast *cast = &node->data.fn_call_expr.cast; // explicit match or non-const to const
cast->source_node = node; if (types_match_const_cast_only(wanted_type, actual_type)) {
cast->after_type = wanted_type; node->data.fn_call_expr.cast_op = CastOpNoop;
eval_const_expr_implicit_cast(g, node, expr_node);
return wanted_type;
}
// explicit cast from pointer to isize or usize
if ((wanted_type == g->builtin_types.entry_isize || wanted_type == g->builtin_types.entry_usize) && if ((wanted_type == g->builtin_types.entry_isize || wanted_type == g->builtin_types.entry_usize) &&
actual_type->id == TypeTableEntryIdPointer) actual_type->id == TypeTableEntryIdPointer)
{ {
cast->op = CastOpPtrToInt; node->data.fn_call_expr.cast_op = CastOpPtrToInt;
eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); eval_const_expr_implicit_cast(g, node, expr_node);
return wanted_type; return wanted_type;
} else if (wanted_type->id == TypeTableEntryIdInt && }
// explicit cast from any int to any other int
if (wanted_type->id == TypeTableEntryIdInt &&
actual_type->id == TypeTableEntryIdInt) actual_type->id == TypeTableEntryIdInt)
{ {
cast->op = CastOpIntWidenOrShorten; node->data.fn_call_expr.cast_op = CastOpIntWidenOrShorten;
eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); eval_const_expr_implicit_cast(g, node, expr_node);
return wanted_type; return wanted_type;
} else if (wanted_type->id == TypeTableEntryIdStruct && }
// explicit cast from fixed size array to unknown size array
if (wanted_type->id == TypeTableEntryIdStruct &&
wanted_type->data.structure.is_unknown_size_array && wanted_type->data.structure.is_unknown_size_array &&
actual_type->id == TypeTableEntryIdArray && actual_type->id == TypeTableEntryIdArray &&
actual_type->data.array.child_type == wanted_type->data.structure.fields[0].type_entry) types_match_const_cast_only(
wanted_type->data.structure.fields[0].type_entry->data.pointer.child_type,
actual_type->data.array.child_type))
{ {
cast->op = CastOpToUnknownSizeArray; node->data.fn_call_expr.cast_op = CastOpToUnknownSizeArray;
context->cast_expr_alloca_list.append(cast); context->cast_alloca_list.append(node);
eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); eval_const_expr_implicit_cast(g, node, expr_node);
return wanted_type; return wanted_type;
} else if (actual_type->id == TypeTableEntryIdNumLitFloat || }
actual_type->id == TypeTableEntryIdNumLitInt)
{ // explicit cast from pointer to another pointer
num_lit_fits_in_other_type(g, expr_node, wanted_type); if (actual_type->id == TypeTableEntryIdPointer &&
cast->op = CastOpNothing;
eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node);
return wanted_type;
} else if (actual_type->id == TypeTableEntryIdPointer &&
wanted_type->id == TypeTableEntryIdPointer) wanted_type->id == TypeTableEntryIdPointer)
{ {
cast->op = CastOpPointerReinterpret; node->data.fn_call_expr.cast_op = CastOpPointerReinterpret;
eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node); eval_const_expr_implicit_cast(g, node, expr_node);
return wanted_type;
}
// explicit cast from child type of maybe type to maybe type
if (wanted_type->id == TypeTableEntryIdMaybe) {
if (types_match_const_cast_only(wanted_type->data.maybe.child_type, actual_type)) {
node->data.fn_call_expr.cast_op = CastOpMaybeWrap;
eval_const_expr_implicit_cast(g, node, expr_node);
return wanted_type;
} else if (actual_type->id == TypeTableEntryIdNumLitInt ||
actual_type->id == TypeTableEntryIdNumLitFloat)
{
if (num_lit_fits_in_other_type(g, expr_node, wanted_type->data.maybe.child_type)) {
node->data.fn_call_expr.cast_op = CastOpMaybeWrap;
eval_const_expr_implicit_cast(g, node, expr_node);
return wanted_type; return wanted_type;
} else { } else {
return g->builtin_types.entry_invalid;
}
}
}
// explicit cast from number literal to another type
if (actual_type->id == TypeTableEntryIdNumLitFloat ||
actual_type->id == TypeTableEntryIdNumLitInt)
{
if (num_lit_fits_in_other_type(g, expr_node, wanted_type)) {
node->data.fn_call_expr.cast_op = CastOpNoop;
eval_const_expr_implicit_cast(g, node, expr_node);
return wanted_type;
} else {
return g->builtin_types.entry_invalid;
}
}
add_node_error(g, node, add_node_error(g, node,
buf_sprintf("invalid cast from type '%s' to '%s'", buf_sprintf("invalid cast from type '%s' to '%s'",
buf_ptr(&actual_type->name), buf_ptr(&actual_type->name),
buf_ptr(&wanted_type->name))); buf_ptr(&wanted_type->name)));
return g->builtin_types.entry_invalid; return g->builtin_types.entry_invalid;
} }
}
static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, static TypeTableEntry *analyze_builtin_fn_call_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node) TypeTableEntry *expected_type, AstNode *node)
@ -3281,38 +3401,13 @@ static TypeTableEntry *analyze_return_expr(CodeGen *g, ImportTableEntry *import,
actual_return_type = g->builtin_types.entry_invalid; actual_return_type = g->builtin_types.entry_invalid;
} }
resolve_type_compatibility(g, context, node, expected_return_type, actual_return_type); resolve_type_compatibility(g, import, context, node, expected_return_type, actual_return_type);
return g->builtin_types.entry_unreachable; return g->builtin_types.entry_unreachable;
} }
static bool type_has_codegen_value(TypeTableEntryId id) { // When you call analyze_expression, the node you pass might no longer be the child node
switch (id) { // you thought it was due to implicit casting rewriting the AST.
case TypeTableEntryIdInvalid:
case TypeTableEntryIdMetaType:
case TypeTableEntryIdVoid:
case TypeTableEntryIdUnreachable:
return false;
// TODO make num lits return false when we make implicit casts insert ast nodes
case TypeTableEntryIdNumLitFloat:
case TypeTableEntryIdNumLitInt:
case TypeTableEntryIdBool:
case TypeTableEntryIdInt:
case TypeTableEntryIdFloat:
case TypeTableEntryIdPointer:
case TypeTableEntryIdArray:
case TypeTableEntryIdStruct:
case TypeTableEntryIdMaybe:
case TypeTableEntryIdError:
case TypeTableEntryIdEnum:
case TypeTableEntryIdFn:
return true;
}
zig_unreachable();
}
static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, static TypeTableEntry *analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
TypeTableEntry *expected_type, AstNode *node) TypeTableEntry *expected_type, AstNode *node)
{ {
@ -3494,39 +3589,19 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
zig_unreachable(); zig_unreachable();
} }
assert(return_type); assert(return_type);
resolve_type_compatibility(g, context, node, expected_type, return_type); // resolve_type_compatibility might do implicit cast which means node is now a child
// of the actual node that we want to return the type of.
//AstNode **field = node->parent_field;
TypeTableEntry *resolved_type = resolve_type_compatibility(g, import, context, node,
expected_type, return_type);
Expr *expr = get_resolved_expr(node); Expr *expr = get_resolved_expr(node);
if (!expr->resolved_type) { expr->type_entry = return_type;
expr->resolved_type = return_type;
}
expr->type_entry = expr->resolved_type;
expr->block_context = context; expr->block_context = context;
if (expr->const_val.ok && type_has_codegen_value(expr->resolved_type->id)) { add_global_const_expr(g, expr);
g->global_const_list.append(expr);
}
return resolved_type;
if (expr->type_entry->id == TypeTableEntryIdUnreachable) {
return expr->type_entry;
}
/* TODO delete this code when we make implicit casts insert ast nodes
Cast *cast_node = &expr->implicit_cast;
if (cast_node->after_type) {
eval_const_expr_implicit_cast(g, import, context, node, cast_node, node);
expr->type_entry = cast_node->after_type;
}
*/
Cast *cast_node = &expr->implicit_maybe_cast;
if (cast_node->after_type) {
eval_const_expr_implicit_cast(g, import, context, node, cast_node, node);
expr->type_entry = cast_node->after_type;
}
return expr->type_entry;
} }
static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node) { static void analyze_top_level_fn_def(CodeGen *g, ImportTableEntry *import, AstNode *node) {

View File

@ -71,8 +71,6 @@ static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVa
static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op, static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,
LLVMValueRef target_ref, LLVMValueRef value, LLVMValueRef target_ref, LLVMValueRef value,
TypeTableEntry *op1_type, TypeTableEntry *op2_type); TypeTableEntry *op1_type, TypeTableEntry *op2_type);
static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_val,
TypeTableEntry *actual_type, TypeTableEntry *wanted_type, Cast *cast_node);
static TypeTableEntry *get_type_for_type_node(AstNode *node) { static TypeTableEntry *get_type_for_type_node(AstNode *node) {
Expr *expr = get_resolved_expr(node); Expr *expr = get_resolved_expr(node);
@ -111,17 +109,7 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) {
} }
static TypeTableEntry *get_expr_type(AstNode *node) { static TypeTableEntry *get_expr_type(AstNode *node) {
Expr *expr = get_resolved_expr(node); return get_resolved_expr(node)->type_entry;
if (expr->implicit_maybe_cast.after_type) {
return expr->implicit_maybe_cast.after_type;
}
if (expr->implicit_cast.after_type) {
return expr->implicit_cast.after_type;
}
if (expr->resolved_type) {
return expr->resolved_type;
}
return expr->type_entry;
} }
static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) { static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_node) {
@ -305,18 +293,84 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
TypeTableEntry *actual_type = get_expr_type(expr_node); TypeTableEntry *actual_type = get_expr_type(expr_node);
TypeTableEntry *wanted_type = get_expr_type(node); TypeTableEntry *wanted_type = get_expr_type(node);
Cast *cast_node = &node->data.fn_call_expr.cast; AstNodeFnCallExpr *cast_expr = &node->data.fn_call_expr;
return gen_bare_cast(g, node, expr_val, actual_type, wanted_type, cast_node); switch (cast_expr->cast_op) {
case CastOpNoCast:
zig_unreachable();
case CastOpNoop:
return expr_val;
case CastOpMaybeWrap:
{
assert(cast_expr->tmp_ptr);
assert(wanted_type->id == TypeTableEntryIdMaybe);
assert(actual_type);
add_debug_source_node(g, node);
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 0, "");
gen_assign_raw(g, node, BinOpTypeAssign,
val_ptr, expr_val, wanted_type->data.maybe.child_type, actual_type);
add_debug_source_node(g, node);
LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 1, "");
LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
return cast_expr->tmp_ptr;
} }
case CastOpPtrToInt:
add_debug_source_node(g, node);
return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
case CastOpPointerReinterpret:
add_debug_source_node(g, node);
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
case CastOpIntWidenOrShorten:
if (actual_type->size_in_bits == wanted_type->size_in_bits) {
return expr_val;
} else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
if (actual_type->data.integral.is_signed) {
add_debug_source_node(g, node);
return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
} else {
add_debug_source_node(g, node);
return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
}
} else {
assert(actual_type->size_in_bits > wanted_type->size_in_bits);
add_debug_source_node(g, node);
return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
}
case CastOpToUnknownSizeArray:
{
assert(cast_expr->tmp_ptr);
assert(wanted_type->id == TypeTableEntryIdStruct);
assert(wanted_type->data.structure.is_unknown_size_array);
TypeTableEntry *pointer_type = wanted_type->data.structure.fields[0].type_entry;
add_debug_source_node(g, node);
LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 0, "");
LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, "");
LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr);
LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_expr->tmp_ptr, 1, "");
LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_isize->type_ref,
actual_type->data.array.len, false);
LLVMBuildStore(g->builder, len_val, len_ptr);
return cast_expr->tmp_ptr;
}
}
zig_unreachable();
}
static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) { static LLVMValueRef gen_fn_call_expr(CodeGen *g, AstNode *node) {
assert(node->type == NodeTypeFnCallExpr); assert(node->type == NodeTypeFnCallExpr);
if (node->data.fn_call_expr.is_builtin) { if (node->data.fn_call_expr.is_builtin) {
return gen_builtin_fn_call_expr(g, node); return gen_builtin_fn_call_expr(g, node);
} else if (node->data.fn_call_expr.cast.after_type) { } else if (node->data.fn_call_expr.cast_op != CastOpNoCast) {
return gen_cast_expr(g, node); return gen_cast_expr(g, node);
} }
@ -752,74 +806,6 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
zig_unreachable(); zig_unreachable();
} }
static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_val,
TypeTableEntry *actual_type, TypeTableEntry *wanted_type, Cast *cast_node)
{
switch (cast_node->op) {
case CastOpNothing:
return expr_val;
case CastOpMaybeWrap:
{
assert(cast_node->ptr);
assert(wanted_type->id == TypeTableEntryIdMaybe);
assert(actual_type);
add_debug_source_node(g, node);
LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 0, "");
gen_assign_raw(g, node, BinOpTypeAssign,
val_ptr, expr_val, wanted_type->data.maybe.child_type, actual_type);
add_debug_source_node(g, node);
LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 1, "");
LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
return cast_node->ptr;
}
case CastOpPtrToInt:
add_debug_source_node(g, node);
return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
case CastOpPointerReinterpret:
add_debug_source_node(g, node);
return LLVMBuildBitCast(g->builder, expr_val, wanted_type->type_ref, "");
case CastOpIntWidenOrShorten:
if (actual_type->size_in_bits == wanted_type->size_in_bits) {
return expr_val;
} else if (actual_type->size_in_bits < wanted_type->size_in_bits) {
if (actual_type->data.integral.is_signed) {
add_debug_source_node(g, node);
return LLVMBuildSExt(g->builder, expr_val, wanted_type->type_ref, "");
} else {
add_debug_source_node(g, node);
return LLVMBuildZExt(g->builder, expr_val, wanted_type->type_ref, "");
}
} else {
assert(actual_type->size_in_bits > wanted_type->size_in_bits);
add_debug_source_node(g, node);
return LLVMBuildTrunc(g->builder, expr_val, wanted_type->type_ref, "");
}
case CastOpToUnknownSizeArray:
{
assert(cast_node->ptr);
TypeTableEntry *pointer_type = wanted_type->data.structure.fields[0].type_entry;
add_debug_source_node(g, node);
LLVMValueRef ptr_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 0, "");
LLVMValueRef expr_bitcast = LLVMBuildBitCast(g->builder, expr_val, pointer_type->type_ref, "");
LLVMBuildStore(g->builder, expr_bitcast, ptr_ptr);
LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 1, "");
LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_isize->type_ref,
actual_type->data.array.len, false);
LLVMBuildStore(g->builder, len_val, len_ptr);
return cast_node->ptr;
}
}
zig_unreachable();
}
static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node, static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
LLVMValueRef val1, LLVMValueRef val2, LLVMValueRef val1, LLVMValueRef val2,
TypeTableEntry *op1_type, TypeTableEntry *op2_type, TypeTableEntry *op1_type, TypeTableEntry *op2_type,
@ -1970,7 +1956,7 @@ static LLVMValueRef gen_switch_expr(CodeGen *g, AstNode *node) {
return phi; return phi;
} }
static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
Expr *expr = get_resolved_expr(node); Expr *expr = get_resolved_expr(node);
if (expr->const_val.ok) { if (expr->const_val.ok) {
assert(expr->const_llvm_val); assert(expr->const_llvm_val);
@ -2072,33 +2058,6 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
zig_unreachable(); zig_unreachable();
} }
static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
LLVMValueRef val = gen_expr_no_cast(g, node);
if (is_node_void_expr(node)) {
return val;
}
Expr *expr = get_resolved_expr(node);
TypeTableEntry *before_type = expr->type_entry;
if (before_type && before_type->id == TypeTableEntryIdUnreachable) {
return val;
}
Cast *cast_node = &expr->implicit_cast;
if (cast_node->after_type) {
val = gen_bare_cast(g, node, val, before_type, cast_node->after_type, cast_node);
before_type = cast_node->after_type;
}
cast_node = &expr->implicit_maybe_cast;
if (cast_node->after_type) {
val = gen_bare_cast(g, node, val, before_type, cast_node->after_type, cast_node);
}
return val;
}
static void build_label_blocks(CodeGen *g, AstNode *block_node) { static void build_label_blocks(CodeGen *g, AstNode *block_node) {
assert(block_node->type == NodeTypeBlock); assert(block_node->type == NodeTypeBlock);
for (int i = 0; i < block_node->data.block.statements.length; i += 1) { for (int i = 0; i < block_node->data.block.statements.length; i += 1) {
@ -2180,14 +2139,7 @@ static void gen_const_globals(CodeGen *g) {
Expr *expr = g->global_const_list.at(i); Expr *expr = g->global_const_list.at(i);
ConstExprValue *const_val = &expr->const_val; ConstExprValue *const_val = &expr->const_val;
assert(const_val->ok); assert(const_val->ok);
TypeTableEntry *type_entry = expr->resolved_type; TypeTableEntry *type_entry = expr->type_entry;
// TODO delete this if when we make implicit casts insert ast nodes
if (type_entry->id == TypeTableEntryIdNumLitFloat ||
type_entry->id == TypeTableEntryIdNumLitInt)
{
continue;
}
if (handle_is_ptr(type_entry)) { if (handle_is_ptr(type_entry)) {
LLVMValueRef global_value = LLVMAddGlobal(g->module, type_entry->type_ref, ""); LLVMValueRef global_value = LLVMAddGlobal(g->module, type_entry->type_ref, "");
@ -2330,10 +2282,12 @@ static void do_code_gen(CodeGen *g) {
} }
// allocate structs which are the result of casts // allocate structs which are the result of casts
for (int cea_i = 0; cea_i < block_context->cast_expr_alloca_list.length; cea_i += 1) { for (int cea_i = 0; cea_i < block_context->cast_alloca_list.length; cea_i += 1) {
Cast *cast_node = block_context->cast_expr_alloca_list.at(cea_i); AstNode *fn_call_node = block_context->cast_alloca_list.at(cea_i);
add_debug_source_node(g, cast_node->source_node); add_debug_source_node(g, fn_call_node);
cast_node->ptr = LLVMBuildAlloca(g->builder, cast_node->after_type->type_ref, ""); Expr *expr = &fn_call_node->data.fn_call_expr.resolved_expr;
fn_call_node->data.fn_call_expr.tmp_ptr = LLVMBuildAlloca(g->builder,
expr->type_entry->type_ref, "");
} }
// allocate structs which are struct value expressions // allocate structs which are struct value expressions

View File

@ -173,6 +173,7 @@ void ast_print(AstNode *node, int indent) {
for (int i = 0; i < indent; i += 1) { for (int i = 0; i < indent; i += 1) {
fprintf(stderr, " "); fprintf(stderr, " ");
} }
assert(node->type == NodeTypeRoot || *node->parent_field == node);
switch (node->type) { switch (node->type) {
case NodeTypeRoot: case NodeTypeRoot:
@ -1008,6 +1009,7 @@ static AstNode *ast_parse_directive(ParseContext *pc, int *token_index) {
*token_index += 1; *token_index += 1;
ast_expect_token(pc, r_paren, TokenIdRParen); ast_expect_token(pc, r_paren, TokenIdRParen);
normalize_parent_ptrs(node);
return node; return node;
} }
@ -1059,6 +1061,7 @@ static AstNode *ast_parse_param_decl(ParseContext *pc, int *token_index) {
node->data.param_decl.type = ast_parse_prefix_op_expr(pc, token_index, true); node->data.param_decl.type = ast_parse_prefix_op_expr(pc, token_index, true);
normalize_parent_ptrs(node);
return node; return node;
} }
@ -1175,6 +1178,7 @@ static AstNode *ast_parse_array_type_expr(ParseContext *pc, int *token_index, bo
node->data.array_type.child_type = ast_parse_prefix_op_expr(pc, token_index, true); node->data.array_type.child_type = ast_parse_prefix_op_expr(pc, token_index, true);
normalize_parent_ptrs(node);
return node; return node;
} }
@ -1358,6 +1362,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc, int *token_index, bool mand
ast_expect_token(pc, rparen_tok, TokenIdRParen); ast_expect_token(pc, rparen_tok, TokenIdRParen);
*token_index += 1; *token_index += 1;
normalize_parent_ptrs(node);
return node; return node;
} }
@ -1416,6 +1421,8 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
ast_eat_token(pc, token_index, TokenIdLParen); ast_eat_token(pc, token_index, TokenIdLParen);
ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params); ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params);
node->data.fn_call_expr.is_builtin = true; node->data.fn_call_expr.is_builtin = true;
normalize_parent_ptrs(node);
return node; return node;
} else if (token->id == TokenIdSymbol) { } else if (token->id == TokenIdSymbol) {
*token_index += 1; *token_index += 1;
@ -1499,6 +1506,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, int *token_index,
ast_buf_from_token(pc, field_name_tok, &field_node->data.struct_val_field.name); ast_buf_from_token(pc, field_name_tok, &field_node->data.struct_val_field.name);
field_node->data.struct_val_field.expr = ast_parse_expression(pc, token_index, true); field_node->data.struct_val_field.expr = ast_parse_expression(pc, token_index, true);
normalize_parent_ptrs(field_node);
node->data.container_init_expr.entries.append(field_node); node->data.container_init_expr.entries.append(field_node);
Token *comma_tok = &pc->tokens->at(*token_index); Token *comma_tok = &pc->tokens->at(*token_index);
@ -1545,6 +1553,7 @@ static AstNode *ast_parse_curly_suffix_expr(ParseContext *pc, int *token_index,
} }
} }
normalize_parent_ptrs(node);
prefix_op_expr = node; prefix_op_expr = node;
} else { } else {
return prefix_op_expr; return prefix_op_expr;
@ -1575,6 +1584,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo
node->data.fn_call_expr.fn_ref_expr = primary_expr; node->data.fn_call_expr.fn_ref_expr = primary_expr;
ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params); ast_parse_fn_call_param_list(pc, token_index, &node->data.fn_call_expr.params);
normalize_parent_ptrs(node);
primary_expr = node; primary_expr = node;
} else if (first_token->id == TokenIdLBracket) { } else if (first_token->id == TokenIdLBracket) {
*token_index += 1; *token_index += 1;
@ -1599,6 +1609,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo
node->data.slice_expr.is_const = true; node->data.slice_expr.is_const = true;
} }
normalize_parent_ptrs(node);
primary_expr = node; primary_expr = node;
} else if (ellipsis_or_r_bracket->id == TokenIdRBracket) { } else if (ellipsis_or_r_bracket->id == TokenIdRBracket) {
*token_index += 1; *token_index += 1;
@ -1607,6 +1618,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo
node->data.array_access_expr.array_ref_expr = primary_expr; node->data.array_access_expr.array_ref_expr = primary_expr;
node->data.array_access_expr.subscript = expr_node; node->data.array_access_expr.subscript = expr_node;
normalize_parent_ptrs(node);
primary_expr = node; primary_expr = node;
} else { } else {
ast_invalid_token_error(pc, first_token); ast_invalid_token_error(pc, first_token);
@ -1620,6 +1632,7 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, int *token_index, boo
node->data.field_access_expr.struct_expr = primary_expr; node->data.field_access_expr.struct_expr = primary_expr;
ast_buf_from_token(pc, name_token, &node->data.field_access_expr.field_name); ast_buf_from_token(pc, name_token, &node->data.field_access_expr.field_name);
normalize_parent_ptrs(node);
primary_expr = node; primary_expr = node;
} else { } else {
return primary_expr; return primary_expr;
@ -1677,6 +1690,8 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo
node->data.prefix_op_expr.primary_expr = prefix_op_expr; node->data.prefix_op_expr.primary_expr = prefix_op_expr;
node->data.prefix_op_expr.prefix_op = prefix_op; node->data.prefix_op_expr.prefix_op = prefix_op;
normalize_parent_ptrs(node);
normalize_parent_ptrs(parent_node);
return parent_node; return parent_node;
} }
@ -1728,6 +1743,7 @@ static AstNode *ast_parse_mult_expr(ParseContext *pc, int *token_index, bool man
node->data.bin_op_expr.bin_op = mult_op; node->data.bin_op_expr.bin_op = mult_op;
node->data.bin_op_expr.op2 = operand_2; node->data.bin_op_expr.op2 = operand_2;
normalize_parent_ptrs(node);
operand_1 = node; operand_1 = node;
} }
} }
@ -1778,6 +1794,7 @@ static AstNode *ast_parse_add_expr(ParseContext *pc, int *token_index, bool mand
node->data.bin_op_expr.bin_op = add_op; node->data.bin_op_expr.bin_op = add_op;
node->data.bin_op_expr.op2 = operand_2; node->data.bin_op_expr.op2 = operand_2;
normalize_parent_ptrs(node);
operand_1 = node; operand_1 = node;
} }
} }
@ -1828,6 +1845,7 @@ static AstNode *ast_parse_bit_shift_expr(ParseContext *pc, int *token_index, boo
node->data.bin_op_expr.bin_op = bit_shift_op; node->data.bin_op_expr.bin_op = bit_shift_op;
node->data.bin_op_expr.op2 = operand_2; node->data.bin_op_expr.op2 = operand_2;
normalize_parent_ptrs(node);
operand_1 = node; operand_1 = node;
} }
} }
@ -1854,6 +1872,7 @@ static AstNode *ast_parse_bin_and_expr(ParseContext *pc, int *token_index, bool
node->data.bin_op_expr.bin_op = BinOpTypeBinAnd; node->data.bin_op_expr.bin_op = BinOpTypeBinAnd;
node->data.bin_op_expr.op2 = operand_2; node->data.bin_op_expr.op2 = operand_2;
normalize_parent_ptrs(node);
operand_1 = node; operand_1 = node;
} }
} }
@ -1879,6 +1898,7 @@ static AstNode *ast_parse_bin_xor_expr(ParseContext *pc, int *token_index, bool
node->data.bin_op_expr.bin_op = BinOpTypeBinXor; node->data.bin_op_expr.bin_op = BinOpTypeBinXor;
node->data.bin_op_expr.op2 = operand_2; node->data.bin_op_expr.op2 = operand_2;
normalize_parent_ptrs(node);
operand_1 = node; operand_1 = node;
} }
} }
@ -1904,6 +1924,7 @@ static AstNode *ast_parse_bin_or_expr(ParseContext *pc, int *token_index, bool m
node->data.bin_op_expr.bin_op = BinOpTypeBinOr; node->data.bin_op_expr.bin_op = BinOpTypeBinOr;
node->data.bin_op_expr.op2 = operand_2; node->data.bin_op_expr.op2 = operand_2;
normalize_parent_ptrs(node);
operand_1 = node; operand_1 = node;
} }
} }
@ -1954,6 +1975,7 @@ static AstNode *ast_parse_comparison_expr(ParseContext *pc, int *token_index, bo
node->data.bin_op_expr.bin_op = cmp_op; node->data.bin_op_expr.bin_op = cmp_op;
node->data.bin_op_expr.op2 = operand_2; node->data.bin_op_expr.op2 = operand_2;
normalize_parent_ptrs(node);
return node; return node;
} }
@ -1978,6 +2000,7 @@ static AstNode *ast_parse_bool_and_expr(ParseContext *pc, int *token_index, bool
node->data.bin_op_expr.bin_op = BinOpTypeBoolAnd; node->data.bin_op_expr.bin_op = BinOpTypeBoolAnd;
node->data.bin_op_expr.op2 = operand_2; node->data.bin_op_expr.op2 = operand_2;
normalize_parent_ptrs(node);
operand_1 = node; operand_1 = node;
} }
} }
@ -2043,6 +2066,8 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
ast_eat_token(pc, token_index, TokenIdRParen); ast_eat_token(pc, token_index, TokenIdRParen);
node->data.if_var_expr.then_block = ast_parse_expression(pc, token_index, true); node->data.if_var_expr.then_block = ast_parse_expression(pc, token_index, true);
node->data.if_var_expr.else_node = ast_parse_else(pc, token_index, false); node->data.if_var_expr.else_node = ast_parse_else(pc, token_index, false);
normalize_parent_ptrs(node);
return node; return node;
} else { } else {
AstNode *node = ast_create_node(pc, NodeTypeIfBoolExpr, if_tok); AstNode *node = ast_create_node(pc, NodeTypeIfBoolExpr, if_tok);
@ -2050,6 +2075,8 @@ static AstNode *ast_parse_if_expr(ParseContext *pc, int *token_index, bool manda
ast_eat_token(pc, token_index, TokenIdRParen); ast_eat_token(pc, token_index, TokenIdRParen);
node->data.if_bool_expr.then_block = ast_parse_expression(pc, token_index, true); node->data.if_bool_expr.then_block = ast_parse_expression(pc, token_index, true);
node->data.if_bool_expr.else_node = ast_parse_else(pc, token_index, false); node->data.if_bool_expr.else_node = ast_parse_else(pc, token_index, false);
normalize_parent_ptrs(node);
return node; return node;
} }
} }
@ -2094,6 +2121,8 @@ static AstNode *ast_parse_return_expr(ParseContext *pc, int *token_index, bool m
AstNode *node = ast_create_node(pc, NodeTypeReturnExpr, token); AstNode *node = ast_create_node(pc, NodeTypeReturnExpr, token);
node->data.return_expr.kind = kind; node->data.return_expr.kind = kind;
node->data.return_expr.expr = ast_parse_expression(pc, token_index, false); node->data.return_expr.expr = ast_parse_expression(pc, token_index, false);
normalize_parent_ptrs(node);
return node; return node;
} }
@ -2156,6 +2185,8 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token
*token_index += 1; *token_index += 1;
if (eq_or_colon->id == TokenIdEq) { if (eq_or_colon->id == TokenIdEq) {
node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true);
normalize_parent_ptrs(node);
return node; return node;
} else if (eq_or_colon->id == TokenIdColon) { } else if (eq_or_colon->id == TokenIdColon) {
node->data.variable_declaration.type = ast_parse_prefix_op_expr(pc, token_index, true); node->data.variable_declaration.type = ast_parse_prefix_op_expr(pc, token_index, true);
@ -2165,6 +2196,8 @@ static AstNode *ast_parse_variable_declaration_expr(ParseContext *pc, int *token
node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true); node->data.variable_declaration.expr = ast_parse_expression(pc, token_index, true);
} }
normalize_parent_ptrs(node);
return node; return node;
} else { } else {
ast_invalid_token_error(pc, eq_or_colon); ast_invalid_token_error(pc, eq_or_colon);
@ -2192,6 +2225,7 @@ static AstNode *ast_parse_bool_or_expr(ParseContext *pc, int *token_index, bool
node->data.bin_op_expr.bin_op = BinOpTypeBoolOr; node->data.bin_op_expr.bin_op = BinOpTypeBoolOr;
node->data.bin_op_expr.op2 = operand_2; node->data.bin_op_expr.op2 = operand_2;
normalize_parent_ptrs(node);
operand_1 = node; operand_1 = node;
} }
} }
@ -2220,7 +2254,7 @@ static AstNode *ast_parse_while_expr(ParseContext *pc, int *token_index, bool ma
node->data.while_expr.body = ast_parse_expression(pc, token_index, true); node->data.while_expr.body = ast_parse_expression(pc, token_index, true);
normalize_parent_ptrs(node);
return node; return node;
} }
@ -2262,6 +2296,8 @@ static AstNode *ast_parse_for_expr(ParseContext *pc, int *token_index, bool mand
ast_eat_token(pc, token_index, TokenIdRParen); ast_eat_token(pc, token_index, TokenIdRParen);
node->data.for_expr.body = ast_parse_expression(pc, token_index, true); node->data.for_expr.body = ast_parse_expression(pc, token_index, true);
normalize_parent_ptrs(node);
return node; return node;
} }
@ -2294,6 +2330,8 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, int *token_index, bool m
if (token->id == TokenIdRBrace) { if (token->id == TokenIdRBrace) {
*token_index += 1; *token_index += 1;
normalize_parent_ptrs(node);
return node; return node;
} }
@ -2313,6 +2351,8 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, int *token_index, bool m
range_node->data.switch_range.start = expr1; range_node->data.switch_range.start = expr1;
range_node->data.switch_range.end = ast_parse_expression(pc, token_index, true); range_node->data.switch_range.end = ast_parse_expression(pc, token_index, true);
normalize_parent_ptrs(range_node);
} else { } else {
prong_node->data.switch_prong.items.append(expr1); prong_node->data.switch_prong.items.append(expr1);
} }
@ -2335,6 +2375,8 @@ static AstNode *ast_parse_switch_expr(ParseContext *pc, int *token_index, bool m
ast_eat_token(pc, token_index, TokenIdFatArrow); ast_eat_token(pc, token_index, TokenIdFatArrow);
prong_node->data.switch_prong.expr = ast_parse_expression(pc, token_index, true); prong_node->data.switch_prong.expr = ast_parse_expression(pc, token_index, true);
ast_eat_token(pc, token_index, TokenIdComma); ast_eat_token(pc, token_index, TokenIdComma);
normalize_parent_ptrs(prong_node);
} }
} }
@ -2430,6 +2472,7 @@ static AstNode *ast_parse_unwrap_maybe_expr(ParseContext *pc, int *token_index,
node->data.bin_op_expr.bin_op = BinOpTypeUnwrapMaybe; node->data.bin_op_expr.bin_op = BinOpTypeUnwrapMaybe;
node->data.bin_op_expr.op2 = rhs; node->data.bin_op_expr.op2 = rhs;
normalize_parent_ptrs(node);
return node; return node;
} }
@ -2453,6 +2496,7 @@ static AstNode *ast_parse_ass_expr(ParseContext *pc, int *token_index, bool mand
node->data.bin_op_expr.bin_op = ass_op; node->data.bin_op_expr.bin_op = ass_op;
node->data.bin_op_expr.op2 = rhs; node->data.bin_op_expr.op2 = rhs;
normalize_parent_ptrs(node);
return node; return node;
} }
@ -2530,6 +2574,7 @@ static AstNode *ast_create_void_expr(ParseContext *pc, Token *token) {
node->data.container_init_expr.type = ast_create_node(pc, NodeTypeSymbol, token); node->data.container_init_expr.type = ast_create_node(pc, NodeTypeSymbol, token);
node->data.container_init_expr.kind = ContainerInitKindArray; node->data.container_init_expr.kind = ContainerInitKindArray;
buf_init_from_str(&node->data.container_init_expr.type->data.symbol_expr.symbol, "void"); buf_init_from_str(&node->data.container_init_expr.type->data.symbol_expr.symbol, "void");
normalize_parent_ptrs(node);
return node; return node;
} }
@ -2581,6 +2626,8 @@ static AstNode *ast_parse_block(ParseContext *pc, int *token_index, bool mandato
last_token = &pc->tokens->at(*token_index); last_token = &pc->tokens->at(*token_index);
if (last_token->id == TokenIdRBrace) { if (last_token->id == TokenIdRBrace) {
*token_index += 1; *token_index += 1;
normalize_parent_ptrs(node);
return node; return node;
} else if (!semicolon_expected) { } else if (!semicolon_expected) {
continue; continue;
@ -2651,6 +2698,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc, int *token_index, bool mand
node->data.fn_proto.return_type = ast_create_void_type_node(pc, next_token); node->data.fn_proto.return_type = ast_create_void_type_node(pc, next_token);
} }
normalize_parent_ptrs(node);
return node; return node;
} }
@ -2667,6 +2715,7 @@ static AstNode *ast_parse_fn_def(ParseContext *pc, int *token_index, bool mandat
ast_eat_token(pc, token_index, TokenIdFatArrow); ast_eat_token(pc, token_index, TokenIdFatArrow);
node->data.fn_def.body = ast_parse_block(pc, token_index, true); node->data.fn_def.body = ast_parse_block(pc, token_index, true);
normalize_parent_ptrs(node);
return node; return node;
} }
@ -2683,6 +2732,7 @@ static AstNode *ast_parse_fn_decl(ParseContext *pc, int *token_index) {
*token_index += 1; *token_index += 1;
ast_expect_token(pc, semicolon, TokenIdSemicolon); ast_expect_token(pc, semicolon, TokenIdSemicolon);
normalize_parent_ptrs(node);
return node; return node;
} }
@ -2725,6 +2775,8 @@ static AstNode *ast_parse_extern_block(ParseContext *pc, int *token_index, bool
pc->directive_list = nullptr; pc->directive_list = nullptr;
*token_index += 1; *token_index += 1;
normalize_parent_ptrs(node);
return node; return node;
} else { } else {
AstNode *child = ast_parse_fn_decl(pc, token_index); AstNode *child = ast_parse_fn_decl(pc, token_index);
@ -2768,6 +2820,7 @@ static AstNode *ast_parse_root_export_decl(ParseContext *pc, int *token_index, b
*token_index += 1; *token_index += 1;
ast_expect_token(pc, semicolon, TokenIdSemicolon); ast_expect_token(pc, semicolon, TokenIdSemicolon);
normalize_parent_ptrs(node);
return node; return node;
} }
@ -2795,6 +2848,7 @@ static AstNode *ast_parse_use(ParseContext *pc, int *token_index) {
node->data.use.directives = pc->directive_list; node->data.use.directives = pc->directive_list;
pc->directive_list = nullptr; pc->directive_list = nullptr;
normalize_parent_ptrs(node);
return node; return node;
} }
@ -2895,12 +2949,13 @@ static AstNode *ast_parse_struct_decl(ParseContext *pc, int *token_index) {
} }
node->data.struct_decl.fields.append(field_node); node->data.struct_decl.fields.append(field_node);
normalize_parent_ptrs(field_node);
} else { } else {
ast_invalid_token_error(pc, token); ast_invalid_token_error(pc, token);
} }
} }
normalize_parent_ptrs(node);
return node; return node;
} }
@ -2948,6 +3003,7 @@ static AstNode *ast_parse_error_value_decl(ParseContext *pc, int *token_index, b
node->data.error_value_decl.visib_mod = visib_mod; node->data.error_value_decl.visib_mod = visib_mod;
ast_buf_from_token(pc, name_tok, &node->data.error_value_decl.name); ast_buf_from_token(pc, name_tok, &node->data.error_value_decl.name);
normalize_parent_ptrs(node);
return node; return node;
} }
@ -3026,6 +3082,7 @@ static AstNode *ast_parse_root(ParseContext *pc, int *token_index) {
ast_invalid_token_error(pc, &pc->tokens->at(*token_index)); ast_invalid_token_error(pc, &pc->tokens->at(*token_index));
} }
normalize_parent_ptrs(node);
return node; return node;
} }
@ -3042,3 +3099,184 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner,
pc.root = ast_parse_root(&pc, &token_index); pc.root = ast_parse_root(&pc, &token_index);
return pc.root; return pc.root;
} }
static void set_field(AstNode **field) {
if (*field) {
(*field)->parent_field = field;
}
}
static void set_list_fields(ZigList<AstNode*> *list) {
for (int i = 0; i < list->length; i += 1) {
set_field(&list->at(i));
}
}
void normalize_parent_ptrs(AstNode *node) {
switch (node->type) {
case NodeTypeRoot:
set_list_fields(&node->data.root.top_level_decls);
break;
case NodeTypeRootExportDecl:
set_list_fields(node->data.root_export_decl.directives);
break;
case NodeTypeFnProto:
set_field(&node->data.fn_proto.return_type);
set_list_fields(node->data.fn_proto.directives);
set_list_fields(&node->data.fn_proto.params);
break;
case NodeTypeFnDef:
set_field(&node->data.fn_def.fn_proto);
set_field(&node->data.fn_def.body);
break;
case NodeTypeFnDecl:
set_field(&node->data.fn_decl.fn_proto);
break;
case NodeTypeParamDecl:
set_field(&node->data.param_decl.type);
break;
case NodeTypeBlock:
set_list_fields(&node->data.block.statements);
break;
case NodeTypeExternBlock:
set_list_fields(node->data.extern_block.directives);
set_list_fields(&node->data.extern_block.fn_decls);
break;
case NodeTypeDirective:
// none
break;
case NodeTypeReturnExpr:
set_field(&node->data.return_expr.expr);
break;
case NodeTypeVariableDeclaration:
set_field(&node->data.variable_declaration.type);
set_field(&node->data.variable_declaration.expr);
break;
case NodeTypeErrorValueDecl:
// none
break;
case NodeTypeBinOpExpr:
set_field(&node->data.bin_op_expr.op1);
set_field(&node->data.bin_op_expr.op2);
break;
case NodeTypeNumberLiteral:
// none
break;
case NodeTypeStringLiteral:
// none
break;
case NodeTypeCharLiteral:
// none
break;
case NodeTypeErrorLiteral:
// none
break;
case NodeTypeSymbol:
// none
break;
case NodeTypePrefixOpExpr:
set_field(&node->data.prefix_op_expr.primary_expr);
break;
case NodeTypeFnCallExpr:
set_field(&node->data.fn_call_expr.fn_ref_expr);
set_list_fields(&node->data.fn_call_expr.params);
break;
case NodeTypeArrayAccessExpr:
set_field(&node->data.array_access_expr.array_ref_expr);
set_field(&node->data.array_access_expr.subscript);
break;
case NodeTypeSliceExpr:
set_field(&node->data.slice_expr.array_ref_expr);
set_field(&node->data.slice_expr.start);
set_field(&node->data.slice_expr.end);
break;
case NodeTypeFieldAccessExpr:
set_field(&node->data.field_access_expr.struct_expr);
break;
case NodeTypeUse:
set_list_fields(node->data.use.directives);
break;
case NodeTypeBoolLiteral:
// none
break;
case NodeTypeNullLiteral:
// none
break;
case NodeTypeIfBoolExpr:
set_field(&node->data.if_bool_expr.condition);
set_field(&node->data.if_bool_expr.then_block);
set_field(&node->data.if_bool_expr.else_node);
break;
case NodeTypeIfVarExpr:
set_field(&node->data.if_var_expr.var_decl.type);
set_field(&node->data.if_var_expr.var_decl.expr);
set_field(&node->data.if_var_expr.then_block);
set_field(&node->data.if_var_expr.else_node);
break;
case NodeTypeWhileExpr:
set_field(&node->data.while_expr.condition);
set_field(&node->data.while_expr.body);
break;
case NodeTypeForExpr:
set_field(&node->data.for_expr.elem_node);
set_field(&node->data.for_expr.array_expr);
set_field(&node->data.for_expr.index_node);
set_field(&node->data.for_expr.body);
break;
case NodeTypeSwitchExpr:
set_field(&node->data.switch_expr.expr);
set_list_fields(&node->data.switch_expr.prongs);
break;
case NodeTypeSwitchProng:
set_list_fields(&node->data.switch_prong.items);
set_field(&node->data.switch_prong.var_symbol);
set_field(&node->data.switch_prong.expr);
break;
case NodeTypeSwitchRange:
set_field(&node->data.switch_range.start);
set_field(&node->data.switch_range.end);
break;
case NodeTypeLabel:
// none
break;
case NodeTypeGoto:
// none
break;
case NodeTypeBreak:
// none
break;
case NodeTypeContinue:
// none
break;
case NodeTypeAsmExpr:
for (int i = 0; i < node->data.asm_expr.input_list.length; i += 1) {
AsmInput *asm_input = node->data.asm_expr.input_list.at(i);
set_field(&asm_input->expr);
}
for (int i = 0; i < node->data.asm_expr.output_list.length; i += 1) {
AsmOutput *asm_output = node->data.asm_expr.output_list.at(i);
set_field(&asm_output->return_type);
}
break;
case NodeTypeStructDecl:
set_list_fields(&node->data.struct_decl.fields);
set_list_fields(&node->data.struct_decl.fns);
set_list_fields(node->data.struct_decl.directives);
break;
case NodeTypeStructField:
set_field(&node->data.struct_field.type);
set_list_fields(node->data.struct_field.directives);
break;
case NodeTypeContainerInitExpr:
set_field(&node->data.container_init_expr.type);
set_list_fields(&node->data.container_init_expr.entries);
break;
case NodeTypeStructValueField:
set_field(&node->data.struct_val_field.expr);
break;
case NodeTypeArrayType:
set_field(&node->data.array_type.size);
set_field(&node->data.array_type.child_type);
break;
}
}

View File

@ -24,4 +24,6 @@ const char *node_type_str(NodeType node_type);
void ast_print(AstNode *node, int indent); void ast_print(AstNode *node, int indent);
void normalize_parent_ptrs(AstNode *node);
#endif #endif

View File

@ -1317,7 +1317,7 @@ fn f() i32 => {
const a = c"a"; const a = c"a";
a a
} }
)SOURCE", 1, ".tmp_source.zig:2:15: error: expected type 'i32', got '&const u8'"); )SOURCE", 1, ".tmp_source.zig:4:5: error: expected type 'i32', got '&const u8'");
add_compile_fail_case("if condition is bool, not int", R"SOURCE( add_compile_fail_case("if condition is bool, not int", R"SOURCE(
fn f() => { fn f() => {