Commit 32e2196257
Changed files (11)
src/all_types.hpp
@@ -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;
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;
+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)
+ {
+ if (bignum_fits_in_bits(&const_val->data.x_bignum, other_type->size_in_bits,
+ other_type->data.integral.is_signed))
+ {
+ expr->resolved_type = other_type;
+ return true;
+ }
+ } else if (other_type->id == TypeTableEntryIdNumLitFloat ||
+ other_type->id == TypeTableEntryIdNumLitInt)
+ {
+ return true;
}
- 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;
- }
+ 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 * resolve_number_literals(CodeGen *g, AstNode *node1, AstNode *node2,
- TypeTableEntry *type1, TypeTableEntry *type2)
+static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *parent_source_node,
+ AstNode **child_nodes, TypeTableEntry **child_types, int child_count)
{
- if (type1->id == TypeTableEntryIdNumberLiteral &&
- type2->id == TypeTableEntryIdNumberLiteral)
- {
- 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))
+ 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)
{
- 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))
+ 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)
{
- 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;
+ 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 {
- return nullptr;
- }
- } 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);
- }
-}
+ add_node_error(g, parent_source_node,
+ buf_sprintf("incompatible types: '%s' and '%s'",
+ buf_ptr(&prev_type->name), buf_ptr(&cur_type->name)));
-static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *node,
- TypeTableEntry *type1, TypeTableEntry *type2, AstNode *node1, AstNode *node2)
-{
- 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;
+ return g->builtin_types.entry_invalid;
+ }
}
-
- 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 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:
src/analyze.hpp
@@ -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);
src/bignum.cpp
@@ -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;
+ }
+}
src/bignum.hpp
@@ -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);
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;
- 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->ok);
+ if (type_entry->id == TypeTableEntryIdInt) {
+ 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) {
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();
-}
src/parser.hpp
@@ -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
std/std.zig
@@ -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;
/*
test/run_tests.cpp
@@ -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() => {
CMakeLists.txt
@@ -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"