number literal rework
parent
5e212db29c
commit
32e2196257
|
@ -25,6 +25,7 @@ include_directories(
|
|||
)
|
||||
|
||||
set(ZIG_SOURCES
|
||||
"${CMAKE_SOURCE_DIR}/src/bignum.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/tokenizer.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/parser.cpp"
|
||||
"${CMAKE_SOURCE_DIR}/src/analyze.cpp"
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "zig_llvm.hpp"
|
||||
#include "hash_map.hpp"
|
||||
#include "errmsg.hpp"
|
||||
#include "bignum.hpp"
|
||||
|
||||
struct AstNode;
|
||||
struct ImportTableEntry;
|
||||
|
@ -49,15 +50,6 @@ enum CastOp {
|
|||
CastOpPointerReinterpret,
|
||||
};
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
struct ConstEnumValue {
|
||||
uint64_t tag;
|
||||
ConstExprValue *payload;
|
||||
|
@ -68,9 +60,7 @@ struct ConstExprValue {
|
|||
bool depends_on_compile_var;
|
||||
|
||||
union {
|
||||
uint64_t x_uint;
|
||||
int64_t x_int;
|
||||
double x_float;
|
||||
BigNum x_bignum;
|
||||
bool x_bool;
|
||||
FnTableEntry *x_fn;
|
||||
TypeTableEntry *x_type;
|
||||
|
@ -79,8 +69,19 @@ struct ConstExprValue {
|
|||
} 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 {
|
||||
TypeTableEntry *type_entry;
|
||||
TypeTableEntry *resolved_type;
|
||||
// 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.
|
||||
BlockContext *block_context;
|
||||
|
@ -92,10 +93,6 @@ struct Expr {
|
|||
ConstExprValue const_val;
|
||||
};
|
||||
|
||||
struct NumLitCodeGen {
|
||||
TypeTableEntry *resolved_type;
|
||||
};
|
||||
|
||||
struct StructValExprCodeGen {
|
||||
TypeTableEntry *type_entry;
|
||||
LLVMValueRef ptr;
|
||||
|
@ -315,7 +312,6 @@ struct AstNodeFnCallExpr {
|
|||
// populated by semantic analyzer:
|
||||
BuiltinFnEntry *builtin_fn;
|
||||
Expr resolved_expr;
|
||||
NumLitCodeGen resolved_num_lit;
|
||||
Cast cast;
|
||||
FnTableEntry *fn_entry;
|
||||
};
|
||||
|
@ -550,26 +546,15 @@ struct AstNodeCharLiteral {
|
|||
};
|
||||
|
||||
enum NumLit {
|
||||
NumLitF32,
|
||||
NumLitF64,
|
||||
NumLitF128,
|
||||
NumLitU8,
|
||||
NumLitU16,
|
||||
NumLitU32,
|
||||
NumLitU64,
|
||||
NumLitI8,
|
||||
NumLitI16,
|
||||
NumLitI32,
|
||||
NumLitI64,
|
||||
|
||||
NumLitCount
|
||||
NumLitFloat,
|
||||
NumLitUInt,
|
||||
};
|
||||
|
||||
struct AstNodeNumberLiteral {
|
||||
NumLit kind;
|
||||
|
||||
// overflow is true if when parsing the number, we discovered it would not
|
||||
// fit without losing data in a uint64_t, int64_t, or double
|
||||
// fit without losing data in a uint64_t or double
|
||||
bool overflow;
|
||||
|
||||
union {
|
||||
|
@ -578,7 +563,6 @@ struct AstNodeNumberLiteral {
|
|||
} data;
|
||||
|
||||
// populated by semantic analyzer
|
||||
NumLitCodeGen codegen;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
|
@ -586,7 +570,6 @@ struct AstNodeErrorLiteral {
|
|||
Buf symbol;
|
||||
|
||||
// populated by semantic analyzer
|
||||
NumLitCodeGen codegen;
|
||||
Expr resolved_expr;
|
||||
};
|
||||
|
||||
|
@ -758,10 +741,6 @@ struct TypeTableEntryStruct {
|
|||
bool reported_infinite_err;
|
||||
};
|
||||
|
||||
struct TypeTableEntryNumLit {
|
||||
NumLit kind;
|
||||
};
|
||||
|
||||
struct TypeTableEntryMaybe {
|
||||
TypeTableEntry *child_type;
|
||||
};
|
||||
|
@ -808,7 +787,8 @@ enum TypeTableEntryId {
|
|||
TypeTableEntryIdPointer,
|
||||
TypeTableEntryIdArray,
|
||||
TypeTableEntryIdStruct,
|
||||
TypeTableEntryIdNumberLiteral,
|
||||
TypeTableEntryIdNumLitFloat,
|
||||
TypeTableEntryIdNumLitInt,
|
||||
TypeTableEntryIdMaybe,
|
||||
TypeTableEntryIdError,
|
||||
TypeTableEntryIdEnum,
|
||||
|
@ -830,7 +810,6 @@ struct TypeTableEntry {
|
|||
TypeTableEntryInt integral;
|
||||
TypeTableEntryArray array;
|
||||
TypeTableEntryStruct structure;
|
||||
TypeTableEntryNumLit num_lit;
|
||||
TypeTableEntryMaybe maybe;
|
||||
TypeTableEntryError error;
|
||||
TypeTableEntryEnum enumeration;
|
||||
|
@ -951,10 +930,10 @@ struct CodeGen {
|
|||
TypeTableEntry *entry_unreachable;
|
||||
TypeTableEntry *entry_type;
|
||||
TypeTableEntry *entry_invalid;
|
||||
TypeTableEntry *entry_num_lit_int;
|
||||
TypeTableEntry *entry_num_lit_float;
|
||||
} builtin_types;
|
||||
|
||||
TypeTableEntry *num_lit_types[NumLitCount];
|
||||
|
||||
LLVMTargetDataRef target_data_ref;
|
||||
unsigned pointer_size_bytes;
|
||||
bool is_static;
|
||||
|
|
666
src/analyze.cpp
666
src/analyze.cpp
|
@ -103,7 +103,8 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
|
|||
case TypeTableEntryIdFloat:
|
||||
case TypeTableEntryIdPointer:
|
||||
case TypeTableEntryIdArray:
|
||||
case TypeTableEntryIdNumberLiteral:
|
||||
case TypeTableEntryIdNumLitFloat:
|
||||
case TypeTableEntryIdNumLitInt:
|
||||
case TypeTableEntryIdMaybe:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdError:
|
||||
|
@ -121,24 +122,20 @@ TypeTableEntry *new_type_table_entry(TypeTableEntryId id) {
|
|||
return entry;
|
||||
}
|
||||
|
||||
static NumLit get_number_literal_kind_unsigned(uint64_t x) {
|
||||
static int bits_needed_for_unsigned(uint64_t x) {
|
||||
if (x <= UINT8_MAX) {
|
||||
return NumLitU8;
|
||||
return 8;
|
||||
} else if (x <= UINT16_MAX) {
|
||||
return NumLitU16;
|
||||
return 16;
|
||||
} else if (x <= UINT32_MAX) {
|
||||
return NumLitU32;
|
||||
return 32;
|
||||
} else {
|
||||
return NumLitU64;
|
||||
return 64;
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *get_number_literal_type_unsigned(CodeGen *g, uint64_t x) {
|
||||
return g->num_lit_types[get_number_literal_kind_unsigned(x)];
|
||||
}
|
||||
|
||||
static TypeTableEntry *get_int_type_unsigned(CodeGen *g, uint64_t x) {
|
||||
return get_int_type(g, false, num_lit_bit_count(get_number_literal_kind_unsigned(x)));
|
||||
static TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
|
||||
return get_int_type(g, false, bits_needed_for_unsigned(x));
|
||||
}
|
||||
|
||||
TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool is_const) {
|
||||
|
@ -660,10 +657,9 @@ static void resolve_enum_type(CodeGen *g, ImportTableEntry *import, TypeTableEnt
|
|||
if (!enum_type->data.enumeration.is_invalid) {
|
||||
enum_type->data.enumeration.gen_field_count = gen_field_index;
|
||||
|
||||
uint64_t tag_size_in_bits = num_lit_bit_count(get_number_literal_kind_unsigned(field_count));
|
||||
enum_type->align_in_bits = tag_size_in_bits;
|
||||
enum_type->size_in_bits = tag_size_in_bits + biggest_union_member_size_in_bits;
|
||||
TypeTableEntry *tag_type_entry = get_int_type_unsigned(g, field_count);
|
||||
TypeTableEntry *tag_type_entry = get_smallest_unsigned_int_type(g, field_count);
|
||||
enum_type->align_in_bits = tag_type_entry->size_in_bits;
|
||||
enum_type->size_in_bits = tag_type_entry->size_in_bits + biggest_union_member_size_in_bits;
|
||||
enum_type->data.enumeration.tag_type = tag_type_entry;
|
||||
|
||||
if (biggest_union_member) {
|
||||
|
@ -1048,136 +1044,105 @@ static TypeTableEntry *get_return_type(BlockContext *context) {
|
|||
return unwrapped_node_type(return_type_node);
|
||||
}
|
||||
|
||||
static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type, TypeTableEntry *other_type) {
|
||||
NumLit num_lit = literal_type->data.num_lit.kind;
|
||||
uint64_t lit_size_in_bits = num_lit_bit_count(num_lit);
|
||||
|
||||
switch (other_type->id) {
|
||||
case TypeTableEntryIdInvalid:
|
||||
case TypeTableEntryIdNumberLiteral:
|
||||
zig_unreachable();
|
||||
case TypeTableEntryIdVoid:
|
||||
case TypeTableEntryIdBool:
|
||||
case TypeTableEntryIdUnreachable:
|
||||
case TypeTableEntryIdPointer:
|
||||
case TypeTableEntryIdArray:
|
||||
case TypeTableEntryIdStruct:
|
||||
case TypeTableEntryIdEnum:
|
||||
case TypeTableEntryIdMetaType:
|
||||
case TypeTableEntryIdFn:
|
||||
case TypeTableEntryIdError:
|
||||
return false;
|
||||
case TypeTableEntryIdInt:
|
||||
if (is_num_lit_unsigned(num_lit)) {
|
||||
return lit_size_in_bits <= other_type->size_in_bits;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case TypeTableEntryIdFloat:
|
||||
if (is_num_lit_float(num_lit)) {
|
||||
return lit_size_in_bits <= other_type->size_in_bits;
|
||||
} else if (other_type->size_in_bits == 32) {
|
||||
return lit_size_in_bits < 24;
|
||||
} else if (other_type->size_in_bits == 64) {
|
||||
return lit_size_in_bits < 53;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
case TypeTableEntryIdMaybe:
|
||||
return false;
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static TypeTableEntry *resolve_rhs_number_literal(CodeGen *g, AstNode *non_literal_node,
|
||||
TypeTableEntry *non_literal_type, AstNode *literal_node, TypeTableEntry *literal_type)
|
||||
{
|
||||
NumLitCodeGen *num_lit_codegen = get_resolved_num_lit(literal_node);
|
||||
|
||||
if (non_literal_type && num_lit_fits_in_other_type(g, literal_type, non_literal_type)) {
|
||||
assert(!num_lit_codegen->resolved_type);
|
||||
num_lit_codegen->resolved_type = non_literal_type;
|
||||
return non_literal_type;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry * resolve_number_literals(CodeGen *g, AstNode *node1, AstNode *node2,
|
||||
TypeTableEntry *type1, TypeTableEntry *type2)
|
||||
{
|
||||
if (type1->id == TypeTableEntryIdNumberLiteral &&
|
||||
type2->id == TypeTableEntryIdNumberLiteral)
|
||||
static bool num_lit_fits_in_other_type(CodeGen *g, AstNode *literal_node, TypeTableEntry *other_type) {
|
||||
Expr *expr = get_resolved_expr(literal_node);
|
||||
ConstExprValue *const_val = &expr->const_val;
|
||||
assert(const_val->ok);
|
||||
if (other_type->id == TypeTableEntryIdFloat) {
|
||||
expr->resolved_type = other_type;
|
||||
return true;
|
||||
} else if (other_type->id == TypeTableEntryIdInt &&
|
||||
const_val->data.x_bignum.kind == BigNumKindInt)
|
||||
{
|
||||
NumLitCodeGen *codegen_num_lit_1 = get_resolved_num_lit(node1);
|
||||
NumLitCodeGen *codegen_num_lit_2 = get_resolved_num_lit(node2);
|
||||
|
||||
assert(!codegen_num_lit_1->resolved_type);
|
||||
assert(!codegen_num_lit_2->resolved_type);
|
||||
|
||||
if (is_num_lit_float(type1->data.num_lit.kind) &&
|
||||
is_num_lit_float(type2->data.num_lit.kind))
|
||||
if (bignum_fits_in_bits(&const_val->data.x_bignum, other_type->size_in_bits,
|
||||
other_type->data.integral.is_signed))
|
||||
{
|
||||
codegen_num_lit_1->resolved_type = g->builtin_types.entry_f64;
|
||||
codegen_num_lit_2->resolved_type = g->builtin_types.entry_f64;
|
||||
return g->builtin_types.entry_f64;
|
||||
} else if (is_num_lit_unsigned(type1->data.num_lit.kind) &&
|
||||
is_num_lit_unsigned(type2->data.num_lit.kind))
|
||||
{
|
||||
codegen_num_lit_1->resolved_type = g->builtin_types.entry_u64;
|
||||
codegen_num_lit_2->resolved_type = g->builtin_types.entry_u64;
|
||||
return g->builtin_types.entry_u64;
|
||||
} else {
|
||||
return nullptr;
|
||||
expr->resolved_type = other_type;
|
||||
return true;
|
||||
}
|
||||
} else if (type1->id == TypeTableEntryIdNumberLiteral) {
|
||||
return resolve_rhs_number_literal(g, node2, type2, node1, type1);
|
||||
} else {
|
||||
assert(type2->id == TypeTableEntryIdNumberLiteral);
|
||||
return resolve_rhs_number_literal(g, node1, type1, node2, type2);
|
||||
} else if (other_type->id == TypeTableEntryIdNumLitFloat ||
|
||||
other_type->id == TypeTableEntryIdNumLitInt)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
add_node_error(g, literal_node,
|
||||
buf_sprintf("value %s cannot be represented in type '%s'",
|
||||
buf_ptr(bignum_to_buf(&const_val->data.x_bignum)),
|
||||
buf_ptr(&other_type->name)));
|
||||
return false;
|
||||
}
|
||||
|
||||
static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *node,
|
||||
TypeTableEntry *type1, TypeTableEntry *type2, AstNode *node1, AstNode *node2)
|
||||
static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *parent_source_node,
|
||||
AstNode **child_nodes, TypeTableEntry **child_types, int child_count)
|
||||
{
|
||||
if (type1->id == TypeTableEntryIdInvalid ||
|
||||
type2->id == TypeTableEntryIdInvalid)
|
||||
{
|
||||
return type1;
|
||||
} else if (type1->id == TypeTableEntryIdUnreachable) {
|
||||
return type2;
|
||||
} else if (type2->id == TypeTableEntryIdUnreachable) {
|
||||
return type1;
|
||||
} else if (type1->id == TypeTableEntryIdInt &&
|
||||
type2->id == TypeTableEntryIdInt &&
|
||||
type1->data.integral.is_signed == type2->data.integral.is_signed)
|
||||
{
|
||||
return (type1->size_in_bits > type2->size_in_bits) ? type1 : type2;
|
||||
} else if (type1->id == TypeTableEntryIdFloat &&
|
||||
type2->id == TypeTableEntryIdFloat)
|
||||
{
|
||||
return (type1->size_in_bits > type2->size_in_bits) ? type1 : type2;
|
||||
} else if (type1->id == TypeTableEntryIdArray &&
|
||||
type2->id == TypeTableEntryIdArray &&
|
||||
type1 == type2)
|
||||
{
|
||||
return type1;
|
||||
} else if (type1->id == TypeTableEntryIdNumberLiteral ||
|
||||
type2->id == TypeTableEntryIdNumberLiteral)
|
||||
{
|
||||
TypeTableEntry *resolved_type = resolve_number_literals(g, node1, node2, type1, type2);
|
||||
if (resolved_type)
|
||||
return resolved_type;
|
||||
} else if (type1 == type2) {
|
||||
return type1;
|
||||
TypeTableEntry *prev_type = child_types[0];
|
||||
AstNode *prev_node = child_nodes[0];
|
||||
if (prev_type->id == TypeTableEntryIdInvalid) {
|
||||
return prev_type;
|
||||
}
|
||||
for (int i = 1; i < child_count; i += 1) {
|
||||
TypeTableEntry *cur_type = child_types[i];
|
||||
AstNode *cur_node = child_nodes[i];
|
||||
if (cur_type->id == TypeTableEntryIdInvalid) {
|
||||
return cur_type;
|
||||
} else if (prev_type->id == TypeTableEntryIdUnreachable) {
|
||||
prev_type = cur_type;
|
||||
prev_node = cur_node;
|
||||
} else if (cur_type->id == TypeTableEntryIdUnreachable) {
|
||||
continue;
|
||||
} else if (prev_type->id == TypeTableEntryIdInt &&
|
||||
cur_type->id == TypeTableEntryIdInt &&
|
||||
prev_type->data.integral.is_signed == cur_type->data.integral.is_signed)
|
||||
{
|
||||
if (cur_type->size_in_bits > prev_type->size_in_bits) {
|
||||
prev_type = cur_type;
|
||||
prev_node = cur_node;
|
||||
}
|
||||
} else if (prev_type->id == TypeTableEntryIdFloat &&
|
||||
cur_type->id == TypeTableEntryIdFloat)
|
||||
{
|
||||
if (cur_type->size_in_bits > prev_type->size_in_bits) {
|
||||
prev_type = cur_type;
|
||||
prev_node = cur_node;
|
||||
}
|
||||
} else if (prev_type->id == TypeTableEntryIdNumLitFloat &&
|
||||
cur_type->id == TypeTableEntryIdNumLitFloat)
|
||||
{
|
||||
continue;
|
||||
} else if (prev_type->id == TypeTableEntryIdNumLitInt &&
|
||||
cur_type->id == TypeTableEntryIdNumLitInt)
|
||||
{
|
||||
continue;
|
||||
} else if (prev_type->id == TypeTableEntryIdNumLitInt ||
|
||||
prev_type->id == TypeTableEntryIdNumLitFloat)
|
||||
{
|
||||
if (num_lit_fits_in_other_type(g, prev_node, cur_type)) {
|
||||
prev_type = cur_type;
|
||||
prev_node = cur_node;
|
||||
continue;
|
||||
} else {
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
} else if (cur_type->id == TypeTableEntryIdNumLitInt ||
|
||||
cur_type->id == TypeTableEntryIdNumLitFloat)
|
||||
{
|
||||
if (num_lit_fits_in_other_type(g, cur_node, prev_type)) {
|
||||
continue;
|
||||
} else {
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
} else if (prev_type == cur_type) {
|
||||
continue;
|
||||
} else {
|
||||
add_node_error(g, parent_source_node,
|
||||
buf_sprintf("incompatible types: '%s' and '%s'",
|
||||
buf_ptr(&prev_type->name), buf_ptr(&cur_type->name)));
|
||||
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("incompatible types: '%s' and '%s'",
|
||||
buf_ptr(&type1->name), buf_ptr(&type2->name)));
|
||||
|
||||
return g->builtin_types.entry_invalid;
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
return prev_type;
|
||||
}
|
||||
|
||||
static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *context, AstNode *node,
|
||||
|
@ -1192,16 +1157,6 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont
|
|||
if (actual_type->id == TypeTableEntryIdUnreachable)
|
||||
return actual_type; // sorry toots; gotta run. good luck with that expected type.
|
||||
|
||||
if (actual_type->id == TypeTableEntryIdNumberLiteral &&
|
||||
num_lit_fits_in_other_type(g, actual_type, expected_type))
|
||||
{
|
||||
NumLitCodeGen *num_lit_code_gen = get_resolved_num_lit(node);
|
||||
assert(!num_lit_code_gen->resolved_type ||
|
||||
num_lit_code_gen->resolved_type == expected_type);
|
||||
num_lit_code_gen->resolved_type = expected_type;
|
||||
return expected_type;
|
||||
}
|
||||
|
||||
if (expected_type->id == TypeTableEntryIdMaybe &&
|
||||
actual_type->id == TypeTableEntryIdMaybe)
|
||||
{
|
||||
|
@ -1283,6 +1238,16 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont
|
|||
return expected_type;
|
||||
}
|
||||
|
||||
if ((actual_type->id == TypeTableEntryIdNumLitFloat ||
|
||||
actual_type->id == TypeTableEntryIdNumLitInt))
|
||||
{
|
||||
if (num_lit_fits_in_other_type(g, node, expected_type)) {
|
||||
return expected_type;
|
||||
} else {
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
add_node_error(g, first_executing_node(node),
|
||||
buf_sprintf("expected type '%s', got '%s'",
|
||||
buf_ptr(&expected_type->name),
|
||||
|
@ -1292,23 +1257,23 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont
|
|||
}
|
||||
|
||||
static TypeTableEntry *resolve_peer_type_compatibility(CodeGen *g, BlockContext *block_context,
|
||||
AstNode *parent_node,
|
||||
AstNode *child1, AstNode *child2,
|
||||
TypeTableEntry *type1, TypeTableEntry *type2)
|
||||
AstNode *parent_source_node,
|
||||
AstNode **child_nodes, TypeTableEntry **child_types, int child_count)
|
||||
{
|
||||
assert(type1);
|
||||
assert(type2);
|
||||
assert(child_count > 0);
|
||||
|
||||
TypeTableEntry *parent_type = determine_peer_type_compatibility(g, parent_node, type1, type2, child1, child2);
|
||||
TypeTableEntry *expected_type = determine_peer_type_compatibility(g, parent_source_node,
|
||||
child_nodes, child_types, child_count);
|
||||
|
||||
if (parent_type->id == TypeTableEntryIdInvalid) {
|
||||
return parent_type;
|
||||
if (expected_type->id == TypeTableEntryIdInvalid) {
|
||||
return expected_type;
|
||||
}
|
||||
|
||||
resolve_type_compatibility(g, block_context, child1, parent_type, type1);
|
||||
resolve_type_compatibility(g, block_context, child2, parent_type, type2);
|
||||
for (int i = 0; i < child_count; i += 1) {
|
||||
resolve_type_compatibility(g, block_context, child_nodes[i], expected_type, child_types[i]);
|
||||
}
|
||||
|
||||
return parent_type;
|
||||
return expected_type;
|
||||
}
|
||||
|
||||
BlockContext *new_block_context(AstNode *node, BlockContext *parent) {
|
||||
|
@ -1732,12 +1697,58 @@ static TypeTableEntry *resolve_expr_const_val_as_unsigned_num_lit(CodeGen *g, As
|
|||
{
|
||||
Expr *expr = get_resolved_expr(node);
|
||||
expr->const_val.ok = true;
|
||||
expr->const_val.data.x_uint = x;
|
||||
TypeTableEntry *num_lit_type = get_number_literal_type_unsigned(g, x);
|
||||
TypeTableEntry *resolved_type = resolve_rhs_number_literal(g, nullptr, expected_type, node, num_lit_type);
|
||||
return resolved_type ? resolved_type : num_lit_type;
|
||||
|
||||
bignum_init_unsigned(&expr->const_val.data.x_bignum, x);
|
||||
|
||||
if (expected_type) {
|
||||
if (expected_type->id == TypeTableEntryIdMaybe) {
|
||||
return g->builtin_types.entry_num_lit_int;
|
||||
} else {
|
||||
num_lit_fits_in_other_type(g, node, expected_type);
|
||||
return expected_type;
|
||||
}
|
||||
} else {
|
||||
return g->builtin_types.entry_num_lit_int;
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *resolve_expr_const_val_as_float_num_lit(CodeGen *g, AstNode *node,
|
||||
TypeTableEntry *expected_type, double x)
|
||||
{
|
||||
Expr *expr = get_resolved_expr(node);
|
||||
expr->const_val.ok = true;
|
||||
|
||||
bignum_init_float(&expr->const_val.data.x_bignum, x);
|
||||
|
||||
if (expected_type) {
|
||||
num_lit_fits_in_other_type(g, node, expected_type);
|
||||
return expected_type;
|
||||
} else {
|
||||
return g->builtin_types.entry_num_lit_float;
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *resolve_expr_const_val_as_bignum_op(CodeGen *g, AstNode *node,
|
||||
bool (*bignum_fn)(BigNum *, BigNum *, BigNum *), AstNode *op1, AstNode *op2,
|
||||
TypeTableEntry *resolved_type)
|
||||
{
|
||||
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
|
||||
ConstExprValue *op1_val = &get_resolved_expr(op1)->const_val;
|
||||
ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val;
|
||||
|
||||
const_val->ok = true;
|
||||
|
||||
if (bignum_fn(&const_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum)) {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("value cannot be represented in any integer type"));
|
||||
} else {
|
||||
num_lit_fits_in_other_type(g, node, resolved_type);
|
||||
}
|
||||
|
||||
return resolved_type;
|
||||
}
|
||||
|
||||
|
||||
static TypeTableEntry *analyze_symbol_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
TypeTableEntry *expected_type, AstNode *node)
|
||||
{
|
||||
|
@ -1918,60 +1929,6 @@ static bool eval_bool_bin_op_bool(bool a, BinOpType bin_op, bool b) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool eval_bool_bin_op_signed(int64_t a, BinOpType bin_op, int64_t b) {
|
||||
if (bin_op == BinOpTypeCmpEq) {
|
||||
return a == b;
|
||||
} else if (bin_op == BinOpTypeCmpNotEq) {
|
||||
return a != b;
|
||||
} else if (bin_op == BinOpTypeCmpLessThan) {
|
||||
return a < b;
|
||||
} else if (bin_op == BinOpTypeCmpGreaterThan) {
|
||||
return a > b;
|
||||
} else if (bin_op == BinOpTypeCmpLessOrEq) {
|
||||
return a <= b;
|
||||
} else if (bin_op == BinOpTypeCmpGreaterOrEq) {
|
||||
return a >= b;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
static bool eval_bool_bin_op_unsigned(uint64_t a, BinOpType bin_op, uint64_t b) {
|
||||
if (bin_op == BinOpTypeCmpEq) {
|
||||
return a == b;
|
||||
} else if (bin_op == BinOpTypeCmpNotEq) {
|
||||
return a != b;
|
||||
} else if (bin_op == BinOpTypeCmpLessThan) {
|
||||
return a < b;
|
||||
} else if (bin_op == BinOpTypeCmpGreaterThan) {
|
||||
return a > b;
|
||||
} else if (bin_op == BinOpTypeCmpLessOrEq) {
|
||||
return a <= b;
|
||||
} else if (bin_op == BinOpTypeCmpGreaterOrEq) {
|
||||
return a >= b;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
static bool eval_bool_bin_op_float(double a, BinOpType bin_op, double b) {
|
||||
if (bin_op == BinOpTypeCmpEq) {
|
||||
return a == b;
|
||||
} else if (bin_op == BinOpTypeCmpNotEq) {
|
||||
return a != b;
|
||||
} else if (bin_op == BinOpTypeCmpLessThan) {
|
||||
return a < b;
|
||||
} else if (bin_op == BinOpTypeCmpGreaterThan) {
|
||||
return a > b;
|
||||
} else if (bin_op == BinOpTypeCmpLessOrEq) {
|
||||
return a <= b;
|
||||
} else if (bin_op == BinOpTypeCmpGreaterOrEq) {
|
||||
return a >= b;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
|
||||
AstNode *node)
|
||||
{
|
||||
|
@ -1983,8 +1940,11 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im
|
|||
TypeTableEntry *op1_type = analyze_expression(g, import, context, nullptr, op1);
|
||||
TypeTableEntry *op2_type = analyze_expression(g, import, context, nullptr, op2);
|
||||
|
||||
AstNode *op_nodes[] = {op1, op2};
|
||||
TypeTableEntry *op_types[] = {op1_type, op2_type};
|
||||
|
||||
TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, context, node,
|
||||
op1, op2, op1_type, op2_type);
|
||||
op_nodes, op_types, 2);
|
||||
|
||||
if (resolved_type->id == TypeTableEntryIdInvalid) {
|
||||
return g->builtin_types.entry_invalid;
|
||||
|
@ -1997,20 +1957,30 @@ static TypeTableEntry *analyze_bool_bin_op_expr(CodeGen *g, ImportTableEntry *im
|
|||
}
|
||||
|
||||
bool answer;
|
||||
if (resolved_type->id == TypeTableEntryIdInt) {
|
||||
if (op1_type->data.integral.is_signed &&
|
||||
op2_type->data.integral.is_signed)
|
||||
{
|
||||
answer = eval_bool_bin_op_signed(op1_val->data.x_int, bin_op_type, op2_val->data.x_int);
|
||||
} else if (!op1_type->data.integral.is_signed &&
|
||||
!op2_type->data.integral.is_signed)
|
||||
{
|
||||
answer = eval_bool_bin_op_unsigned(op1_val->data.x_uint, bin_op_type, op2_val->data.x_uint);
|
||||
if (resolved_type->id == TypeTableEntryIdNumLitFloat ||
|
||||
resolved_type->id == TypeTableEntryIdNumLitInt ||
|
||||
resolved_type->id == TypeTableEntryIdFloat ||
|
||||
resolved_type->id == TypeTableEntryIdInt)
|
||||
{
|
||||
bool (*bignum_cmp)(BigNum *, BigNum *);
|
||||
if (bin_op_type == BinOpTypeCmpEq) {
|
||||
bignum_cmp = bignum_cmp_eq;
|
||||
} else if (bin_op_type == BinOpTypeCmpNotEq) {
|
||||
bignum_cmp = bignum_cmp_neq;
|
||||
} else if (bin_op_type == BinOpTypeCmpLessThan) {
|
||||
bignum_cmp = bignum_cmp_lt;
|
||||
} else if (bin_op_type == BinOpTypeCmpGreaterThan) {
|
||||
bignum_cmp = bignum_cmp_gt;
|
||||
} else if (bin_op_type == BinOpTypeCmpLessOrEq) {
|
||||
bignum_cmp = bignum_cmp_lte;
|
||||
} else if (bin_op_type == BinOpTypeCmpGreaterOrEq) {
|
||||
bignum_cmp = bignum_cmp_gte;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
} else if (resolved_type->id == TypeTableEntryIdFloat) {
|
||||
answer = eval_bool_bin_op_float(op1_val->data.x_float, bin_op_type, op2_val->data.x_float);
|
||||
|
||||
answer = bignum_cmp(&op1_val->data.x_bignum, &op2_val->data.x_bignum);
|
||||
|
||||
} else if (resolved_type->id == TypeTableEntryIdEnum) {
|
||||
ConstEnumValue *enum1 = &op1_val->data.x_enum;
|
||||
ConstEnumValue *enum2 = &op2_val->data.x_enum;
|
||||
|
@ -2124,7 +2094,45 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
|
|||
TypeTableEntry *lhs_type = analyze_expression(g, import, context, expected_type, op1);
|
||||
TypeTableEntry *rhs_type = analyze_expression(g, import, context, expected_type, op2);
|
||||
|
||||
return resolve_peer_type_compatibility(g, context, node, op1, op2, lhs_type, rhs_type);
|
||||
AstNode *op_nodes[] = {op1, op2};
|
||||
TypeTableEntry *op_types[] = {lhs_type, rhs_type};
|
||||
|
||||
TypeTableEntry *resolved_type = resolve_peer_type_compatibility(g, context, node,
|
||||
op_nodes, op_types, 2);
|
||||
|
||||
if (resolved_type->id == TypeTableEntryIdInvalid) {
|
||||
return resolved_type;
|
||||
}
|
||||
|
||||
ConstExprValue *op1_val = &get_resolved_expr(op1)->const_val;
|
||||
ConstExprValue *op2_val = &get_resolved_expr(op2)->const_val;
|
||||
if (!op1_val->ok || !op2_val->ok) {
|
||||
return resolved_type;
|
||||
}
|
||||
|
||||
if (bin_op_type == BinOpTypeAdd) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_add, op1, op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeSub) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_sub, op1, op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeMult) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_mul, op1, op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeDiv) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_div, op1, op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeMod) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_mod, op1, op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeBinOr) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_or, op1, op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeBinAnd) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_and, op1, op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeBinXor) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_xor, op1, op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeBitShiftLeft) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_shl, op1, op2, resolved_type);
|
||||
} else if (bin_op_type == BinOpTypeBitShiftRight) {
|
||||
return resolve_expr_const_val_as_bignum_op(g, node, bignum_shr, op1, op2, resolved_type);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
case BinOpTypeUnwrapMaybe:
|
||||
{
|
||||
|
@ -2197,6 +2205,8 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
|
|||
AstNodeVariableDeclaration *variable_declaration,
|
||||
bool expr_is_maybe)
|
||||
{
|
||||
bool is_const = variable_declaration->is_const;
|
||||
|
||||
TypeTableEntry *explicit_type = nullptr;
|
||||
if (variable_declaration->type != nullptr) {
|
||||
explicit_type = analyze_type_expr(g, import, context, variable_declaration->type);
|
||||
|
@ -2223,19 +2233,19 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
|
|||
add_node_error(g, source_node,
|
||||
buf_sprintf("variable initialization is unreachable"));
|
||||
implicit_type = g->builtin_types.entry_invalid;
|
||||
} else if (implicit_type->id == TypeTableEntryIdNumberLiteral) {
|
||||
add_node_error(g, source_node,
|
||||
buf_sprintf("unable to infer variable type"));
|
||||
implicit_type = g->builtin_types.entry_invalid;
|
||||
} else if (implicit_type->id == TypeTableEntryIdMetaType &&
|
||||
!variable_declaration->is_const)
|
||||
} else if (!is_const &&
|
||||
(implicit_type->id == TypeTableEntryIdNumLitFloat ||
|
||||
implicit_type->id == TypeTableEntryIdNumLitInt))
|
||||
{
|
||||
add_node_error(g, source_node, buf_sprintf("unable to infer variable type"));
|
||||
implicit_type = g->builtin_types.entry_invalid;
|
||||
} else if (implicit_type->id == TypeTableEntryIdMetaType && !is_const) {
|
||||
add_node_error(g, source_node, buf_sprintf("variable of type 'type' must be constant"));
|
||||
implicit_type = g->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
if (implicit_type == nullptr && variable_declaration->is_const) {
|
||||
if (implicit_type == nullptr && is_const) {
|
||||
add_node_error(g, source_node, buf_sprintf("const variable missing initialization"));
|
||||
implicit_type = g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
@ -2244,7 +2254,7 @@ static VariableTableEntry *analyze_variable_declaration_raw(CodeGen *g, ImportTa
|
|||
assert(type != nullptr); // should have been caught by the parser
|
||||
|
||||
VariableTableEntry *var = add_local_var(g, source_node, context,
|
||||
&variable_declaration->symbol, type, variable_declaration->is_const);
|
||||
&variable_declaration->symbol, type, is_const);
|
||||
|
||||
|
||||
bool is_pub = (variable_declaration->visib_mod != VisibModPrivate);
|
||||
|
@ -2300,28 +2310,15 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry
|
|||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
|
||||
const_val->ok = true;
|
||||
if (is_num_lit_unsigned(node->data.number_literal.kind)) {
|
||||
const_val->data.x_uint = node->data.number_literal.data.x_uint;
|
||||
} else if (is_num_lit_float(node->data.number_literal.kind)) {
|
||||
const_val->data.x_float = node->data.number_literal.data.x_float;
|
||||
if (node->data.number_literal.kind == NumLitUInt) {
|
||||
return resolve_expr_const_val_as_unsigned_num_lit(g, node,
|
||||
expected_type, node->data.number_literal.data.x_uint);
|
||||
} else if (node->data.number_literal.kind == NumLitFloat) {
|
||||
return resolve_expr_const_val_as_float_num_lit(g, node,
|
||||
expected_type, node->data.number_literal.data.x_float);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
TypeTableEntry *num_lit_type = g->num_lit_types[node->data.number_literal.kind];
|
||||
if (expected_type) {
|
||||
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
|
||||
assert(!codegen_num_lit->resolved_type);
|
||||
TypeTableEntry *after_implicit_cast_resolved_type =
|
||||
resolve_type_compatibility(g, block_context, node, expected_type, num_lit_type);
|
||||
assert(codegen_num_lit->resolved_type ||
|
||||
after_implicit_cast_resolved_type->id == TypeTableEntryIdInvalid);
|
||||
return after_implicit_cast_resolved_type;
|
||||
} else {
|
||||
return num_lit_type;
|
||||
}
|
||||
}
|
||||
|
||||
static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import,
|
||||
|
@ -2353,8 +2350,15 @@ static TypeTableEntry *analyze_array_type(CodeGen *g, ImportTableEntry *import,
|
|||
|
||||
ConstExprValue *const_val = &get_resolved_expr(size_node)->const_val;
|
||||
if (const_val->ok) {
|
||||
return resolve_expr_const_val_as_type(g, node,
|
||||
get_array_type(g, child_type, const_val->data.x_uint));
|
||||
if (const_val->data.x_bignum.is_negative) {
|
||||
add_node_error(g, size_node,
|
||||
buf_sprintf("array size %s is negative",
|
||||
buf_ptr(bignum_to_buf(&const_val->data.x_bignum))));
|
||||
return g->builtin_types.entry_invalid;
|
||||
} else {
|
||||
return resolve_expr_const_val_as_type(g, node,
|
||||
get_array_type(g, child_type, const_val->data.x_bignum.data.x_uint));
|
||||
}
|
||||
} else {
|
||||
return resolve_expr_const_val_as_type(g, node,
|
||||
get_unknown_size_array_type(g, child_type, node->data.array_type.is_const));
|
||||
|
@ -2493,9 +2497,9 @@ static TypeTableEntry *analyze_if_then_else(CodeGen *g, ImportTableEntry *import
|
|||
if (expected_type) {
|
||||
return (then_type->id == TypeTableEntryIdUnreachable) ? else_type : then_type;
|
||||
} else {
|
||||
return resolve_peer_type_compatibility(g, context, parent_node,
|
||||
then_block, else_node,
|
||||
then_type, else_type);
|
||||
AstNode *op_nodes[] = {then_block, else_node};
|
||||
TypeTableEntry *op_types[] = {then_type, else_type};
|
||||
return resolve_peer_type_compatibility(g, context, parent_node, op_nodes, op_types, 2);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2535,10 +2539,60 @@ static TypeTableEntry *analyze_min_max_value(CodeGen *g, ImportTableEntry *impor
|
|||
if (type_entry->id == TypeTableEntryIdInvalid) {
|
||||
return g->builtin_types.entry_invalid;
|
||||
} else if (type_entry->id == TypeTableEntryIdInt) {
|
||||
// TODO const expr eval for min/max int
|
||||
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
|
||||
const_val->ok = true;
|
||||
if (is_max) {
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
int64_t val;
|
||||
if (type_entry->size_in_bits == 64) {
|
||||
val = INT64_MAX;
|
||||
} else if (type_entry->size_in_bits == 32) {
|
||||
val = INT32_MAX;
|
||||
} else if (type_entry->size_in_bits == 16) {
|
||||
val = INT16_MAX;
|
||||
} else if (type_entry->size_in_bits == 8) {
|
||||
val = INT8_MAX;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
bignum_init_signed(&const_val->data.x_bignum, val);
|
||||
} else {
|
||||
uint64_t val;
|
||||
if (type_entry->size_in_bits == 64) {
|
||||
val = UINT64_MAX;
|
||||
} else if (type_entry->size_in_bits == 32) {
|
||||
val = UINT32_MAX;
|
||||
} else if (type_entry->size_in_bits == 16) {
|
||||
val = UINT16_MAX;
|
||||
} else if (type_entry->size_in_bits == 8) {
|
||||
val = UINT8_MAX;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
bignum_init_unsigned(&const_val->data.x_bignum, val);
|
||||
}
|
||||
} else {
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
int64_t val;
|
||||
if (type_entry->size_in_bits == 64) {
|
||||
val = INT64_MIN;
|
||||
} else if (type_entry->size_in_bits == 32) {
|
||||
val = INT32_MIN;
|
||||
} else if (type_entry->size_in_bits == 16) {
|
||||
val = INT16_MIN;
|
||||
} else if (type_entry->size_in_bits == 8) {
|
||||
val = INT8_MIN;
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
bignum_init_signed(&const_val->data.x_bignum, val);
|
||||
} else {
|
||||
bignum_init_unsigned(&const_val->data.x_bignum, 0);
|
||||
}
|
||||
}
|
||||
return type_entry;
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
// TODO const expr eval for min/max float
|
||||
zig_panic("TODO analyze_min_max_value float");
|
||||
return type_entry;
|
||||
} else if (type_entry->id == TypeTableEntryIdBool) {
|
||||
return resolve_expr_const_val_as_bool(g, node, is_max);
|
||||
|
@ -2559,10 +2613,9 @@ static void eval_const_expr_implicit_cast(CodeGen *g, ImportTableEntry *import,
|
|||
case CastOpPointerReinterpret:
|
||||
{
|
||||
ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val;
|
||||
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
|
||||
if (other_val != const_val) {
|
||||
*const_val = *other_val;
|
||||
}
|
||||
ConstExprValue *const_val = &cast->const_val;
|
||||
assert(const_val != other_val);
|
||||
*const_val = *other_val;
|
||||
break;
|
||||
}
|
||||
case CastOpToUnknownSizeArray:
|
||||
|
@ -2571,14 +2624,11 @@ static void eval_const_expr_implicit_cast(CodeGen *g, ImportTableEntry *import,
|
|||
case CastOpMaybeWrap:
|
||||
{
|
||||
ConstExprValue *other_val = &get_resolved_expr(expr_node)->const_val;
|
||||
ConstExprValue *const_val = &get_resolved_expr(node)->const_val;
|
||||
ConstExprValue *const_val = &cast->const_val;
|
||||
if (!other_val->ok) {
|
||||
break;
|
||||
} else if (const_val == other_val) {
|
||||
ConstExprValue *new_val = allocate<ConstExprValue>(1);
|
||||
memcpy(new_val, other_val, sizeof(ConstExprValue));
|
||||
other_val = new_val;
|
||||
}
|
||||
assert(const_val != other_val);
|
||||
|
||||
const_val->data.x_maybe = other_val;
|
||||
const_val->ok = true;
|
||||
|
@ -2635,12 +2685,10 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
|
|||
context->cast_expr_alloca_list.append(cast);
|
||||
eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node);
|
||||
return wanted_type;
|
||||
} else if (actual_type->id == TypeTableEntryIdNumberLiteral &&
|
||||
num_lit_fits_in_other_type(g, actual_type, wanted_type))
|
||||
} else if (actual_type->id == TypeTableEntryIdNumLitFloat ||
|
||||
actual_type->id == TypeTableEntryIdNumLitInt)
|
||||
{
|
||||
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(expr_node);
|
||||
assert(!codegen_num_lit->resolved_type);
|
||||
codegen_num_lit->resolved_type = wanted_type;
|
||||
num_lit_fits_in_other_type(g, expr_node, wanted_type);
|
||||
cast->op = CastOpNothing;
|
||||
eval_const_expr_implicit_cast(g, import, context, node, cast, expr_node);
|
||||
return wanted_type;
|
||||
|
@ -2998,7 +3046,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
|
|||
return g->builtin_types.entry_bool;
|
||||
}
|
||||
|
||||
bool answer = target_const_val->data.x_bool;
|
||||
bool answer = !target_const_val->data.x_bool;
|
||||
return resolve_expr_const_val_as_bool(g, node, answer);
|
||||
}
|
||||
case PrefixOpBinNot:
|
||||
|
@ -3008,8 +3056,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
|
|||
if (expr_type->id == TypeTableEntryIdInvalid) {
|
||||
return expr_type;
|
||||
} else if (expr_type->id == TypeTableEntryIdInt ||
|
||||
(expr_type->id == TypeTableEntryIdNumberLiteral &&
|
||||
!is_num_lit_float(expr_type->data.num_lit.kind)))
|
||||
expr_type->id == TypeTableEntryIdNumLitInt)
|
||||
{
|
||||
return expr_type;
|
||||
} else {
|
||||
|
@ -3017,6 +3064,7 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
|
|||
buf_ptr(&expr_type->name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
// TODO const expr eval
|
||||
}
|
||||
case PrefixOpNegation:
|
||||
{
|
||||
|
@ -3030,13 +3078,16 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
|
|||
return expr_type;
|
||||
} else if (expr_type->id == TypeTableEntryIdFloat) {
|
||||
return expr_type;
|
||||
} else if (expr_type->id == TypeTableEntryIdNumberLiteral) {
|
||||
} else if (expr_type->id == TypeTableEntryIdNumLitInt) {
|
||||
return expr_type;
|
||||
} else if (expr_type->id == TypeTableEntryIdNumLitFloat) {
|
||||
return expr_type;
|
||||
} else {
|
||||
add_node_error(g, node, buf_sprintf("invalid negation type: '%s'",
|
||||
buf_ptr(&expr_type->name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
// TODO const expr eval
|
||||
}
|
||||
case PrefixOpAddressOf:
|
||||
case PrefixOpConstAddressOf:
|
||||
|
@ -4129,59 +4180,6 @@ Expr *get_resolved_expr(AstNode *node) {
|
|||
zig_unreachable();
|
||||
}
|
||||
|
||||
NumLitCodeGen *get_resolved_num_lit(AstNode *node) {
|
||||
switch (node->type) {
|
||||
case NodeTypeNumberLiteral:
|
||||
return &node->data.number_literal.codegen;
|
||||
case NodeTypeErrorLiteral:
|
||||
return &node->data.error_literal.codegen;
|
||||
case NodeTypeFnCallExpr:
|
||||
return &node->data.fn_call_expr.resolved_num_lit;
|
||||
case NodeTypeReturnExpr:
|
||||
case NodeTypeBinOpExpr:
|
||||
case NodeTypePrefixOpExpr:
|
||||
case NodeTypeArrayAccessExpr:
|
||||
case NodeTypeSliceExpr:
|
||||
case NodeTypeFieldAccessExpr:
|
||||
case NodeTypeIfBoolExpr:
|
||||
case NodeTypeIfVarExpr:
|
||||
case NodeTypeWhileExpr:
|
||||
case NodeTypeForExpr:
|
||||
case NodeTypeSwitchExpr:
|
||||
case NodeTypeSwitchProng:
|
||||
case NodeTypeSwitchRange:
|
||||
case NodeTypeAsmExpr:
|
||||
case NodeTypeContainerInitExpr:
|
||||
case NodeTypeRoot:
|
||||
case NodeTypeRootExportDecl:
|
||||
case NodeTypeFnProto:
|
||||
case NodeTypeFnDef:
|
||||
case NodeTypeFnDecl:
|
||||
case NodeTypeParamDecl:
|
||||
case NodeTypeBlock:
|
||||
case NodeTypeExternBlock:
|
||||
case NodeTypeDirective:
|
||||
case NodeTypeVariableDeclaration:
|
||||
case NodeTypeStringLiteral:
|
||||
case NodeTypeCharLiteral:
|
||||
case NodeTypeSymbol:
|
||||
case NodeTypeUse:
|
||||
case NodeTypeBoolLiteral:
|
||||
case NodeTypeNullLiteral:
|
||||
case NodeTypeLabel:
|
||||
case NodeTypeGoto:
|
||||
case NodeTypeBreak:
|
||||
case NodeTypeContinue:
|
||||
case NodeTypeStructDecl:
|
||||
case NodeTypeStructField:
|
||||
case NodeTypeStructValueField:
|
||||
case NodeTypeArrayType:
|
||||
case NodeTypeErrorValueDecl:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
TopLevelDecl *get_resolved_top_level_decl(AstNode *node) {
|
||||
switch (node->type) {
|
||||
case NodeTypeVariableDeclaration:
|
||||
|
|
|
@ -18,7 +18,6 @@ VariableTableEntry *find_variable(BlockContext *context, Buf *name);
|
|||
TypeTableEntry *find_container(BlockContext *context, Buf *name);
|
||||
BlockContext *new_block_context(AstNode *node, BlockContext *parent);
|
||||
Expr *get_resolved_expr(AstNode *node);
|
||||
NumLitCodeGen *get_resolved_num_lit(AstNode *node);
|
||||
TopLevelDecl *get_resolved_top_level_decl(AstNode *node);
|
||||
bool is_node_void_expr(AstNode *node);
|
||||
TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits);
|
||||
|
|
|
@ -0,0 +1,305 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "bignum.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
static void bignum_normalize(BigNum *bn) {
|
||||
assert(bn->kind == BigNumKindInt);
|
||||
if (bn->data.x_uint == 0) {
|
||||
bn->is_negative = false;
|
||||
}
|
||||
}
|
||||
|
||||
void bignum_init_float(BigNum *dest, double x) {
|
||||
dest->kind = BigNumKindFloat;
|
||||
dest->is_negative = false;
|
||||
dest->data.x_float = x;
|
||||
}
|
||||
|
||||
void bignum_init_unsigned(BigNum *dest, uint64_t x) {
|
||||
dest->kind = BigNumKindInt;
|
||||
dest->is_negative = false;
|
||||
dest->data.x_uint = x;
|
||||
}
|
||||
|
||||
void bignum_init_signed(BigNum *dest, int64_t x) {
|
||||
dest->kind = BigNumKindInt;
|
||||
if (x < 0) {
|
||||
dest->is_negative = true;
|
||||
dest->data.x_uint = ((uint64_t)(-(x + 1))) + 1;
|
||||
} else {
|
||||
dest->is_negative = false;
|
||||
dest->data.x_uint = x;
|
||||
}
|
||||
}
|
||||
|
||||
bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed) {
|
||||
assert(bn->kind == BigNumKindInt);
|
||||
|
||||
if (is_signed) {
|
||||
if (bn->data.x_uint <= ((uint64_t)(INT8_MAX)) + 1) {
|
||||
return bit_count >= 8;
|
||||
} else if (bn->data.x_uint <= ((uint64_t)(INT16_MAX)) + 1) {
|
||||
return bit_count >= 16;
|
||||
} else if (bn->data.x_uint <= ((uint64_t)(INT32_MAX)) + 1) {
|
||||
return bit_count >= 32;
|
||||
} else {
|
||||
return bit_count >= 64;
|
||||
}
|
||||
} else {
|
||||
if (bn->is_negative) {
|
||||
return bn->data.x_uint == 0;
|
||||
} else {
|
||||
if (bn->data.x_uint <= UINT8_MAX) {
|
||||
return bit_count >= 8;
|
||||
} else if (bn->data.x_uint <= UINT16_MAX) {
|
||||
return bit_count >= 16;
|
||||
} else if (bn->data.x_uint <= UINT32_MAX) {
|
||||
return bit_count >= 32;
|
||||
} else {
|
||||
return bit_count >= 64;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t bignum_to_twos_complement(BigNum *bn) {
|
||||
assert(bn->kind == BigNumKindInt);
|
||||
|
||||
if (bn->is_negative) {
|
||||
int64_t x = bn->data.x_uint;
|
||||
return -x;
|
||||
} else {
|
||||
return bn->data.x_uint;
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if overflow happened
|
||||
bool bignum_add(BigNum *dest, BigNum *op1, BigNum *op2) {
|
||||
assert(op1->kind == op2->kind);
|
||||
dest->kind = op1->kind;
|
||||
|
||||
if (dest->kind == BigNumKindFloat) {
|
||||
dest->data.x_float = op1->data.x_float + op2->data.x_float;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (op1->is_negative == op2->is_negative) {
|
||||
return __builtin_uaddll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint);
|
||||
} else if (!op1->is_negative && op2->is_negative) {
|
||||
if (__builtin_usubll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint)) {
|
||||
dest->data.x_uint = (UINT64_MAX - dest->data.x_uint) + 1;
|
||||
dest->is_negative = true;
|
||||
bignum_normalize(dest);
|
||||
return false;
|
||||
} else {
|
||||
bignum_normalize(dest);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return bignum_add(dest, op2, op1);
|
||||
}
|
||||
}
|
||||
|
||||
void bignum_negate(BigNum *dest, BigNum *op) {
|
||||
dest->kind = op->kind;
|
||||
|
||||
if (dest->kind == BigNumKindFloat) {
|
||||
dest->data.x_float = -dest->data.x_float;
|
||||
} else {
|
||||
dest->data.x_uint = op->data.x_uint;
|
||||
dest->is_negative = !op->is_negative;
|
||||
bignum_normalize(dest);
|
||||
}
|
||||
}
|
||||
|
||||
bool bignum_sub(BigNum *dest, BigNum *op1, BigNum *op2) {
|
||||
BigNum op2_negated;
|
||||
bignum_negate(&op2_negated, op2);
|
||||
return bignum_add(dest, op1, &op2_negated);
|
||||
}
|
||||
|
||||
bool bignum_mul(BigNum *dest, BigNum *op1, BigNum *op2) {
|
||||
assert(op1->kind == op2->kind);
|
||||
dest->kind = op1->kind;
|
||||
|
||||
if (dest->kind == BigNumKindFloat) {
|
||||
dest->data.x_float = op1->data.x_float * op2->data.x_float;
|
||||
bignum_normalize(dest);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (__builtin_umulll_overflow(op1->data.x_uint, op2->data.x_uint, &dest->data.x_uint)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
dest->is_negative = op1->is_negative != op2->is_negative;
|
||||
bignum_normalize(dest);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bignum_div(BigNum *dest, BigNum *op1, BigNum *op2) {
|
||||
assert(op1->kind == op2->kind);
|
||||
dest->kind = op1->kind;
|
||||
|
||||
if (dest->kind == BigNumKindFloat) {
|
||||
dest->data.x_float = op1->data.x_float / op2->data.x_float;
|
||||
} else {
|
||||
dest->data.x_uint = op1->data.x_uint / op2->data.x_uint;
|
||||
dest->is_negative = op1->is_negative != op2->is_negative;
|
||||
bignum_normalize(dest);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bignum_mod(BigNum *dest, BigNum *op1, BigNum *op2) {
|
||||
assert(op1->kind == op2->kind);
|
||||
dest->kind = op1->kind;
|
||||
|
||||
if (dest->kind == BigNumKindFloat) {
|
||||
dest->data.x_float = fmod(op1->data.x_float, op2->data.x_float);
|
||||
} else {
|
||||
if (op1->is_negative || op2->is_negative) {
|
||||
zig_panic("TODO handle mod with negative numbers");
|
||||
}
|
||||
dest->data.x_uint = op1->data.x_uint % op2->data.x_uint;
|
||||
bignum_normalize(dest);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bignum_or(BigNum *dest, BigNum *op1, BigNum *op2) {
|
||||
assert(op1->kind == BigNumKindInt);
|
||||
assert(op2->kind == BigNumKindInt);
|
||||
|
||||
assert(!op1->is_negative);
|
||||
assert(!op2->is_negative);
|
||||
|
||||
dest->kind = BigNumKindInt;
|
||||
dest->data.x_uint = op1->data.x_uint | op2->data.x_uint;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bignum_and(BigNum *dest, BigNum *op1, BigNum *op2) {
|
||||
assert(op1->kind == BigNumKindInt);
|
||||
assert(op2->kind == BigNumKindInt);
|
||||
|
||||
assert(!op1->is_negative);
|
||||
assert(!op2->is_negative);
|
||||
|
||||
dest->kind = BigNumKindInt;
|
||||
dest->data.x_uint = op1->data.x_uint & op2->data.x_uint;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bignum_xor(BigNum *dest, BigNum *op1, BigNum *op2) {
|
||||
assert(op1->kind == BigNumKindInt);
|
||||
assert(op2->kind == BigNumKindInt);
|
||||
|
||||
assert(!op1->is_negative);
|
||||
assert(!op2->is_negative);
|
||||
|
||||
dest->kind = BigNumKindInt;
|
||||
dest->data.x_uint = op1->data.x_uint ^ op2->data.x_uint;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bignum_shl(BigNum *dest, BigNum *op1, BigNum *op2) {
|
||||
assert(op1->kind == BigNumKindInt);
|
||||
assert(op2->kind == BigNumKindInt);
|
||||
|
||||
assert(!op1->is_negative);
|
||||
assert(!op2->is_negative);
|
||||
|
||||
dest->kind = BigNumKindInt;
|
||||
dest->data.x_uint = op1->data.x_uint << op2->data.x_uint;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool bignum_shr(BigNum *dest, BigNum *op1, BigNum *op2) {
|
||||
assert(op1->kind == BigNumKindInt);
|
||||
assert(op2->kind == BigNumKindInt);
|
||||
|
||||
assert(!op1->is_negative);
|
||||
assert(!op2->is_negative);
|
||||
|
||||
dest->kind = BigNumKindInt;
|
||||
dest->data.x_uint = op1->data.x_uint >> op2->data.x_uint;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Buf *bignum_to_buf(BigNum *bn) {
|
||||
if (bn->kind == BigNumKindFloat) {
|
||||
return buf_sprintf("%f", bn->data.x_float);
|
||||
} else {
|
||||
const char *neg = bn->is_negative ? "-" : "";
|
||||
return buf_sprintf("%s%llu", neg, bn->data.x_uint);
|
||||
}
|
||||
}
|
||||
|
||||
bool bignum_cmp_eq(BigNum *op1, BigNum *op2) {
|
||||
assert(op1->kind == op2->kind);
|
||||
if (op1->kind == BigNumKindFloat) {
|
||||
return op1->data.x_float == op2->data.x_float;
|
||||
} else {
|
||||
return op1->data.x_uint == op2->data.x_uint &&
|
||||
(op1->is_negative == op2->is_negative || op1->data.x_uint == 0);
|
||||
}
|
||||
}
|
||||
|
||||
bool bignum_cmp_neq(BigNum *op1, BigNum *op2) {
|
||||
return !bignum_cmp_eq(op1, op2);
|
||||
}
|
||||
|
||||
bool bignum_cmp_lt(BigNum *op1, BigNum *op2) {
|
||||
return !bignum_cmp_gte(op1, op2);
|
||||
}
|
||||
|
||||
bool bignum_cmp_gt(BigNum *op1, BigNum *op2) {
|
||||
return !bignum_cmp_lte(op1, op2);
|
||||
}
|
||||
|
||||
bool bignum_cmp_lte(BigNum *op1, BigNum *op2) {
|
||||
assert(op1->kind == op2->kind);
|
||||
if (op1->kind == BigNumKindFloat) {
|
||||
return (op1->data.x_float <= op2->data.x_float);
|
||||
}
|
||||
|
||||
// assume normalized is_negative
|
||||
if (!op1->is_negative && !op2->is_negative) {
|
||||
return op1->data.x_uint <= op2->data.x_uint;
|
||||
} else if (op1->is_negative && op2->is_negative) {
|
||||
return op1->data.x_uint >= op2->data.x_uint;
|
||||
} else if (op1->is_negative && !op2->is_negative) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool bignum_cmp_gte(BigNum *op1, BigNum *op2) {
|
||||
assert(op1->kind == op2->kind);
|
||||
|
||||
if (op1->kind == BigNumKindFloat) {
|
||||
return (op1->data.x_float >= op2->data.x_float);
|
||||
}
|
||||
|
||||
// assume normalized is_negative
|
||||
if (!op1->is_negative && !op2->is_negative) {
|
||||
return op1->data.x_uint >= op2->data.x_uint;
|
||||
} else if (op1->is_negative && op2->is_negative) {
|
||||
return op1->data.x_uint <= op2->data.x_uint;
|
||||
} else if (op1->is_negative && !op2->is_negative) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2016 Andrew Kelley
|
||||
*
|
||||
* This file is part of zig, which is MIT licensed.
|
||||
* See http://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#include "buffer.hpp"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
enum BigNumKind {
|
||||
BigNumKindInt,
|
||||
BigNumKindFloat,
|
||||
};
|
||||
|
||||
struct BigNum {
|
||||
BigNumKind kind;
|
||||
bool is_negative;
|
||||
union {
|
||||
unsigned long long x_uint;
|
||||
double x_float;
|
||||
} data;
|
||||
};
|
||||
|
||||
void bignum_init_float(BigNum *dest, double x);
|
||||
void bignum_init_unsigned(BigNum *dest, uint64_t x);
|
||||
void bignum_init_signed(BigNum *dest, int64_t x);
|
||||
|
||||
bool bignum_fits_in_bits(BigNum *bn, int bit_count, bool is_signed);
|
||||
uint64_t bignum_to_twos_complement(BigNum *bn);
|
||||
|
||||
// returns true if overflow happened
|
||||
bool bignum_add(BigNum *dest, BigNum *op1, BigNum *op2);
|
||||
bool bignum_sub(BigNum *dest, BigNum *op1, BigNum *op2);
|
||||
bool bignum_mul(BigNum *dest, BigNum *op1, BigNum *op2);
|
||||
bool bignum_div(BigNum *dest, BigNum *op1, BigNum *op2);
|
||||
bool bignum_mod(BigNum *dest, BigNum *op1, BigNum *op2);
|
||||
|
||||
bool bignum_or(BigNum *dest, BigNum *op1, BigNum *op2);
|
||||
bool bignum_and(BigNum *dest, BigNum *op1, BigNum *op2);
|
||||
bool bignum_xor(BigNum *dest, BigNum *op1, BigNum *op2);
|
||||
bool bignum_shl(BigNum *dest, BigNum *op1, BigNum *op2);
|
||||
bool bignum_shr(BigNum *dest, BigNum *op1, BigNum *op2);
|
||||
|
||||
void bignum_negate(BigNum *dest, BigNum *op);
|
||||
|
||||
// returns the result of the comparison
|
||||
bool bignum_cmp_eq(BigNum *op1, BigNum *op2);
|
||||
bool bignum_cmp_neq(BigNum *op1, BigNum *op2);
|
||||
bool bignum_cmp_lt(BigNum *op1, BigNum *op2);
|
||||
bool bignum_cmp_gt(BigNum *op1, BigNum *op2);
|
||||
bool bignum_cmp_lte(BigNum *op1, BigNum *op2);
|
||||
bool bignum_cmp_gte(BigNum *op1, BigNum *op2);
|
||||
|
||||
Buf *bignum_to_buf(BigNum *bn);
|
169
src/codegen.cpp
169
src/codegen.cpp
|
@ -118,6 +118,9 @@ static TypeTableEntry *get_expr_type(AstNode *node) {
|
|||
if (expr->implicit_cast.after_type) {
|
||||
return expr->implicit_cast.after_type;
|
||||
}
|
||||
if (expr->resolved_type) {
|
||||
return expr->resolved_type;
|
||||
}
|
||||
return expr->type_entry;
|
||||
}
|
||||
|
||||
|
@ -131,29 +134,35 @@ static TypeTableEntry *fn_proto_type_from_type_node(CodeGen *g, AstNode *type_no
|
|||
}
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_number_literal_raw(CodeGen *g, AstNode *source_node,
|
||||
NumLitCodeGen *codegen_num_lit, AstNodeNumberLiteral *num_lit_node)
|
||||
{
|
||||
TypeTableEntry *type_entry = codegen_num_lit->resolved_type;
|
||||
static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *expr_node) {
|
||||
Expr *expr = get_resolved_expr(expr_node);
|
||||
TypeTableEntry *type_entry = expr->resolved_type;
|
||||
if (!type_entry) {
|
||||
type_entry = expr->type_entry;
|
||||
}
|
||||
assert(type_entry);
|
||||
|
||||
// override the expression type for number literals
|
||||
get_resolved_expr(source_node)->type_entry = type_entry;
|
||||
ConstExprValue *const_val = &expr->const_val;
|
||||
|
||||
assert(const_val->ok);
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
// here the union has int64_t and uint64_t and we purposefully read
|
||||
// the uint64_t value in either case, because we want the twos
|
||||
// complement representation
|
||||
|
||||
assert(const_val->data.x_bignum.kind == BigNumKindInt);
|
||||
return LLVMConstInt(type_entry->type_ref,
|
||||
num_lit_node->data.x_uint,
|
||||
type_entry->data.integral.is_signed);
|
||||
bignum_to_twos_complement(&const_val->data.x_bignum),
|
||||
type_entry->data.integral.is_signed);
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
|
||||
return LLVMConstReal(type_entry->type_ref,
|
||||
num_lit_node->data.x_float);
|
||||
if (const_val->data.x_bignum.kind == BigNumKindFloat) {
|
||||
return LLVMConstReal(type_entry->type_ref, const_val->data.x_bignum.data.x_float);
|
||||
} else {
|
||||
int64_t x = const_val->data.x_bignum.data.x_uint;
|
||||
if (const_val->data.x_bignum.is_negative) {
|
||||
x = -x;
|
||||
}
|
||||
return LLVMConstReal(type_entry->type_ref, x);
|
||||
}
|
||||
} else {
|
||||
zig_panic("bad number literal type");
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,73 +274,10 @@ static LLVMValueRef gen_builtin_fn_call_expr(CodeGen *g, AstNode *node) {
|
|||
return nullptr;
|
||||
}
|
||||
case BuiltinFnIdSizeof:
|
||||
{
|
||||
assert(node->data.fn_call_expr.params.length == 1);
|
||||
AstNode *type_node = node->data.fn_call_expr.params.at(0);
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
|
||||
|
||||
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
|
||||
AstNodeNumberLiteral num_lit_node;
|
||||
num_lit_node.kind = NumLitU64; // this field isn't even read
|
||||
num_lit_node.overflow = false;
|
||||
num_lit_node.data.x_uint = type_entry->size_in_bits / 8;
|
||||
return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
|
||||
}
|
||||
case BuiltinFnIdMinValue:
|
||||
{
|
||||
assert(node->data.fn_call_expr.params.length == 1);
|
||||
AstNode *type_node = node->data.fn_call_expr.params.at(0);
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
|
||||
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
return LLVMConstInt(type_entry->type_ref, 1ULL << (type_entry->size_in_bits - 1), false);
|
||||
} else {
|
||||
return LLVMConstNull(type_entry->type_ref);
|
||||
}
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
zig_panic("TODO codegen min_value float");
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
case BuiltinFnIdMaxValue:
|
||||
{
|
||||
assert(node->data.fn_call_expr.params.length == 1);
|
||||
AstNode *type_node = node->data.fn_call_expr.params.at(0);
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
|
||||
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdInt) {
|
||||
if (type_entry->data.integral.is_signed) {
|
||||
return LLVMConstInt(type_entry->type_ref, (1ULL << (type_entry->size_in_bits - 1)) - 1, false);
|
||||
} else {
|
||||
return LLVMConstAllOnes(type_entry->type_ref);
|
||||
}
|
||||
} else if (type_entry->id == TypeTableEntryIdFloat) {
|
||||
zig_panic("TODO codegen max_value float");
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
case BuiltinFnIdMemberCount:
|
||||
{
|
||||
assert(node->data.fn_call_expr.params.length == 1);
|
||||
AstNode *type_node = node->data.fn_call_expr.params.at(0);
|
||||
TypeTableEntry *type_entry = get_type_for_type_node(type_node);
|
||||
|
||||
if (type_entry->id == TypeTableEntryIdEnum) {
|
||||
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
|
||||
AstNodeNumberLiteral num_lit_node;
|
||||
num_lit_node.kind = NumLitU64; // field ignored
|
||||
num_lit_node.overflow = false;
|
||||
num_lit_node.data.x_uint = type_entry->data.enumeration.field_count;
|
||||
return gen_number_literal_raw(g, node, codegen_num_lit, &num_lit_node);
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
}
|
||||
return gen_number_literal(g, node);
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
@ -1407,11 +1353,22 @@ static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
|
|||
assert(node->data.if_bool_expr.condition);
|
||||
assert(node->data.if_bool_expr.then_block);
|
||||
|
||||
LLVMValueRef cond_value = gen_expr(g, node->data.if_bool_expr.condition);
|
||||
ConstExprValue *const_val = &get_resolved_expr(node->data.if_bool_expr.condition)->const_val;
|
||||
if (const_val->ok) {
|
||||
if (const_val->data.x_bool) {
|
||||
return gen_expr(g, node->data.if_bool_expr.then_block);
|
||||
} else if (node->data.if_bool_expr.else_node) {
|
||||
return gen_expr(g, node->data.if_bool_expr.else_node);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
} else {
|
||||
LLVMValueRef cond_value = gen_expr(g, node->data.if_bool_expr.condition);
|
||||
|
||||
return gen_if_bool_expr_raw(g, node, cond_value,
|
||||
node->data.if_bool_expr.then_block,
|
||||
node->data.if_bool_expr.else_node);
|
||||
return gen_if_bool_expr_raw(g, node, cond_value,
|
||||
node->data.if_bool_expr.then_block,
|
||||
node->data.if_bool_expr.else_node);
|
||||
}
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
|
||||
|
@ -1932,15 +1889,6 @@ static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
|
|||
get_resolved_expr(node)->block_context, false, &init_val);
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_number_literal(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeNumberLiteral);
|
||||
|
||||
NumLitCodeGen *codegen_num_lit = get_resolved_num_lit(node);
|
||||
assert(codegen_num_lit);
|
||||
|
||||
return gen_number_literal_raw(g, node, codegen_num_lit, &node->data.number_literal);
|
||||
}
|
||||
|
||||
static LLVMValueRef gen_error_literal(CodeGen *g, AstNode *node) {
|
||||
assert(node->type == NodeTypeErrorLiteral);
|
||||
|
||||
|
@ -2383,20 +2331,6 @@ static void add_int_overflow_fns(CodeGen *g, TypeTableEntry *type_entry) {
|
|||
type_entry->data.integral.mul_with_overflow_fn = get_arithmetic_overflow_fn(g, type_entry, "smul", "umul");
|
||||
}
|
||||
|
||||
static const NumLit num_lit_kinds[] = {
|
||||
NumLitF32,
|
||||
NumLitF64,
|
||||
NumLitF128,
|
||||
NumLitU8,
|
||||
NumLitU16,
|
||||
NumLitU32,
|
||||
NumLitU64,
|
||||
NumLitI8,
|
||||
NumLitI16,
|
||||
NumLitI32,
|
||||
NumLitI64,
|
||||
};
|
||||
|
||||
static const int int_sizes_in_bits[] = {
|
||||
8,
|
||||
16,
|
||||
|
@ -2411,18 +2345,15 @@ static void define_builtin_types(CodeGen *g) {
|
|||
buf_init_from_str(&entry->name, "(invalid)");
|
||||
g->builtin_types.entry_invalid = entry;
|
||||
}
|
||||
|
||||
assert(NumLitCount == array_length(num_lit_kinds));
|
||||
for (int i = 0; i < NumLitCount; i += 1) {
|
||||
NumLit num_lit_kind = num_lit_kinds[i];
|
||||
// This type should just create a constant with whatever actual number
|
||||
// type is expected at the time.
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumberLiteral);
|
||||
buf_resize(&entry->name, 0);
|
||||
buf_appendf(&entry->name, "(%s literal)", num_lit_str(num_lit_kind));
|
||||
entry->data.num_lit.kind = num_lit_kind;
|
||||
entry->size_in_bits = num_lit_bit_count(num_lit_kind);
|
||||
g->num_lit_types[i] = entry;
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitFloat);
|
||||
buf_init_from_str(&entry->name, "(float literal)");
|
||||
g->builtin_types.entry_num_lit_float = entry;
|
||||
}
|
||||
{
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdNumLitInt);
|
||||
buf_init_from_str(&entry->name, "(integer literal)");
|
||||
g->builtin_types.entry_num_lit_int = entry;
|
||||
}
|
||||
|
||||
for (int i = 0; i < array_length(int_sizes_in_bits); i += 1) {
|
||||
|
|
121
src/parser.cpp
121
src/parser.cpp
|
@ -301,13 +301,12 @@ void ast_print(AstNode *node, int indent) {
|
|||
break;
|
||||
case NodeTypeNumberLiteral:
|
||||
{
|
||||
NumLit num_lit = node->data.number_literal.kind;
|
||||
NumLit kind = node->data.number_literal.kind;
|
||||
const char *name = node_type_str(node->type);
|
||||
const char *kind_str = num_lit_str(num_lit);
|
||||
if (is_num_lit_unsigned(num_lit)) {
|
||||
fprintf(stderr, "%s %s %" PRIu64 "\n", name, kind_str, node->data.number_literal.data.x_uint);
|
||||
if (kind == NumLitUInt) {
|
||||
fprintf(stderr, "%s uint %" PRIu64 "\n", name, node->data.number_literal.data.x_uint);
|
||||
} else {
|
||||
fprintf(stderr, "%s %s %f\n", name, kind_str, node->data.number_literal.data.x_float);
|
||||
fprintf(stderr, "%s float %f\n", name, node->data.number_literal.data.x_float);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -808,16 +807,7 @@ static void parse_number_literal(ParseContext *pc, Token *token, AstNodeNumberLi
|
|||
if (num_lit->overflow) return;
|
||||
|
||||
num_lit->data.x_uint = whole_number;
|
||||
|
||||
if (whole_number <= UINT8_MAX) {
|
||||
num_lit->kind = NumLitU8;
|
||||
} else if (whole_number <= UINT16_MAX) {
|
||||
num_lit->kind = NumLitU16;
|
||||
} else if (whole_number <= UINT32_MAX) {
|
||||
num_lit->kind = NumLitU32;
|
||||
} else {
|
||||
num_lit->kind = NumLitU64;
|
||||
}
|
||||
num_lit->kind = NumLitUInt;
|
||||
} else {
|
||||
// float
|
||||
|
||||
|
@ -834,7 +824,7 @@ static void parse_number_literal(ParseContext *pc, Token *token, AstNodeNumberLi
|
|||
}
|
||||
assert(str_end == buf_ptr(pc->buf) + token->end_pos);
|
||||
num_lit->data.x_float = x;
|
||||
num_lit->kind = NumLitF64;
|
||||
num_lit->kind = NumLitFloat;
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -954,8 +944,7 @@ static void parse_number_literal(ParseContext *pc, Token *token, AstNodeNumberLi
|
|||
double x = *(double *)&double_bits;
|
||||
|
||||
num_lit->data.x_float = x;
|
||||
// TODO: see if we can store it in f32
|
||||
num_lit->kind = NumLitF64;
|
||||
num_lit->kind = NumLitFloat;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3053,99 +3042,3 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner,
|
|||
pc.root = ast_parse_root(&pc, &token_index);
|
||||
return pc.root;
|
||||
}
|
||||
|
||||
const char *num_lit_str(NumLit num_lit) {
|
||||
switch (num_lit) {
|
||||
case NumLitF32:
|
||||
return "f32";
|
||||
case NumLitF64:
|
||||
return "f64";
|
||||
case NumLitF128:
|
||||
return "f128";
|
||||
case NumLitU8:
|
||||
return "u8";
|
||||
case NumLitU16:
|
||||
return "u16";
|
||||
case NumLitU32:
|
||||
return "u32";
|
||||
case NumLitU64:
|
||||
return "u64";
|
||||
case NumLitI8:
|
||||
return "i8";
|
||||
case NumLitI16:
|
||||
return "i16";
|
||||
case NumLitI32:
|
||||
return "i32";
|
||||
case NumLitI64:
|
||||
return "i64";
|
||||
case NumLitCount:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
bool is_num_lit_unsigned(NumLit num_lit) {
|
||||
switch (num_lit) {
|
||||
case NumLitF32:
|
||||
case NumLitF64:
|
||||
case NumLitF128:
|
||||
case NumLitI8:
|
||||
case NumLitI16:
|
||||
case NumLitI32:
|
||||
case NumLitI64:
|
||||
return false;
|
||||
case NumLitU8:
|
||||
case NumLitU16:
|
||||
case NumLitU32:
|
||||
case NumLitU64:
|
||||
return true;
|
||||
case NumLitCount:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
bool is_num_lit_float(NumLit num_lit) {
|
||||
switch (num_lit) {
|
||||
case NumLitF32:
|
||||
case NumLitF64:
|
||||
case NumLitF128:
|
||||
return true;
|
||||
case NumLitU8:
|
||||
case NumLitU16:
|
||||
case NumLitU32:
|
||||
case NumLitU64:
|
||||
case NumLitI8:
|
||||
case NumLitI16:
|
||||
case NumLitI32:
|
||||
case NumLitI64:
|
||||
return false;
|
||||
case NumLitCount:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
uint64_t num_lit_bit_count(NumLit num_lit) {
|
||||
switch (num_lit) {
|
||||
case NumLitU8:
|
||||
case NumLitI8:
|
||||
return 8;
|
||||
case NumLitU16:
|
||||
case NumLitI16:
|
||||
return 16;
|
||||
case NumLitU32:
|
||||
case NumLitI32:
|
||||
case NumLitF32:
|
||||
return 32;
|
||||
case NumLitU64:
|
||||
case NumLitI64:
|
||||
case NumLitF64:
|
||||
return 64;
|
||||
case NumLitF128:
|
||||
return 128;
|
||||
case NumLitCount:
|
||||
zig_unreachable();
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
|
|
@ -24,10 +24,4 @@ const char *node_type_str(NodeType node_type);
|
|||
|
||||
void ast_print(AstNode *node, int indent);
|
||||
|
||||
const char *num_lit_str(NumLit num_lit);
|
||||
bool is_num_lit_unsigned(NumLit num_lit);
|
||||
bool is_num_lit_float(NumLit num_lit);
|
||||
uint64_t num_lit_bit_count(NumLit num_lit);
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -34,7 +34,7 @@ pub %.BadPerm;
|
|||
pub %.PipeFail;
|
||||
*/
|
||||
|
||||
const buffer_size: u16 = 4 * 1024;
|
||||
//const buffer_size: u16 = 4 * 1024;
|
||||
const max_u64_base10_digits: isize = 20;
|
||||
|
||||
/*
|
||||
|
|
|
@ -1323,7 +1323,7 @@ fn f() i32 => {
|
|||
fn f() => {
|
||||
if (0) {}
|
||||
}
|
||||
)SOURCE", 1, ".tmp_source.zig:3:9: error: expected type 'bool', got '(u8 literal)'");
|
||||
)SOURCE", 1, ".tmp_source.zig:3:9: error: value 0 cannot be represented in type 'bool'");
|
||||
|
||||
add_compile_fail_case("assign unreachable", R"SOURCE(
|
||||
fn f() => {
|
||||
|
|
Loading…
Reference in New Issue