explicit wrapping integer operations
instead of wrapping integer types closes #159
This commit is contained in:
parent
3eb5afd245
commit
8552d7fd19
@ -69,7 +69,7 @@ UnwrapError = "%%" option("|" "Symbol" "|") Expression
|
||||
|
||||
AssignmentExpression = UnwrapExpression AssignmentOperator UnwrapExpression | UnwrapExpression
|
||||
|
||||
AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "&&=" | "||="
|
||||
AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "&&=" | "||=" | "*%=" | "+%=" | "-%=" | "<<%="
|
||||
|
||||
BlockExpression = IfExpression | Block | WhileExpression | ForExpression | SwitchExpression
|
||||
|
||||
@ -111,17 +111,17 @@ BinaryAndExpression = BitShiftExpression "&" BinaryAndExpression | BitShiftExpre
|
||||
|
||||
BitShiftExpression = AdditionExpression BitShiftOperator BitShiftExpression | AdditionExpression
|
||||
|
||||
BitShiftOperator = "<<" | ">>"
|
||||
BitShiftOperator = "<<" | ">>" | "<<%"
|
||||
|
||||
AdditionExpression = MultiplyExpression AdditionOperator AdditionExpression | MultiplyExpression
|
||||
|
||||
AdditionOperator = "+" | "-" | "++"
|
||||
AdditionOperator = "+" | "-" | "++" | "+%" | "-%"
|
||||
|
||||
MultiplyExpression = CurlySuffixExpression MultiplyOperator MultiplyExpression | CurlySuffixExpression
|
||||
|
||||
CurlySuffixExpression = TypeExpr option(ContainerInitExpression)
|
||||
|
||||
MultiplyOperator = "*" | "/" | "%" | "**"
|
||||
MultiplyOperator = "*" | "/" | "%" | "**" | "*%"
|
||||
|
||||
PrefixOpExpression = PrefixOp PrefixOpExpression | SuffixOpExpression
|
||||
|
||||
@ -141,7 +141,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")
|
||||
|
||||
StructLiteralField = "." "Symbol" "=" Expression
|
||||
|
||||
PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | "??"
|
||||
PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | "??" | "-%"
|
||||
|
||||
PrimaryExpression = "Number" | "String" | "CharLiteral" | KeywordLiteral | GroupedExpression | GotoExpression | BlockExpression | "Symbol" | ("@" "Symbol" FnCallExpression) | ArrayType | (option("extern") FnProto) | AsmExpression | ("error" "." "Symbol")
|
||||
|
||||
@ -181,26 +181,15 @@ x{}
|
||||
Type name C equivalent Description
|
||||
|
||||
i8 int8_t signed 8-bit integer
|
||||
u8 (none) unsigned 8-bit integer
|
||||
u8 uint8_t unsigned 8-bit integer
|
||||
i16 int16_t signed 16-bit integer
|
||||
u16 (none) unsigned 16-bit integer
|
||||
u16 uint16_t unsigned 16-bit integer
|
||||
i32 int32_t signed 32-bit integer
|
||||
u32 (none) unsigned 32-bit integer
|
||||
u32 uint32_t unsigned 32-bit integer
|
||||
i64 int64_t signed 64-bit integer
|
||||
u64 (none) unsigned 64-bit integer
|
||||
u64 uint64_t unsigned 64-bit integer
|
||||
isize intptr_t signed pointer sized integer
|
||||
usize (none) unsigned pointer sized integer
|
||||
|
||||
i8w (none) wrapping signed 8-bit integer
|
||||
u8w uint8_t wrapping unsigned 8-bit integer
|
||||
i16w (none) wrapping signed 16-bit integer
|
||||
u16w uint16_t wrapping unsigned 16-bit integer
|
||||
i32w (none) wrapping signed 32-bit integer
|
||||
u32w uint32_t wrapping unsigned 32-bit integer
|
||||
i64w (none) wrapping signed 64-bit integer
|
||||
u64w uint64_t wrapping unsigned 64-bit integer
|
||||
isizew (none) wrapping signed pointer sized integer
|
||||
usizew uintptr_t wrapping unsigned pointer sized integer
|
||||
usize uintptr_t unsigned pointer sized integer
|
||||
|
||||
c_short short for ABI compatibility with C
|
||||
c_ushort unsigned short for ABI compatibility with C
|
||||
@ -213,8 +202,8 @@ c_ulonglong unsigned long long for ABI compatibility with C
|
||||
c_long_double long double for ABI compatibility with C
|
||||
c_void void for ABI compatibility with C
|
||||
|
||||
f32 float 32-bit IEE754 floating point
|
||||
f64 double 64-bit IEE754 floating point
|
||||
f32 float 32-bit floating point
|
||||
f64 double 64-bit floating point
|
||||
```
|
||||
|
||||
### Boolean Type
|
||||
@ -595,9 +584,8 @@ const b: u8 = @truncate(u8, a);
|
||||
This function, when semantically analyzed, causes a compile error with the message `msg`.
|
||||
|
||||
There are several ways that code avoids being semantically checked, such as using `if`
|
||||
or `switch` with compile variables, and inline functions.
|
||||
or `switch` with compile time constants, and inline functions.
|
||||
|
||||
### @int_type(inline is_signed: bool, inline bit_count: u8, inline is_wrapping: bool) -> type
|
||||
### @int_type(inline is_signed: bool, inline bit_count: u8) -> type
|
||||
|
||||
This function returns an integer type with the given signness, bit count, and
|
||||
wrapping behavior.
|
||||
This function returns an integer type with the given signness and bit count.
|
||||
|
@ -17,7 +17,6 @@ syn keyword zigConstant null undefined
|
||||
syn keyword zigKeyword fn use
|
||||
syn keyword zigType bool f32 f64 void unreachable type error
|
||||
syn keyword zigType i8 u8 i16 u16 i32 u32 i64 u64 isize usize
|
||||
syn keyword zigType i8w u8w i16w u16w i32w u32w i64w u64w isizew usizew
|
||||
syn keyword zigType c_short c_ushort c_int c_uint c_long c_ulong c_longlong c_ulonglong
|
||||
|
||||
syn keyword zigBoolean true false
|
||||
|
@ -315,11 +315,15 @@ enum BinOpType {
|
||||
BinOpTypeInvalid,
|
||||
BinOpTypeAssign,
|
||||
BinOpTypeAssignTimes,
|
||||
BinOpTypeAssignTimesWrap,
|
||||
BinOpTypeAssignDiv,
|
||||
BinOpTypeAssignMod,
|
||||
BinOpTypeAssignPlus,
|
||||
BinOpTypeAssignPlusWrap,
|
||||
BinOpTypeAssignMinus,
|
||||
BinOpTypeAssignMinusWrap,
|
||||
BinOpTypeAssignBitShiftLeft,
|
||||
BinOpTypeAssignBitShiftLeftWrap,
|
||||
BinOpTypeAssignBitShiftRight,
|
||||
BinOpTypeAssignBitAnd,
|
||||
BinOpTypeAssignBitXor,
|
||||
@ -338,10 +342,14 @@ enum BinOpType {
|
||||
BinOpTypeBinXor,
|
||||
BinOpTypeBinAnd,
|
||||
BinOpTypeBitShiftLeft,
|
||||
BinOpTypeBitShiftLeftWrap,
|
||||
BinOpTypeBitShiftRight,
|
||||
BinOpTypeAdd,
|
||||
BinOpTypeAddWrap,
|
||||
BinOpTypeSub,
|
||||
BinOpTypeSubWrap,
|
||||
BinOpTypeMult,
|
||||
BinOpTypeMultWrap,
|
||||
BinOpTypeDiv,
|
||||
BinOpTypeMod,
|
||||
BinOpTypeUnwrapMaybe,
|
||||
@ -449,6 +457,7 @@ enum PrefixOp {
|
||||
PrefixOpBoolNot,
|
||||
PrefixOpBinNot,
|
||||
PrefixOpNegation,
|
||||
PrefixOpNegationWrap,
|
||||
PrefixOpAddressOf,
|
||||
PrefixOpConstAddressOf,
|
||||
PrefixOpDereference,
|
||||
@ -860,7 +869,6 @@ struct TypeTableEntryPointer {
|
||||
struct TypeTableEntryInt {
|
||||
int bit_count;
|
||||
bool is_signed;
|
||||
bool is_wrapping;
|
||||
};
|
||||
|
||||
struct TypeTableEntryFloat {
|
||||
@ -1185,7 +1193,7 @@ struct CodeGen {
|
||||
|
||||
struct {
|
||||
TypeTableEntry *entry_bool;
|
||||
TypeTableEntry *entry_int[2][2][4]; // [signed,unsigned][wrapping,nonwrapping][8,16,32,64]
|
||||
TypeTableEntry *entry_int[2][4]; // [signed,unsigned][8,16,32,64]
|
||||
TypeTableEntry *entry_c_int[CIntTypeCount];
|
||||
TypeTableEntry *entry_c_long_double;
|
||||
TypeTableEntry *entry_c_void;
|
||||
|
@ -245,7 +245,7 @@ static bool is_slice(TypeTableEntry *type) {
|
||||
}
|
||||
|
||||
TypeTableEntry *get_smallest_unsigned_int_type(CodeGen *g, uint64_t x) {
|
||||
return get_int_type(g, false, false, bits_needed_for_unsigned(x));
|
||||
return get_int_type(g, false, bits_needed_for_unsigned(x));
|
||||
}
|
||||
|
||||
static TypeTableEntry *get_generic_fn_type(CodeGen *g, AstNode *decl_node) {
|
||||
@ -2037,25 +2037,13 @@ static TypeTableEntry *determine_peer_type_compatibility(CodeGen *g, AstNode *pa
|
||||
continue;
|
||||
} else if (prev_type->id == TypeTableEntryIdInt &&
|
||||
cur_type->id == TypeTableEntryIdInt &&
|
||||
prev_type->data.integral.is_signed == cur_type->data.integral.is_signed &&
|
||||
(cur_type->data.integral.bit_count >= prev_type->data.integral.bit_count &&
|
||||
(cur_type->data.integral.is_wrapping || !prev_type->data.integral.is_wrapping)))
|
||||
prev_type->data.integral.is_signed == cur_type->data.integral.is_signed)
|
||||
{
|
||||
if (cur_type->data.integral.bit_count > prev_type->data.integral.bit_count) {
|
||||
prev_type = cur_type;
|
||||
prev_node = cur_node;
|
||||
} else if (cur_type->data.integral.is_wrapping && !prev_type->data.integral.is_wrapping) {
|
||||
prev_type = cur_type;
|
||||
prev_node = cur_node;
|
||||
}
|
||||
continue;
|
||||
} else if (prev_type->id == TypeTableEntryIdInt &&
|
||||
cur_type->id == TypeTableEntryIdInt &&
|
||||
prev_type->data.integral.is_signed == cur_type->data.integral.is_signed &&
|
||||
(prev_type->data.integral.bit_count >= cur_type->data.integral.bit_count &&
|
||||
(prev_type->data.integral.is_wrapping || !cur_type->data.integral.is_wrapping)))
|
||||
{
|
||||
continue;
|
||||
} else if (prev_type->id == TypeTableEntryIdFloat &&
|
||||
cur_type->id == TypeTableEntryIdFloat)
|
||||
{
|
||||
@ -2726,9 +2714,6 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
|
||||
} else if (buf_eql_str(field_name, "is_signed")) {
|
||||
return resolve_expr_const_val_as_bool(g, node, child_type->data.integral.is_signed,
|
||||
depends_on_compile_var);
|
||||
} else if (buf_eql_str(field_name, "is_wrapping")) {
|
||||
return resolve_expr_const_val_as_bool(g, node, child_type->data.integral.is_wrapping,
|
||||
depends_on_compile_var);
|
||||
} else {
|
||||
add_node_error(g, node,
|
||||
buf_sprintf("type '%s' has no member called '%s'",
|
||||
@ -3122,15 +3107,19 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {
|
||||
case BinOpTypeAssign:
|
||||
return true;
|
||||
case BinOpTypeAssignTimes:
|
||||
case BinOpTypeAssignTimesWrap:
|
||||
case BinOpTypeAssignDiv:
|
||||
case BinOpTypeAssignMod:
|
||||
return type->id == TypeTableEntryIdInt || type->id == TypeTableEntryIdFloat;
|
||||
case BinOpTypeAssignPlus:
|
||||
case BinOpTypeAssignPlusWrap:
|
||||
case BinOpTypeAssignMinus:
|
||||
case BinOpTypeAssignMinusWrap:
|
||||
return type->id == TypeTableEntryIdInt ||
|
||||
type->id == TypeTableEntryIdFloat ||
|
||||
type->id == TypeTableEntryIdPointer;
|
||||
case BinOpTypeAssignBitShiftLeft:
|
||||
case BinOpTypeAssignBitShiftLeftWrap:
|
||||
case BinOpTypeAssignBitShiftRight:
|
||||
case BinOpTypeAssignBitAnd:
|
||||
case BinOpTypeAssignBitXor:
|
||||
@ -3153,10 +3142,14 @@ static bool is_op_allowed(TypeTableEntry *type, BinOpType op) {
|
||||
case BinOpTypeBinXor:
|
||||
case BinOpTypeBinAnd:
|
||||
case BinOpTypeBitShiftLeft:
|
||||
case BinOpTypeBitShiftLeftWrap:
|
||||
case BinOpTypeBitShiftRight:
|
||||
case BinOpTypeAdd:
|
||||
case BinOpTypeAddWrap:
|
||||
case BinOpTypeSub:
|
||||
case BinOpTypeSubWrap:
|
||||
case BinOpTypeMult:
|
||||
case BinOpTypeMultWrap:
|
||||
case BinOpTypeDiv:
|
||||
case BinOpTypeMod:
|
||||
case BinOpTypeUnwrapMaybe:
|
||||
@ -3437,11 +3430,15 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
|
||||
switch (bin_op_type) {
|
||||
case BinOpTypeAssign:
|
||||
case BinOpTypeAssignTimes:
|
||||
case BinOpTypeAssignTimesWrap:
|
||||
case BinOpTypeAssignDiv:
|
||||
case BinOpTypeAssignMod:
|
||||
case BinOpTypeAssignPlus:
|
||||
case BinOpTypeAssignPlusWrap:
|
||||
case BinOpTypeAssignMinus:
|
||||
case BinOpTypeAssignMinusWrap:
|
||||
case BinOpTypeAssignBitShiftLeft:
|
||||
case BinOpTypeAssignBitShiftLeftWrap:
|
||||
case BinOpTypeAssignBitShiftRight:
|
||||
case BinOpTypeAssignBitAnd:
|
||||
case BinOpTypeAssignBitXor:
|
||||
@ -3481,10 +3478,14 @@ static TypeTableEntry *analyze_bin_op_expr(CodeGen *g, ImportTableEntry *import,
|
||||
case BinOpTypeBinXor:
|
||||
case BinOpTypeBinAnd:
|
||||
case BinOpTypeBitShiftLeft:
|
||||
case BinOpTypeBitShiftLeftWrap:
|
||||
case BinOpTypeBitShiftRight:
|
||||
case BinOpTypeAdd:
|
||||
case BinOpTypeAddWrap:
|
||||
case BinOpTypeSub:
|
||||
case BinOpTypeSubWrap:
|
||||
case BinOpTypeMult:
|
||||
case BinOpTypeMultWrap:
|
||||
case BinOpTypeDiv:
|
||||
case BinOpTypeMod:
|
||||
{
|
||||
@ -4911,42 +4912,35 @@ static TypeTableEntry *analyze_int_type(CodeGen *g, ImportTableEntry *import,
|
||||
{
|
||||
AstNode **is_signed_node = &node->data.fn_call_expr.params.at(0);
|
||||
AstNode **bit_count_node = &node->data.fn_call_expr.params.at(1);
|
||||
AstNode **is_wrap_node = &node->data.fn_call_expr.params.at(2);
|
||||
|
||||
TypeTableEntry *bool_type = g->builtin_types.entry_bool;
|
||||
TypeTableEntry *usize_type = g->builtin_types.entry_usize;
|
||||
TypeTableEntry *is_signed_type = analyze_expression(g, import, context, bool_type, *is_signed_node);
|
||||
TypeTableEntry *bit_count_type = analyze_expression(g, import, context, usize_type, *bit_count_node);
|
||||
TypeTableEntry *is_wrap_type = analyze_expression(g, import, context, bool_type, *is_wrap_node);
|
||||
|
||||
if (is_signed_type->id == TypeTableEntryIdInvalid ||
|
||||
bit_count_type->id == TypeTableEntryIdInvalid ||
|
||||
is_wrap_type->id == TypeTableEntryIdInvalid)
|
||||
bit_count_type->id == TypeTableEntryIdInvalid)
|
||||
{
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
ConstExprValue *is_signed_val = &get_resolved_expr(*is_signed_node)->const_val;
|
||||
ConstExprValue *bit_count_val = &get_resolved_expr(*bit_count_node)->const_val;
|
||||
ConstExprValue *is_wrap_val = &get_resolved_expr(*is_wrap_node)->const_val;
|
||||
|
||||
AstNode *bad_node = nullptr;
|
||||
if (!is_signed_val->ok) {
|
||||
bad_node = *is_signed_node;
|
||||
} else if (!bit_count_val->ok) {
|
||||
bad_node = *bit_count_node;
|
||||
} else if (!is_wrap_val->ok) {
|
||||
bad_node = *is_wrap_node;
|
||||
}
|
||||
if (bad_node) {
|
||||
add_node_error(g, bad_node, buf_sprintf("unable to evaluate constant expression"));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
|
||||
bool depends_on_compile_var = is_signed_val->depends_on_compile_var ||
|
||||
bit_count_val->depends_on_compile_var || is_wrap_val->depends_on_compile_var;
|
||||
bool depends_on_compile_var = is_signed_val->depends_on_compile_var || bit_count_val->depends_on_compile_var;
|
||||
|
||||
TypeTableEntry *int_type = get_int_type(g, is_signed_val->data.x_bool, is_wrap_val->data.x_bool,
|
||||
TypeTableEntry *int_type = get_int_type(g, is_signed_val->data.x_bool,
|
||||
bit_count_val->data.x_bignum.data.x_uint);
|
||||
return resolve_expr_const_val_as_type(g, node, int_type, depends_on_compile_var);
|
||||
|
||||
@ -5727,15 +5721,17 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
|
||||
// TODO const expr eval
|
||||
}
|
||||
case PrefixOpNegation:
|
||||
case PrefixOpNegationWrap:
|
||||
{
|
||||
TypeTableEntry *expr_type = analyze_expression(g, import, context, nullptr, *expr_node);
|
||||
if (expr_type->id == TypeTableEntryIdInvalid) {
|
||||
return expr_type;
|
||||
} else if ((expr_type->id == TypeTableEntryIdInt &&
|
||||
expr_type->data.integral.is_signed) ||
|
||||
expr_type->id == TypeTableEntryIdFloat ||
|
||||
expr_type->id == TypeTableEntryIdNumLitInt ||
|
||||
expr_type->id == TypeTableEntryIdNumLitFloat)
|
||||
((expr_type->id == TypeTableEntryIdFloat ||
|
||||
expr_type->id == TypeTableEntryIdNumLitFloat) &&
|
||||
prefix_op != PrefixOpNegationWrap))
|
||||
{
|
||||
ConstExprValue *target_const_val = &get_resolved_expr(*expr_node)->const_val;
|
||||
if (!target_const_val->ok) {
|
||||
@ -5745,10 +5741,28 @@ static TypeTableEntry *analyze_prefix_op_expr(CodeGen *g, ImportTableEntry *impo
|
||||
const_val->ok = true;
|
||||
const_val->depends_on_compile_var = target_const_val->depends_on_compile_var;
|
||||
bignum_negate(&const_val->data.x_bignum, &target_const_val->data.x_bignum);
|
||||
if (expr_type->id == TypeTableEntryIdFloat ||
|
||||
expr_type->id == TypeTableEntryIdNumLitFloat ||
|
||||
expr_type->id == TypeTableEntryIdNumLitInt)
|
||||
{
|
||||
return expr_type;
|
||||
}
|
||||
|
||||
bool overflow = !bignum_fits_in_bits(&const_val->data.x_bignum,
|
||||
expr_type->data.integral.bit_count, expr_type->data.integral.is_signed);
|
||||
if (prefix_op == PrefixOpNegationWrap) {
|
||||
if (overflow) {
|
||||
const_val->data.x_bignum.is_negative = true;
|
||||
}
|
||||
} else if (overflow) {
|
||||
add_node_error(g, *expr_node, buf_sprintf("negation caused overflow"));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
return expr_type;
|
||||
} else {
|
||||
add_node_error(g, node, buf_sprintf("invalid negation type: '%s'",
|
||||
buf_ptr(&expr_type->name)));
|
||||
const char *fmt = (prefix_op == PrefixOpNegationWrap) ?
|
||||
"invalid wrapping negation type: '%s'" : "invalid negation type: '%s'";
|
||||
add_node_error(g, node, buf_sprintf(fmt, buf_ptr(&expr_type->name)));
|
||||
return g->builtin_types.entry_invalid;
|
||||
}
|
||||
}
|
||||
@ -7059,7 +7073,7 @@ bool is_node_void_expr(AstNode *node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, bool is_wrapping, int size_in_bits) {
|
||||
TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits) {
|
||||
int index;
|
||||
if (size_in_bits == 8) {
|
||||
index = 0;
|
||||
@ -7072,11 +7086,11 @@ TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, bool is_wrapping,
|
||||
} else {
|
||||
zig_unreachable();
|
||||
}
|
||||
return &g->builtin_types.entry_int[is_signed ? 0 : 1][is_wrapping ? 0 : 1][index];
|
||||
return &g->builtin_types.entry_int[is_signed ? 0 : 1][index];
|
||||
}
|
||||
|
||||
TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, bool is_wrapping, int size_in_bits) {
|
||||
return *get_int_type_ptr(g, is_signed, is_wrapping, size_in_bits);
|
||||
TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits) {
|
||||
return *get_int_type_ptr(g, is_signed, size_in_bits);
|
||||
}
|
||||
|
||||
TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type) {
|
||||
|
@ -19,8 +19,8 @@ BlockContext *new_block_context(AstNode *node, BlockContext *parent);
|
||||
Expr *get_resolved_expr(AstNode *node);
|
||||
bool is_node_void_expr(AstNode *node);
|
||||
uint64_t type_size(CodeGen *g, TypeTableEntry *type_entry);
|
||||
TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, bool is_wrapping, int size_in_bits);
|
||||
TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, bool is_wrapping, int size_in_bits);
|
||||
TypeTableEntry **get_int_type_ptr(CodeGen *g, bool is_signed, int size_in_bits);
|
||||
TypeTableEntry *get_int_type(CodeGen *g, bool is_signed, int size_in_bits);
|
||||
TypeTableEntry **get_c_int_type_ptr(CodeGen *g, CIntType c_int_type);
|
||||
TypeTableEntry *get_c_int_type(CodeGen *g, CIntType c_int_type);
|
||||
TypeTableEntry *get_typedecl_type(CodeGen *g, const char *name, TypeTableEntry *child_type);
|
||||
|
@ -4,41 +4,49 @@
|
||||
|
||||
static const char *bin_op_str(BinOpType bin_op) {
|
||||
switch (bin_op) {
|
||||
case BinOpTypeInvalid: return "(invalid)";
|
||||
case BinOpTypeBoolOr: return "||";
|
||||
case BinOpTypeBoolAnd: return "&&";
|
||||
case BinOpTypeCmpEq: return "==";
|
||||
case BinOpTypeCmpNotEq: return "!=";
|
||||
case BinOpTypeCmpLessThan: return "<";
|
||||
case BinOpTypeCmpGreaterThan: return ">";
|
||||
case BinOpTypeCmpLessOrEq: return "<=";
|
||||
case BinOpTypeCmpGreaterOrEq: return ">=";
|
||||
case BinOpTypeBinOr: return "|";
|
||||
case BinOpTypeBinXor: return "^";
|
||||
case BinOpTypeBinAnd: return "&";
|
||||
case BinOpTypeBitShiftLeft: return "<<";
|
||||
case BinOpTypeBitShiftRight: return ">>";
|
||||
case BinOpTypeAdd: return "+";
|
||||
case BinOpTypeSub: return "-";
|
||||
case BinOpTypeMult: return "*";
|
||||
case BinOpTypeDiv: return "/";
|
||||
case BinOpTypeMod: return "%";
|
||||
case BinOpTypeAssign: return "=";
|
||||
case BinOpTypeAssignTimes: return "*=";
|
||||
case BinOpTypeAssignDiv: return "/=";
|
||||
case BinOpTypeAssignMod: return "%=";
|
||||
case BinOpTypeAssignPlus: return "+=";
|
||||
case BinOpTypeAssignMinus: return "-=";
|
||||
case BinOpTypeAssignBitShiftLeft: return "<<=";
|
||||
case BinOpTypeAssignBitShiftRight: return ">>=";
|
||||
case BinOpTypeAssignBitAnd: return "&=";
|
||||
case BinOpTypeAssignBitXor: return "^=";
|
||||
case BinOpTypeAssignBitOr: return "|=";
|
||||
case BinOpTypeAssignBoolAnd: return "&&=";
|
||||
case BinOpTypeAssignBoolOr: return "||=";
|
||||
case BinOpTypeUnwrapMaybe: return "??";
|
||||
case BinOpTypeArrayCat: return "++";
|
||||
case BinOpTypeArrayMult: return "**";
|
||||
case BinOpTypeInvalid: return "(invalid)";
|
||||
case BinOpTypeBoolOr: return "||";
|
||||
case BinOpTypeBoolAnd: return "&&";
|
||||
case BinOpTypeCmpEq: return "==";
|
||||
case BinOpTypeCmpNotEq: return "!=";
|
||||
case BinOpTypeCmpLessThan: return "<";
|
||||
case BinOpTypeCmpGreaterThan: return ">";
|
||||
case BinOpTypeCmpLessOrEq: return "<=";
|
||||
case BinOpTypeCmpGreaterOrEq: return ">=";
|
||||
case BinOpTypeBinOr: return "|";
|
||||
case BinOpTypeBinXor: return "^";
|
||||
case BinOpTypeBinAnd: return "&";
|
||||
case BinOpTypeBitShiftLeft: return "<<";
|
||||
case BinOpTypeBitShiftLeftWrap: return "<<%";
|
||||
case BinOpTypeBitShiftRight: return ">>";
|
||||
case BinOpTypeAdd: return "+";
|
||||
case BinOpTypeAddWrap: return "+%";
|
||||
case BinOpTypeSub: return "-";
|
||||
case BinOpTypeSubWrap: return "-%";
|
||||
case BinOpTypeMult: return "*";
|
||||
case BinOpTypeMultWrap: return "*%";
|
||||
case BinOpTypeDiv: return "/";
|
||||
case BinOpTypeMod: return "%";
|
||||
case BinOpTypeAssign: return "=";
|
||||
case BinOpTypeAssignTimes: return "*=";
|
||||
case BinOpTypeAssignTimesWrap: return "*%=";
|
||||
case BinOpTypeAssignDiv: return "/=";
|
||||
case BinOpTypeAssignMod: return "%=";
|
||||
case BinOpTypeAssignPlus: return "+=";
|
||||
case BinOpTypeAssignPlusWrap: return "+%=";
|
||||
case BinOpTypeAssignMinus: return "-=";
|
||||
case BinOpTypeAssignMinusWrap: return "-%=";
|
||||
case BinOpTypeAssignBitShiftLeft: return "<<=";
|
||||
case BinOpTypeAssignBitShiftLeftWrap: return "<<%=";
|
||||
case BinOpTypeAssignBitShiftRight: return ">>=";
|
||||
case BinOpTypeAssignBitAnd: return "&=";
|
||||
case BinOpTypeAssignBitXor: return "^=";
|
||||
case BinOpTypeAssignBitOr: return "|=";
|
||||
case BinOpTypeAssignBoolAnd: return "&&=";
|
||||
case BinOpTypeAssignBoolOr: return "||=";
|
||||
case BinOpTypeUnwrapMaybe: return "??";
|
||||
case BinOpTypeArrayCat: return "++";
|
||||
case BinOpTypeArrayMult: return "**";
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
@ -47,6 +55,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
|
||||
switch (prefix_op) {
|
||||
case PrefixOpInvalid: return "(invalid)";
|
||||
case PrefixOpNegation: return "-";
|
||||
case PrefixOpNegationWrap: return "-%";
|
||||
case PrefixOpBoolNot: return "!";
|
||||
case PrefixOpBinNot: return "~";
|
||||
case PrefixOpAddressOf: return "&";
|
||||
|
111
src/codegen.cpp
111
src/codegen.cpp
@ -1564,17 +1564,20 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
|
||||
AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
|
||||
TypeTableEntry *expr_type = get_expr_type(expr_node);
|
||||
|
||||
switch (node->data.prefix_op_expr.prefix_op) {
|
||||
PrefixOp op = node->data.prefix_op_expr.prefix_op;
|
||||
|
||||
switch (op) {
|
||||
case PrefixOpInvalid:
|
||||
zig_unreachable();
|
||||
case PrefixOpNegation:
|
||||
case PrefixOpNegationWrap:
|
||||
{
|
||||
LLVMValueRef expr = gen_expr(g, expr_node);
|
||||
set_debug_source_node(g, node);
|
||||
if (expr_type->id == TypeTableEntryIdFloat) {
|
||||
return LLVMBuildFNeg(g->builder, expr, "");
|
||||
} else if (expr_type->id == TypeTableEntryIdInt) {
|
||||
if (expr_type->data.integral.is_wrapping) {
|
||||
if (op == PrefixOpNegationWrap) {
|
||||
return LLVMBuildNeg(g->builder, expr, "");
|
||||
} else if (want_debug_safety(g, expr_node)) {
|
||||
LLVMValueRef zero = LLVMConstNull(LLVMTypeOf(expr));
|
||||
@ -1796,17 +1799,23 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
|
||||
set_debug_source_node(g, source_node);
|
||||
return LLVMBuildAnd(g->builder, val1, val2, "");
|
||||
case BinOpTypeBitShiftLeft:
|
||||
case BinOpTypeBitShiftLeftWrap:
|
||||
case BinOpTypeAssignBitShiftLeft:
|
||||
set_debug_source_node(g, source_node);
|
||||
assert(op1_type->id == TypeTableEntryIdInt);
|
||||
if (op1_type->data.integral.is_wrapping) {
|
||||
return LLVMBuildShl(g->builder, val1, val2, "");
|
||||
} else if (want_debug_safety(g, source_node)) {
|
||||
return gen_overflow_shl_op(g, op1_type, val1, val2);
|
||||
} else if (op1_type->data.integral.is_signed) {
|
||||
return ZigLLVMBuildNSWShl(g->builder, val1, val2, "");
|
||||
} else {
|
||||
return ZigLLVMBuildNUWShl(g->builder, val1, val2, "");
|
||||
case BinOpTypeAssignBitShiftLeftWrap:
|
||||
{
|
||||
set_debug_source_node(g, source_node);
|
||||
assert(op1_type->id == TypeTableEntryIdInt);
|
||||
bool is_wrapping = (bin_op == BinOpTypeBitShiftLeftWrap) ||
|
||||
(bin_op == BinOpTypeAssignBitShiftLeftWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildShl(g->builder, val1, val2, "");
|
||||
} else if (want_debug_safety(g, source_node)) {
|
||||
return gen_overflow_shl_op(g, op1_type, val1, val2);
|
||||
} else if (op1_type->data.integral.is_signed) {
|
||||
return ZigLLVMBuildNSWShl(g->builder, val1, val2, "");
|
||||
} else {
|
||||
return ZigLLVMBuildNUWShl(g->builder, val1, val2, "");
|
||||
}
|
||||
}
|
||||
case BinOpTypeBitShiftRight:
|
||||
case BinOpTypeAssignBitShiftRight:
|
||||
@ -1820,12 +1829,15 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
|
||||
return LLVMBuildLShr(g->builder, val1, val2, "");
|
||||
}
|
||||
case BinOpTypeAdd:
|
||||
case BinOpTypeAddWrap:
|
||||
case BinOpTypeAssignPlus:
|
||||
case BinOpTypeAssignPlusWrap:
|
||||
set_debug_source_node(g, source_node);
|
||||
if (op1_type->id == TypeTableEntryIdFloat) {
|
||||
return LLVMBuildFAdd(g->builder, val1, val2, "");
|
||||
} else if (op1_type->id == TypeTableEntryIdInt) {
|
||||
if (op1_type->data.integral.is_wrapping) {
|
||||
bool is_wrapping = (bin_op == BinOpTypeAddWrap) || (bin_op == BinOpTypeAssignPlusWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildAdd(g->builder, val1, val2, "");
|
||||
} else if (want_debug_safety(g, source_node)) {
|
||||
return gen_overflow_op(g, op1_type, AddSubMulAdd, val1, val2);
|
||||
@ -1838,12 +1850,15 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
|
||||
zig_unreachable();
|
||||
}
|
||||
case BinOpTypeSub:
|
||||
case BinOpTypeSubWrap:
|
||||
case BinOpTypeAssignMinus:
|
||||
case BinOpTypeAssignMinusWrap:
|
||||
set_debug_source_node(g, source_node);
|
||||
if (op1_type->id == TypeTableEntryIdFloat) {
|
||||
return LLVMBuildFSub(g->builder, val1, val2, "");
|
||||
} else if (op1_type->id == TypeTableEntryIdInt) {
|
||||
if (op1_type->data.integral.is_wrapping) {
|
||||
bool is_wrapping = (bin_op == BinOpTypeSubWrap || bin_op == BinOpTypeAssignMinusWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildSub(g->builder, val1, val2, "");
|
||||
} else if (want_debug_safety(g, source_node)) {
|
||||
return gen_overflow_op(g, op1_type, AddSubMulSub, val1, val2);
|
||||
@ -1856,12 +1871,15 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
|
||||
zig_unreachable();
|
||||
}
|
||||
case BinOpTypeMult:
|
||||
case BinOpTypeMultWrap:
|
||||
case BinOpTypeAssignTimes:
|
||||
case BinOpTypeAssignTimesWrap:
|
||||
set_debug_source_node(g, source_node);
|
||||
if (op1_type->id == TypeTableEntryIdFloat) {
|
||||
return LLVMBuildFMul(g->builder, val1, val2, "");
|
||||
} else if (op1_type->id == TypeTableEntryIdInt) {
|
||||
if (op1_type->data.integral.is_wrapping) {
|
||||
bool is_wrapping = (bin_op == BinOpTypeMultWrap || bin_op == BinOpTypeAssignTimesWrap);
|
||||
if (is_wrapping) {
|
||||
return LLVMBuildMul(g->builder, val1, val2, "");
|
||||
} else if (want_debug_safety(g, source_node)) {
|
||||
return gen_overflow_op(g, op1_type, AddSubMulMul, val1, val2);
|
||||
@ -2214,11 +2232,15 @@ static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
|
||||
zig_unreachable();
|
||||
case BinOpTypeAssign:
|
||||
case BinOpTypeAssignTimes:
|
||||
case BinOpTypeAssignTimesWrap:
|
||||
case BinOpTypeAssignDiv:
|
||||
case BinOpTypeAssignMod:
|
||||
case BinOpTypeAssignPlus:
|
||||
case BinOpTypeAssignPlusWrap:
|
||||
case BinOpTypeAssignMinus:
|
||||
case BinOpTypeAssignMinusWrap:
|
||||
case BinOpTypeAssignBitShiftLeft:
|
||||
case BinOpTypeAssignBitShiftLeftWrap:
|
||||
case BinOpTypeAssignBitShiftRight:
|
||||
case BinOpTypeAssignBitAnd:
|
||||
case BinOpTypeAssignBitXor:
|
||||
@ -2243,10 +2265,14 @@ static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
|
||||
case BinOpTypeBinXor:
|
||||
case BinOpTypeBinAnd:
|
||||
case BinOpTypeBitShiftLeft:
|
||||
case BinOpTypeBitShiftLeftWrap:
|
||||
case BinOpTypeBitShiftRight:
|
||||
case BinOpTypeAdd:
|
||||
case BinOpTypeAddWrap:
|
||||
case BinOpTypeSub:
|
||||
case BinOpTypeSubWrap:
|
||||
case BinOpTypeMult:
|
||||
case BinOpTypeMultWrap:
|
||||
case BinOpTypeDiv:
|
||||
case BinOpTypeMod:
|
||||
return gen_arithmetic_bin_op_expr(g, node);
|
||||
@ -4188,17 +4214,7 @@ static const CIntTypeInfo c_int_type_infos[] = {
|
||||
{CIntTypeULongLong, "c_ulonglong", false},
|
||||
};
|
||||
|
||||
struct SignWrap {
|
||||
bool is_signed;
|
||||
bool is_wrapping;
|
||||
};
|
||||
|
||||
static const SignWrap sign_wrap_list[] = {
|
||||
{false, false},
|
||||
{false, true},
|
||||
{true, false},
|
||||
{true, true},
|
||||
};
|
||||
static const bool is_signed_list[] = { false, true, };
|
||||
|
||||
static void define_builtin_types(CodeGen *g) {
|
||||
{
|
||||
@ -4238,18 +4254,16 @@ static void define_builtin_types(CodeGen *g) {
|
||||
|
||||
for (int int_size_i = 0; int_size_i < array_length(int_sizes_in_bits); int_size_i += 1) {
|
||||
int size_in_bits = int_sizes_in_bits[int_size_i];
|
||||
for (int sign_wrap_i = 0; sign_wrap_i < array_length(sign_wrap_list); sign_wrap_i += 1) {
|
||||
bool is_signed = sign_wrap_list[sign_wrap_i].is_signed;
|
||||
bool is_wrapping = sign_wrap_list[sign_wrap_i].is_wrapping;
|
||||
for (int is_sign_i = 0; is_sign_i < array_length(is_signed_list); is_sign_i += 1) {
|
||||
bool is_signed = is_signed_list[is_sign_i];
|
||||
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
|
||||
entry->type_ref = LLVMIntType(size_in_bits);
|
||||
entry->deep_const = true;
|
||||
|
||||
const char u_or_i = is_signed ? 'i' : 'u';
|
||||
const char *w_or_none = is_wrapping ? "w" : "";
|
||||
buf_resize(&entry->name, 0);
|
||||
buf_appendf(&entry->name, "%c%d%s", u_or_i, size_in_bits, w_or_none);
|
||||
buf_appendf(&entry->name, "%c%d", u_or_i, size_in_bits);
|
||||
|
||||
unsigned dwarf_tag;
|
||||
if (is_signed) {
|
||||
@ -4271,11 +4285,10 @@ static void define_builtin_types(CodeGen *g) {
|
||||
entry->di_type = LLVMZigCreateDebugBasicType(g->dbuilder, buf_ptr(&entry->name),
|
||||
debug_size_in_bits, debug_align_in_bits, dwarf_tag);
|
||||
entry->data.integral.is_signed = is_signed;
|
||||
entry->data.integral.is_wrapping = is_wrapping;
|
||||
entry->data.integral.bit_count = size_in_bits;
|
||||
g->primitive_type_table.put(&entry->name, entry);
|
||||
|
||||
get_int_type_ptr(g, is_signed, is_wrapping, size_in_bits)[0] = entry;
|
||||
get_int_type_ptr(g, is_signed, size_in_bits)[0] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4297,7 +4310,6 @@ static void define_builtin_types(CodeGen *g) {
|
||||
debug_align_in_bits,
|
||||
is_signed ? LLVMZigEncoding_DW_ATE_signed() : LLVMZigEncoding_DW_ATE_unsigned());
|
||||
entry->data.integral.is_signed = is_signed;
|
||||
entry->data.integral.is_wrapping = !is_signed;
|
||||
entry->data.integral.bit_count = size_in_bits;
|
||||
g->primitive_type_table.put(&entry->name, entry);
|
||||
|
||||
@ -4319,21 +4331,18 @@ static void define_builtin_types(CodeGen *g) {
|
||||
g->primitive_type_table.put(&entry->name, entry);
|
||||
}
|
||||
|
||||
for (int sign_wrap_i = 0; sign_wrap_i < array_length(sign_wrap_list); sign_wrap_i += 1) {
|
||||
bool is_signed = sign_wrap_list[sign_wrap_i].is_signed;
|
||||
bool is_wrapping = sign_wrap_list[sign_wrap_i].is_wrapping;
|
||||
for (int sign_i = 0; sign_i < array_length(is_signed_list); sign_i += 1) {
|
||||
bool is_signed = is_signed_list[sign_i];
|
||||
|
||||
TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdInt);
|
||||
entry->deep_const = true;
|
||||
entry->type_ref = LLVMIntType(g->pointer_size_bytes * 8);
|
||||
|
||||
const char u_or_i = is_signed ? 'i' : 'u';
|
||||
const char *w_or_none = is_wrapping ? "w" : "";
|
||||
buf_resize(&entry->name, 0);
|
||||
buf_appendf(&entry->name, "%csize%s", u_or_i, w_or_none);
|
||||
buf_appendf(&entry->name, "%csize", u_or_i);
|
||||
|
||||
entry->data.integral.is_signed = is_signed;
|
||||
entry->data.integral.is_wrapping = is_wrapping;
|
||||
entry->data.integral.bit_count = g->pointer_size_bytes * 8;
|
||||
|
||||
uint64_t debug_size_in_bits = 8*LLVMStoreSizeOfType(g->target_data_ref, entry->type_ref);
|
||||
@ -4344,9 +4353,9 @@ static void define_builtin_types(CodeGen *g) {
|
||||
is_signed ? LLVMZigEncoding_DW_ATE_signed() : LLVMZigEncoding_DW_ATE_unsigned());
|
||||
g->primitive_type_table.put(&entry->name, entry);
|
||||
|
||||
if (is_signed && !is_wrapping) {
|
||||
if (is_signed) {
|
||||
g->builtin_types.entry_isize = entry;
|
||||
} else if (!is_signed && !is_wrapping) {
|
||||
} else {
|
||||
g->builtin_types.entry_usize = entry;
|
||||
}
|
||||
}
|
||||
@ -4430,14 +4439,14 @@ static void define_builtin_types(CodeGen *g) {
|
||||
g->primitive_type_table.put(&entry->name, entry);
|
||||
}
|
||||
|
||||
g->builtin_types.entry_u8 = get_int_type(g, false, false, 8);
|
||||
g->builtin_types.entry_u16 = get_int_type(g, false, false, 16);
|
||||
g->builtin_types.entry_u32 = get_int_type(g, false, false, 32);
|
||||
g->builtin_types.entry_u64 = get_int_type(g, false, false, 64);
|
||||
g->builtin_types.entry_i8 = get_int_type(g, true, false, 8);
|
||||
g->builtin_types.entry_i16 = get_int_type(g, true, false, 16);
|
||||
g->builtin_types.entry_i32 = get_int_type(g, true, false, 32);
|
||||
g->builtin_types.entry_i64 = get_int_type(g, true, false, 64);
|
||||
g->builtin_types.entry_u8 = get_int_type(g, false, 8);
|
||||
g->builtin_types.entry_u16 = get_int_type(g, false, 16);
|
||||
g->builtin_types.entry_u32 = get_int_type(g, false, 32);
|
||||
g->builtin_types.entry_u64 = get_int_type(g, false, 64);
|
||||
g->builtin_types.entry_i8 = get_int_type(g, true, 8);
|
||||
g->builtin_types.entry_i16 = get_int_type(g, true, 16);
|
||||
g->builtin_types.entry_i32 = get_int_type(g, true, 32);
|
||||
g->builtin_types.entry_i64 = get_int_type(g, true, 64);
|
||||
|
||||
{
|
||||
g->builtin_types.entry_c_void = get_typedecl_type(g, "c_void", g->builtin_types.entry_u8);
|
||||
@ -4703,7 +4712,7 @@ static void define_builtin_fns(CodeGen *g) {
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdDivExact, "div_exact", 2);
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdTruncate, "truncate", 2);
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdCompileErr, "compile_err", 1);
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdIntType, "int_type", 3);
|
||||
create_builtin_fn_with_arg_count(g, BuiltinFnIdIntType, "int_type", 2);
|
||||
}
|
||||
|
||||
static void init(CodeGen *g, Buf *source_path) {
|
||||
|
47
src/eval.cpp
47
src/eval.cpp
@ -146,7 +146,7 @@ static int64_t min_signed_val(TypeTableEntry *type_entry) {
|
||||
|
||||
static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue *op2_val,
|
||||
ConstExprValue *out_val, bool (*bignum_fn)(BigNum *, BigNum *, BigNum *),
|
||||
TypeTableEntry *type)
|
||||
TypeTableEntry *type, bool wrapping_op)
|
||||
{
|
||||
bool overflow = bignum_fn(&out_val->data.x_bignum, &op1_val->data.x_bignum, &op2_val->data.x_bignum);
|
||||
if (overflow) {
|
||||
@ -156,7 +156,7 @@ static int eval_const_expr_bin_op_bignum(ConstExprValue *op1_val, ConstExprValue
|
||||
if (type->id == TypeTableEntryIdInt && !bignum_fits_in_bits(&out_val->data.x_bignum,
|
||||
type->data.integral.bit_count, type->data.integral.is_signed))
|
||||
{
|
||||
if (type->data.integral.is_wrapping) {
|
||||
if (wrapping_op) {
|
||||
if (type->data.integral.is_signed) {
|
||||
out_val->data.x_bignum.data.x_uint = max_unsigned_val(type) - out_val->data.x_bignum.data.x_uint + 1;
|
||||
out_val->data.x_bignum.is_negative = !out_val->data.x_bignum.is_negative;
|
||||
@ -187,11 +187,15 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
switch (bin_op) {
|
||||
case BinOpTypeAssign:
|
||||
case BinOpTypeAssignTimes:
|
||||
case BinOpTypeAssignTimesWrap:
|
||||
case BinOpTypeAssignDiv:
|
||||
case BinOpTypeAssignMod:
|
||||
case BinOpTypeAssignPlus:
|
||||
case BinOpTypeAssignPlusWrap:
|
||||
case BinOpTypeAssignMinus:
|
||||
case BinOpTypeAssignMinusWrap:
|
||||
case BinOpTypeAssignBitShiftLeft:
|
||||
case BinOpTypeAssignBitShiftLeftWrap:
|
||||
case BinOpTypeAssignBitShiftRight:
|
||||
case BinOpTypeAssignBitAnd:
|
||||
case BinOpTypeAssignBitXor:
|
||||
@ -256,21 +260,29 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
return 0;
|
||||
}
|
||||
case BinOpTypeAdd:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, false);
|
||||
case BinOpTypeAddWrap:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_add, op1_type, true);
|
||||
case BinOpTypeBinOr:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or, op1_type);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_or, op1_type, false);
|
||||
case BinOpTypeBinXor:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_xor, op1_type, false);
|
||||
case BinOpTypeBinAnd:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and, op1_type);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_and, op1_type, false);
|
||||
case BinOpTypeBitShiftLeft:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, false);
|
||||
case BinOpTypeBitShiftLeftWrap:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shl, op1_type, true);
|
||||
case BinOpTypeBitShiftRight:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_shr, op1_type, false);
|
||||
case BinOpTypeSub:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, false);
|
||||
case BinOpTypeSubWrap:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_sub, op1_type, true);
|
||||
case BinOpTypeMult:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, false);
|
||||
case BinOpTypeMultWrap:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mul, op1_type, true);
|
||||
case BinOpTypeDiv:
|
||||
{
|
||||
bool is_int = false;
|
||||
@ -289,11 +301,11 @@ int eval_const_expr_bin_op(ConstExprValue *op1_val, TypeTableEntry *op1_type,
|
||||
{
|
||||
return ErrorDivByZero;
|
||||
} else {
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div, op1_type);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_div, op1_type, false);
|
||||
}
|
||||
}
|
||||
case BinOpTypeMod:
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type);
|
||||
return eval_const_expr_bin_op_bignum(op1_val, op2_val, out_val, bignum_mod, op1_type, false);
|
||||
case BinOpTypeUnwrapMaybe:
|
||||
zig_panic("TODO");
|
||||
case BinOpTypeArrayCat:
|
||||
@ -314,11 +326,15 @@ static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)
|
||||
switch (bin_op) {
|
||||
case BinOpTypeAssign:
|
||||
case BinOpTypeAssignTimes:
|
||||
case BinOpTypeAssignTimesWrap:
|
||||
case BinOpTypeAssignDiv:
|
||||
case BinOpTypeAssignMod:
|
||||
case BinOpTypeAssignPlus:
|
||||
case BinOpTypeAssignPlusWrap:
|
||||
case BinOpTypeAssignMinus:
|
||||
case BinOpTypeAssignMinusWrap:
|
||||
case BinOpTypeAssignBitShiftLeft:
|
||||
case BinOpTypeAssignBitShiftLeftWrap:
|
||||
case BinOpTypeAssignBitShiftRight:
|
||||
case BinOpTypeAssignBitAnd:
|
||||
case BinOpTypeAssignBitXor:
|
||||
@ -338,10 +354,14 @@ static bool eval_bin_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_val)
|
||||
case BinOpTypeBinXor:
|
||||
case BinOpTypeBinAnd:
|
||||
case BinOpTypeBitShiftLeft:
|
||||
case BinOpTypeBitShiftLeftWrap:
|
||||
case BinOpTypeBitShiftRight:
|
||||
case BinOpTypeAdd:
|
||||
case BinOpTypeAddWrap:
|
||||
case BinOpTypeSub:
|
||||
case BinOpTypeSubWrap:
|
||||
case BinOpTypeMult:
|
||||
case BinOpTypeMultWrap:
|
||||
case BinOpTypeDiv:
|
||||
case BinOpTypeMod:
|
||||
case BinOpTypeUnwrapMaybe:
|
||||
@ -1098,13 +1118,14 @@ static bool eval_prefix_op_expr(EvalFn *ef, AstNode *node, ConstExprValue *out_v
|
||||
break;
|
||||
}
|
||||
case PrefixOpNegation:
|
||||
case PrefixOpNegationWrap:
|
||||
if (expr_type->id == TypeTableEntryIdInt) {
|
||||
assert(expr_type->data.integral.is_signed);
|
||||
bignum_negate(&out_val->data.x_bignum, &expr_val.data.x_bignum);
|
||||
out_val->ok = true;
|
||||
bool overflow = !bignum_fits_in_bits(&out_val->data.x_bignum,
|
||||
expr_type->data.integral.bit_count, expr_type->data.integral.is_signed);
|
||||
if (expr_type->data.integral.is_wrapping) {
|
||||
if (prefix_op == PrefixOpNegationWrap) {
|
||||
if (overflow) {
|
||||
out_val->data.x_bignum.is_negative = true;
|
||||
}
|
||||
|
@ -1384,6 +1384,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {
|
||||
switch (token->id) {
|
||||
case TokenIdBang: return PrefixOpBoolNot;
|
||||
case TokenIdDash: return PrefixOpNegation;
|
||||
case TokenIdMinusPercent: return PrefixOpNegationWrap;
|
||||
case TokenIdTilde: return PrefixOpBinNot;
|
||||
case TokenIdAmpersand: return PrefixOpAddressOf;
|
||||
case TokenIdStar: return PrefixOpDereference;
|
||||
@ -1399,7 +1400,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {
|
||||
|
||||
/*
|
||||
PrefixOpExpression : PrefixOp PrefixOpExpression | SuffixOpExpression
|
||||
PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const)))
|
||||
PrefixOp = "!" | "-" | "~" | "*" | ("&" option("const")) | "?" | "%" | "%%" | "??" | "-%"
|
||||
*/
|
||||
static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
@ -1458,16 +1459,17 @@ static AstNode *ast_parse_prefix_op_expr(ParseContext *pc, int *token_index, boo
|
||||
|
||||
static BinOpType tok_to_mult_op(Token *token) {
|
||||
switch (token->id) {
|
||||
case TokenIdStar: return BinOpTypeMult;
|
||||
case TokenIdStarStar: return BinOpTypeArrayMult;
|
||||
case TokenIdSlash: return BinOpTypeDiv;
|
||||
case TokenIdPercent: return BinOpTypeMod;
|
||||
default: return BinOpTypeInvalid;
|
||||
case TokenIdStar: return BinOpTypeMult;
|
||||
case TokenIdTimesPercent: return BinOpTypeMultWrap;
|
||||
case TokenIdStarStar: return BinOpTypeArrayMult;
|
||||
case TokenIdSlash: return BinOpTypeDiv;
|
||||
case TokenIdPercent: return BinOpTypeMod;
|
||||
default: return BinOpTypeInvalid;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
MultiplyOperator = "*" | "/" | "%" | "**"
|
||||
MultiplyOperator = "*" | "/" | "%" | "**" | "*%"
|
||||
*/
|
||||
static BinOpType ast_parse_mult_op(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
@ -1511,15 +1513,17 @@ static AstNode *ast_parse_mult_expr(ParseContext *pc, int *token_index, bool man
|
||||
|
||||
static BinOpType tok_to_add_op(Token *token) {
|
||||
switch (token->id) {
|
||||
case TokenIdPlus: return BinOpTypeAdd;
|
||||
case TokenIdDash: return BinOpTypeSub;
|
||||
case TokenIdPlusPlus: return BinOpTypeArrayCat;
|
||||
default: return BinOpTypeInvalid;
|
||||
case TokenIdPlus: return BinOpTypeAdd;
|
||||
case TokenIdPlusPercent: return BinOpTypeAddWrap;
|
||||
case TokenIdDash: return BinOpTypeSub;
|
||||
case TokenIdMinusPercent: return BinOpTypeSubWrap;
|
||||
case TokenIdPlusPlus: return BinOpTypeArrayCat;
|
||||
default: return BinOpTypeInvalid;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
AdditionOperator : "+" | "-" | "++"
|
||||
AdditionOperator = "+" | "-" | "++" | "+%" | "-%"
|
||||
*/
|
||||
static BinOpType ast_parse_add_op(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
@ -1563,14 +1567,15 @@ static AstNode *ast_parse_add_expr(ParseContext *pc, int *token_index, bool mand
|
||||
|
||||
static BinOpType tok_to_bit_shift_op(Token *token) {
|
||||
switch (token->id) {
|
||||
case TokenIdBitShiftLeft: return BinOpTypeBitShiftLeft;
|
||||
case TokenIdBitShiftRight: return BinOpTypeBitShiftRight;
|
||||
case TokenIdBitShiftLeft: return BinOpTypeBitShiftLeft;
|
||||
case TokenIdBitShiftLeftPercent: return BinOpTypeBitShiftLeftWrap;
|
||||
case TokenIdBitShiftRight: return BinOpTypeBitShiftRight;
|
||||
default: return BinOpTypeInvalid;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
BitShiftOperator : token(BitShiftLeft) | token(BitShiftRight)
|
||||
BitShiftOperator = "<<" | ">>" | "<<%"
|
||||
*/
|
||||
static BinOpType ast_parse_bit_shift_op(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
@ -2230,11 +2235,15 @@ static BinOpType tok_to_ass_op(Token *token) {
|
||||
switch (token->id) {
|
||||
case TokenIdEq: return BinOpTypeAssign;
|
||||
case TokenIdTimesEq: return BinOpTypeAssignTimes;
|
||||
case TokenIdTimesPercentEq: return BinOpTypeAssignTimesWrap;
|
||||
case TokenIdDivEq: return BinOpTypeAssignDiv;
|
||||
case TokenIdModEq: return BinOpTypeAssignMod;
|
||||
case TokenIdPlusEq: return BinOpTypeAssignPlus;
|
||||
case TokenIdPlusPercentEq: return BinOpTypeAssignPlusWrap;
|
||||
case TokenIdMinusEq: return BinOpTypeAssignMinus;
|
||||
case TokenIdMinusPercentEq: return BinOpTypeAssignMinusWrap;
|
||||
case TokenIdBitShiftLeftEq: return BinOpTypeAssignBitShiftLeft;
|
||||
case TokenIdBitShiftLeftPercentEq: return BinOpTypeAssignBitShiftLeftWrap;
|
||||
case TokenIdBitShiftRightEq: return BinOpTypeAssignBitShiftRight;
|
||||
case TokenIdBitAndEq: return BinOpTypeAssignBitAnd;
|
||||
case TokenIdBitXorEq: return BinOpTypeAssignBitXor;
|
||||
@ -2246,7 +2255,7 @@ static BinOpType tok_to_ass_op(Token *token) {
|
||||
}
|
||||
|
||||
/*
|
||||
AssignmentOperator : token(Eq) | token(TimesEq) | token(DivEq) | token(ModEq) | token(PlusEq) | token(MinusEq) | token(BitShiftLeftEq) | token(BitShiftRightEq) | token(BitAndEq) | token(BitXorEq) | token(BitOrEq) | token(BoolAndEq) | token(BoolOrEq)
|
||||
AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | "&=" | "^=" | "|=" | "&&=" | "||=" | "*%=" | "+%=" | "-%=" | "<<%="
|
||||
*/
|
||||
static BinOpType ast_parse_ass_op(ParseContext *pc, int *token_index, bool mandatory) {
|
||||
Token *token = &pc->tokens->at(*token_index);
|
||||
|
@ -154,10 +154,13 @@ enum TokenizeState {
|
||||
TokenizeStateCharLiteral,
|
||||
TokenizeStateCharLiteralEnd,
|
||||
TokenizeStateSawStar,
|
||||
TokenizeStateSawStarPercent,
|
||||
TokenizeStateSawSlash,
|
||||
TokenizeStateSawPercent,
|
||||
TokenizeStateSawPlus,
|
||||
TokenizeStateSawPlusPercent,
|
||||
TokenizeStateSawDash,
|
||||
TokenizeStateSawMinusPercent,
|
||||
TokenizeStateSawAmpersand,
|
||||
TokenizeStateSawAmpersandAmpersand,
|
||||
TokenizeStateSawCaret,
|
||||
@ -171,6 +174,7 @@ enum TokenizeState {
|
||||
TokenizeStateSawBang,
|
||||
TokenizeStateSawLessThan,
|
||||
TokenizeStateSawLessThanLessThan,
|
||||
TokenizeStateSawShiftLeftPercent,
|
||||
TokenizeStateSawGreaterThan,
|
||||
TokenizeStateSawGreaterThanGreaterThan,
|
||||
TokenizeStateSawDot,
|
||||
@ -596,6 +600,24 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
case '%':
|
||||
t.cur_tok->id = TokenIdBitShiftLeftPercent;
|
||||
t.state = TokenizeStateSawShiftLeftPercent;
|
||||
break;
|
||||
default:
|
||||
t.pos -= 1;
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case TokenizeStateSawShiftLeftPercent:
|
||||
switch (c) {
|
||||
case '=':
|
||||
t.cur_tok->id = TokenIdBitShiftLeftPercentEq;
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
default:
|
||||
t.pos -= 1;
|
||||
end_token(&t);
|
||||
@ -648,6 +670,24 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
case '%':
|
||||
t.cur_tok->id = TokenIdTimesPercent;
|
||||
t.state = TokenizeStateSawStarPercent;
|
||||
break;
|
||||
default:
|
||||
t.pos -= 1;
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case TokenizeStateSawStarPercent:
|
||||
switch (c) {
|
||||
case '=':
|
||||
t.cur_tok->id = TokenIdTimesPercentEq;
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
default:
|
||||
t.pos -= 1;
|
||||
end_token(&t);
|
||||
@ -691,6 +731,24 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
case '%':
|
||||
t.cur_tok->id = TokenIdPlusPercent;
|
||||
t.state = TokenizeStateSawPlusPercent;
|
||||
break;
|
||||
default:
|
||||
t.pos -= 1;
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case TokenizeStateSawPlusPercent:
|
||||
switch (c) {
|
||||
case '=':
|
||||
t.cur_tok->id = TokenIdPlusPercentEq;
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
default:
|
||||
t.pos -= 1;
|
||||
end_token(&t);
|
||||
@ -1181,6 +1239,24 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
case '%':
|
||||
t.cur_tok->id = TokenIdMinusPercent;
|
||||
t.state = TokenizeStateSawMinusPercent;
|
||||
break;
|
||||
default:
|
||||
t.pos -= 1;
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
case TokenizeStateSawMinusPercent:
|
||||
switch (c) {
|
||||
case '=':
|
||||
t.cur_tok->id = TokenIdMinusPercentEq;
|
||||
end_token(&t);
|
||||
t.state = TokenizeStateStart;
|
||||
break;
|
||||
default:
|
||||
t.pos -= 1;
|
||||
end_token(&t);
|
||||
@ -1252,6 +1328,10 @@ void tokenize(Buf *buf, Tokenization *out) {
|
||||
case TokenizeStateSawDot:
|
||||
case TokenizeStateSawQuestionMark:
|
||||
case TokenizeStateSawAtSign:
|
||||
case TokenizeStateSawStarPercent:
|
||||
case TokenizeStateSawPlusPercent:
|
||||
case TokenizeStateSawMinusPercent:
|
||||
case TokenizeStateSawShiftLeftPercent:
|
||||
end_token(&t);
|
||||
break;
|
||||
case TokenizeStateSawDotDot:
|
||||
@ -1372,6 +1452,14 @@ const char * token_name(TokenId id) {
|
||||
case TokenIdMaybeAssign: return "?=";
|
||||
case TokenIdAtSign: return "@";
|
||||
case TokenIdPercentDot: return "%.";
|
||||
case TokenIdTimesPercent: return "*%";
|
||||
case TokenIdTimesPercentEq: return "*%=";
|
||||
case TokenIdPlusPercent: return "+%";
|
||||
case TokenIdPlusPercentEq: return "+%=";
|
||||
case TokenIdMinusPercent: return "-%";
|
||||
case TokenIdMinusPercentEq: return "-%=";
|
||||
case TokenIdBitShiftLeftPercent: return "<<%";
|
||||
case TokenIdBitShiftLeftPercentEq: return "<<%=";
|
||||
}
|
||||
return "(invalid token)";
|
||||
}
|
||||
|
@ -70,11 +70,19 @@ enum TokenId {
|
||||
TokenIdBinXor,
|
||||
TokenIdEq,
|
||||
TokenIdTimesEq,
|
||||
TokenIdTimesPercent,
|
||||
TokenIdTimesPercentEq,
|
||||
TokenIdDivEq,
|
||||
TokenIdModEq,
|
||||
TokenIdPlusEq,
|
||||
TokenIdPlusPercent,
|
||||
TokenIdPlusPercentEq,
|
||||
TokenIdMinusEq,
|
||||
TokenIdMinusPercent,
|
||||
TokenIdMinusPercentEq,
|
||||
TokenIdBitShiftLeftEq,
|
||||
TokenIdBitShiftLeftPercent,
|
||||
TokenIdBitShiftLeftPercentEq,
|
||||
TokenIdBitShiftRightEq,
|
||||
TokenIdBitAndEq,
|
||||
TokenIdBitXorEq,
|
||||
|
@ -235,7 +235,7 @@ fn char_to_digit(c: u8, radix: u8) -> %u8 {
|
||||
}
|
||||
|
||||
pub fn buf_print_signed(inline T: type, out_buf: []u8, x: T) -> usize {
|
||||
const uint = @int_type(false, T.bit_count, false);
|
||||
const uint = @int_type(false, T.bit_count);
|
||||
if (x < 0) {
|
||||
out_buf[0] = '-';
|
||||
return 1 + buf_print_unsigned(uint, out_buf[1...], uint(-(x + 1)) + 1);
|
||||
|
11
std/rand.zig
11
std/rand.zig
@ -77,7 +77,7 @@ pub struct Rand {
|
||||
|
||||
/// Get a floating point value in the range 0.0..1.0.
|
||||
pub fn float(r: &Rand, inline T: type) -> T {
|
||||
const int_type = @int_type(false, @sizeof(T) * 8, false);
|
||||
const int_type = @int_type(false, @sizeof(T) * 8);
|
||||
// TODO switch statement for constant values
|
||||
const precision = if (T == f32) {
|
||||
16777216
|
||||
@ -99,7 +99,6 @@ struct MersenneTwister(
|
||||
l: int, f: int)
|
||||
{
|
||||
const Self = MersenneTwister(int, n, m, r, a, u, d, s, b, t, c, l, f);
|
||||
const intw = @int_type(int.is_signed, int.bit_count, true);
|
||||
|
||||
array: [n]int,
|
||||
index: usize,
|
||||
@ -113,7 +112,7 @@ struct MersenneTwister(
|
||||
var prev_value = seed;
|
||||
mt.array[0] = prev_value;
|
||||
{var i: usize = 1; while (i < n; i += 1) {
|
||||
prev_value = intw(i) + intw(f) * intw(prev_value ^ (prev_value >> (int.bit_count - 2)));
|
||||
prev_value = int(i) +% f *% (prev_value ^ (prev_value >> (int.bit_count - 2)));
|
||||
mt.array[i] = prev_value;
|
||||
}};
|
||||
|
||||
@ -152,12 +151,12 @@ struct MersenneTwister(
|
||||
mt.index = 0;
|
||||
}
|
||||
|
||||
var x: intw = mt.array[mt.index];
|
||||
var x = mt.array[mt.index];
|
||||
mt.index += 1;
|
||||
|
||||
x ^= ((x >> u) & d);
|
||||
x ^= ((x << s) & b);
|
||||
x ^= ((x << t) & c);
|
||||
x ^= ((x <<% s) & b);
|
||||
x ^= ((x <<% t) & c);
|
||||
x ^= (x >> l);
|
||||
|
||||
return x;
|
||||
|
@ -1362,12 +1362,6 @@ fn mul(a: u16, b: u16) -> u16 {
|
||||
".tmp_source.zig:3:18: note: called from here",
|
||||
".tmp_source.zig:6:7: note: overflow occurred here");
|
||||
|
||||
add_compile_fail_case("add incompatible int types", R"SOURCE(
|
||||
fn add(x: i8w, y: i32) {
|
||||
const z = x + y;
|
||||
}
|
||||
)SOURCE", 1, ".tmp_source.zig:3:17: error: incompatible types: 'i8w' and 'i32'");
|
||||
|
||||
add_compile_fail_case("truncate sign mismatch", R"SOURCE(
|
||||
fn f() {
|
||||
const x: u32 = 10;
|
||||
|
@ -1458,17 +1458,17 @@ fn unsigned_wrapping() {
|
||||
test_unsigned_wrapping_eval(@max_value(u32));
|
||||
test_unsigned_wrapping_noeval(@max_value(u32));
|
||||
}
|
||||
fn test_unsigned_wrapping_eval(x: u32w) {
|
||||
const zero = x + 1;
|
||||
fn test_unsigned_wrapping_eval(x: u32) {
|
||||
const zero = x +% 1;
|
||||
assert(zero == 0);
|
||||
const orig = zero - 1;
|
||||
const orig = zero -% 1;
|
||||
assert(orig == @max_value(u32));
|
||||
}
|
||||
#static_eval_enable(false)
|
||||
fn test_unsigned_wrapping_noeval(x: u32w) {
|
||||
const zero = x + 1;
|
||||
fn test_unsigned_wrapping_noeval(x: u32) {
|
||||
const zero = x +% 1;
|
||||
assert(zero == 0);
|
||||
const orig = zero - 1;
|
||||
const orig = zero -% 1;
|
||||
assert(orig == @max_value(u32));
|
||||
}
|
||||
|
||||
@ -1477,17 +1477,17 @@ fn signed_wrapping() {
|
||||
test_signed_wrapping_eval(@max_value(i32));
|
||||
test_signed_wrapping_noeval(@max_value(i32));
|
||||
}
|
||||
fn test_signed_wrapping_eval(x: i32w) {
|
||||
const min_val = x + 1;
|
||||
fn test_signed_wrapping_eval(x: i32) {
|
||||
const min_val = x +% 1;
|
||||
assert(min_val == @min_value(i32));
|
||||
const max_val = min_val - 1;
|
||||
const max_val = min_val -% 1;
|
||||
assert(max_val == @max_value(i32));
|
||||
}
|
||||
#static_eval_enable(false)
|
||||
fn test_signed_wrapping_noeval(x: i32w) {
|
||||
const min_val = x + 1;
|
||||
fn test_signed_wrapping_noeval(x: i32) {
|
||||
const min_val = x +% 1;
|
||||
assert(min_val == @min_value(i32));
|
||||
const max_val = min_val - 1;
|
||||
const max_val = min_val -% 1;
|
||||
assert(max_val == @max_value(i32));
|
||||
}
|
||||
|
||||
@ -1496,15 +1496,15 @@ fn negation_wrapping() {
|
||||
test_negation_wrapping_eval(@min_value(i16));
|
||||
test_negation_wrapping_noeval(@min_value(i16));
|
||||
}
|
||||
fn test_negation_wrapping_eval(x: i16w) {
|
||||
fn test_negation_wrapping_eval(x: i16) {
|
||||
assert(x == -32768);
|
||||
const neg = -x;
|
||||
const neg = -%x;
|
||||
assert(neg == -32768);
|
||||
}
|
||||
#static_eval_enable(false)
|
||||
fn test_negation_wrapping_noeval(x: i16w) {
|
||||
fn test_negation_wrapping_noeval(x: i16) {
|
||||
assert(x == -32768);
|
||||
const neg = -x;
|
||||
const neg = -%x;
|
||||
assert(neg == -32768);
|
||||
}
|
||||
|
||||
@ -1513,13 +1513,13 @@ fn shl_wrapping() {
|
||||
test_shl_wrapping_eval(@max_value(u16));
|
||||
test_shl_wrapping_noeval(@max_value(u16));
|
||||
}
|
||||
fn test_shl_wrapping_eval(x: u16w) {
|
||||
const shifted = x << 1;
|
||||
fn test_shl_wrapping_eval(x: u16) {
|
||||
const shifted = x <<% 1;
|
||||
assert(shifted == 65534);
|
||||
}
|
||||
#static_eval_enable(false)
|
||||
fn test_shl_wrapping_noeval(x: u16w) {
|
||||
const shifted = x << 1;
|
||||
fn test_shl_wrapping_noeval(x: u16) {
|
||||
const shifted = x <<% 1;
|
||||
assert(shifted == 65534);
|
||||
}
|
||||
|
||||
@ -1531,23 +1531,6 @@ fn shl_with_overflow() {
|
||||
assert(result == 0b1011111111111100);
|
||||
}
|
||||
|
||||
#attribute("test")
|
||||
fn combine_non_wrap_with_wrap() {
|
||||
const x: i32 = 123;
|
||||
const y: i32w = 456;
|
||||
const z = x + y;
|
||||
const z2 = y + x;
|
||||
assert(@typeof(z) == i32w);
|
||||
assert(@typeof(z2) == i32w);
|
||||
|
||||
const a: i8 = 123;
|
||||
const b: i32w = 456;
|
||||
const c = b + a;
|
||||
const d = a + b;
|
||||
assert(@typeof(c) == i32w);
|
||||
assert(@typeof(d) == i32w);
|
||||
}
|
||||
|
||||
#attribute("test")
|
||||
fn c_string_concatenation() {
|
||||
const a = c"OK" ++ c" IT " ++ c"WORKED";
|
||||
@ -1687,41 +1670,21 @@ struct DivResult {
|
||||
|
||||
#attribute("test")
|
||||
fn int_type_builtin() {
|
||||
assert(@int_type(true, 8, false) == i8);
|
||||
assert(@int_type(true, 16, false) == i16);
|
||||
assert(@int_type(true, 32, false) == i32);
|
||||
assert(@int_type(true, 64, false) == i64);
|
||||
assert(@int_type(true, 8) == i8);
|
||||
assert(@int_type(true, 16) == i16);
|
||||
assert(@int_type(true, 32) == i32);
|
||||
assert(@int_type(true, 64) == i64);
|
||||
|
||||
assert(@int_type(false, 8, false) == u8);
|
||||
assert(@int_type(false, 16, false) == u16);
|
||||
assert(@int_type(false, 32, false) == u32);
|
||||
assert(@int_type(false, 64, false) == u64);
|
||||
|
||||
assert(@int_type(true, 8, true) == i8w);
|
||||
assert(@int_type(true, 16, true) == i16w);
|
||||
assert(@int_type(true, 32, true) == i32w);
|
||||
assert(@int_type(true, 64, true) == i64w);
|
||||
|
||||
assert(@int_type(false, 8, true) == u8w);
|
||||
assert(@int_type(false, 16, true) == u16w);
|
||||
assert(@int_type(false, 32, true) == u32w);
|
||||
assert(@int_type(false, 64, true) == u64w);
|
||||
assert(@int_type(false, 8) == u8);
|
||||
assert(@int_type(false, 16) == u16);
|
||||
assert(@int_type(false, 32) == u32);
|
||||
assert(@int_type(false, 64) == u64);
|
||||
|
||||
assert(i8.bit_count == 8);
|
||||
assert(i16.bit_count == 16);
|
||||
assert(i32.bit_count == 32);
|
||||
assert(i64.bit_count == 64);
|
||||
|
||||
assert(!i8.is_wrapping);
|
||||
assert(!i16.is_wrapping);
|
||||
assert(!i32.is_wrapping);
|
||||
assert(!i64.is_wrapping);
|
||||
|
||||
assert(i8w.is_wrapping);
|
||||
assert(i16w.is_wrapping);
|
||||
assert(i32w.is_wrapping);
|
||||
assert(i64w.is_wrapping);
|
||||
|
||||
assert(i8.is_signed);
|
||||
assert(i16.is_signed);
|
||||
assert(i32.is_signed);
|
||||
|
Loading…
x
Reference in New Issue
Block a user