all: add unsigned shift operators (#11536)
parent
e4bd2306da
commit
95136cbfc7
|
@ -5557,10 +5557,11 @@ This lists operators for [primitive types](#primitive-types) only.
|
||||||
|
|
||||||
<< left shift integer << unsigned integer
|
<< left shift integer << unsigned integer
|
||||||
>> right shift integer >> unsigned integer
|
>> right shift integer >> unsigned integer
|
||||||
|
>>> unsigned right shift integer >> unsigned integer
|
||||||
|
|
||||||
|
|
||||||
Precedence Operator
|
Precedence Operator
|
||||||
5 * / % << >> &
|
5 * / % << >> >>> &
|
||||||
4 + - | ^
|
4 + - | ^
|
||||||
3 == != < <= > >=
|
3 == != < <= > >=
|
||||||
2 &&
|
2 &&
|
||||||
|
@ -5570,5 +5571,5 @@ Precedence Operator
|
||||||
Assignment Operators
|
Assignment Operators
|
||||||
+= -= *= /= %=
|
+= -= *= /= %=
|
||||||
&= |= ^=
|
&= |= ^=
|
||||||
>>= <<=
|
>>= <<= >>>=
|
||||||
```
|
```
|
||||||
|
|
|
@ -1599,6 +1599,50 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
||||||
.right_shift {
|
.right_shift {
|
||||||
return c.check_shift(left_type, right_type, left_pos, right_pos)
|
return c.check_shift(left_type, right_type, left_pos, right_pos)
|
||||||
}
|
}
|
||||||
|
.unsigned_right_shift {
|
||||||
|
modified_left_type := if !left_type.is_int() {
|
||||||
|
c.error('invalid operation: shift on type `${c.table.get_type_symbol(left_type).name}`',
|
||||||
|
left_pos)
|
||||||
|
ast.void_type_idx
|
||||||
|
} else if left_type.is_int_literal() {
|
||||||
|
// int literal => i64
|
||||||
|
ast.u32_type_idx
|
||||||
|
} else if left_type.is_unsigned() {
|
||||||
|
left_type
|
||||||
|
} else {
|
||||||
|
// signed types' idx adds with 5 will get correct relative unsigned type
|
||||||
|
// i8 => byte
|
||||||
|
// i16 => u16
|
||||||
|
// int => u32
|
||||||
|
// i64 => u64
|
||||||
|
// isize => usize
|
||||||
|
// i128 => u128 NOT IMPLEMENTED YET
|
||||||
|
left_type.idx() + ast.u32_type_idx - ast.int_type_idx
|
||||||
|
}
|
||||||
|
|
||||||
|
if modified_left_type == 0 {
|
||||||
|
return ast.void_type
|
||||||
|
}
|
||||||
|
|
||||||
|
node = ast.InfixExpr{
|
||||||
|
left: ast.CastExpr{
|
||||||
|
expr: node.left
|
||||||
|
typ: modified_left_type
|
||||||
|
typname: c.table.type_str(modified_left_type)
|
||||||
|
pos: node.pos
|
||||||
|
}
|
||||||
|
left_type: left_type
|
||||||
|
op: .right_shift
|
||||||
|
right: node.right
|
||||||
|
right_type: right_type
|
||||||
|
is_stmt: false
|
||||||
|
pos: node.pos
|
||||||
|
auto_locked: node.auto_locked
|
||||||
|
or_block: node.or_block
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.check_shift(left_type, right_type, left_pos, right_pos)
|
||||||
|
}
|
||||||
.key_is, .not_is {
|
.key_is, .not_is {
|
||||||
right_expr := node.right
|
right_expr := node.right
|
||||||
mut typ := match right_expr {
|
mut typ := match right_expr {
|
||||||
|
@ -4275,6 +4319,60 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
||||||
right.position())
|
right.position())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.unsigned_right_shift_assign {
|
||||||
|
if node.left.len != 1 || node.right.len != 1 {
|
||||||
|
c.error('unsupported operation: unable to lower expression for unsigned shift assignment.',
|
||||||
|
node.pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
modified_left_type := if !left_type.is_int() {
|
||||||
|
c.error('invalid operation: shift on type `${c.table.get_type_symbol(left_type).name}`',
|
||||||
|
node.pos)
|
||||||
|
ast.void_type_idx
|
||||||
|
} else if left_type.is_int_literal() {
|
||||||
|
// int literal => i64
|
||||||
|
ast.u32_type_idx
|
||||||
|
} else if left_type.is_unsigned() {
|
||||||
|
left_type
|
||||||
|
} else {
|
||||||
|
// signed types' idx adds with 5 will get correct relative unsigned type
|
||||||
|
// i8 => byte
|
||||||
|
// i16 => u16
|
||||||
|
// int => u32
|
||||||
|
// i64 => u64
|
||||||
|
// isize => usize
|
||||||
|
// i128 => u128 NOT IMPLEMENTED YET
|
||||||
|
left_type.idx() + ast.u32_type_idx - ast.int_type_idx
|
||||||
|
}
|
||||||
|
|
||||||
|
node = ast.AssignStmt{
|
||||||
|
op: .assign
|
||||||
|
pos: node.pos
|
||||||
|
comments: node.comments
|
||||||
|
end_comments: node.end_comments
|
||||||
|
left: node.left
|
||||||
|
right: [
|
||||||
|
ast.Expr(ast.InfixExpr{
|
||||||
|
left: ast.CastExpr{
|
||||||
|
expr: node.left[0]
|
||||||
|
typ: modified_left_type
|
||||||
|
typname: c.table.type_str(modified_left_type)
|
||||||
|
pos: node.pos
|
||||||
|
}
|
||||||
|
op: .right_shift
|
||||||
|
right: node.right[0]
|
||||||
|
left_type: modified_left_type
|
||||||
|
right_type: right_type
|
||||||
|
pos: node.pos
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
left_types: node.left_types
|
||||||
|
right_types: node.right_types
|
||||||
|
is_static: node.is_static
|
||||||
|
is_simple: node.is_simple
|
||||||
|
has_cross_var: node.has_cross_var
|
||||||
|
}
|
||||||
|
}
|
||||||
else {}
|
else {}
|
||||||
}
|
}
|
||||||
if node.op in [.plus_assign, .minus_assign, .mod_assign, .mult_assign, .div_assign]
|
if node.op in [.plus_assign, .minus_assign, .mod_assign, .mult_assign, .div_assign]
|
||||||
|
|
|
@ -480,7 +480,6 @@ fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr {
|
||||||
if is_key_in {
|
if is_key_in {
|
||||||
p.inside_in_array = false
|
p.inside_in_array = false
|
||||||
}
|
}
|
||||||
|
|
||||||
p.expecting_type = prev_expecting_type
|
p.expecting_type = prev_expecting_type
|
||||||
if p.pref.is_vet && op in [.key_in, .not_in] && right is ast.ArrayInit
|
if p.pref.is_vet && op in [.key_in, .not_in] && right is ast.ArrayInit
|
||||||
&& (right as ast.ArrayInit).exprs.len == 1 {
|
&& (right as ast.ArrayInit).exprs.len == 1 {
|
||||||
|
|
|
@ -936,11 +936,31 @@ fn (mut s Scanner) text_scan() token.Token {
|
||||||
for typ in typs {
|
for typ in typs {
|
||||||
// TODO: combine two ifs once logic shortcut with `.all()` is fixed
|
// TODO: combine two ifs once logic shortcut with `.all()` is fixed
|
||||||
if typ.len == 0 {
|
if typ.len == 0 {
|
||||||
|
if s.text[s.pos + 2] == `>` {
|
||||||
|
if s.pos + 3 < s.text.len && s.text[s.pos + 3] == `=` {
|
||||||
|
s.pos += 3
|
||||||
|
return s.new_token(.unsigned_right_shift_assign,
|
||||||
|
'', 4)
|
||||||
|
}
|
||||||
|
s.pos += 2
|
||||||
|
return s.new_token(.unsigned_right_shift, '',
|
||||||
|
3)
|
||||||
|
}
|
||||||
s.pos++
|
s.pos++
|
||||||
return s.new_token(.right_shift, '', 2)
|
return s.new_token(.right_shift, '', 2)
|
||||||
}
|
}
|
||||||
if !(typ[0].is_capital() && typ[1..].bytes().all(it.is_alnum()))
|
if !(typ[0].is_capital() && typ[1..].bytes().all(it.is_alnum()))
|
||||||
&& typ !in ast.builtin_type_names {
|
&& typ !in ast.builtin_type_names {
|
||||||
|
if s.text[s.pos + 2] == `>` {
|
||||||
|
if s.pos + 3 < s.text.len && s.text[s.pos + 3] == `=` {
|
||||||
|
s.pos += 3
|
||||||
|
return s.new_token(.unsigned_right_shift_assign,
|
||||||
|
'', 4)
|
||||||
|
}
|
||||||
|
s.pos += 2
|
||||||
|
return s.new_token(.unsigned_right_shift, '',
|
||||||
|
3)
|
||||||
|
}
|
||||||
s.pos++
|
s.pos++
|
||||||
return s.new_token(.right_shift, '', 2)
|
return s.new_token(.right_shift, '', 2)
|
||||||
}
|
}
|
||||||
|
@ -948,6 +968,14 @@ fn (mut s Scanner) text_scan() token.Token {
|
||||||
return s.new_token(.gt, '', 1)
|
return s.new_token(.gt, '', 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if s.text[s.pos + 2] == `>` {
|
||||||
|
if s.pos + 3 < s.text.len && s.text[s.pos + 3] == `=` {
|
||||||
|
s.pos += 3
|
||||||
|
return s.new_token(.unsigned_right_shift_assign, '', 4)
|
||||||
|
}
|
||||||
|
s.pos += 2
|
||||||
|
return s.new_token(.unsigned_right_shift, '', 3)
|
||||||
|
}
|
||||||
s.pos++
|
s.pos++
|
||||||
return s.new_token(.right_shift, '', 2)
|
return s.new_token(.right_shift, '', 2)
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
const answer_u64 = u64(9223372036854775805)
|
||||||
|
|
||||||
|
const (
|
||||||
|
answer_u32 = u32(2147483645)
|
||||||
|
answer_u16 = u16(32765)
|
||||||
|
answer_u8 = u8(125)
|
||||||
|
)
|
||||||
|
|
||||||
|
fn test_unsigned_right_shift_expr_isize_usize() {
|
||||||
|
$if x32 {
|
||||||
|
assert isize(-5) >>> 1 == answer_u32
|
||||||
|
assert usize(-5) >>> 1 == answer_u32
|
||||||
|
}
|
||||||
|
$if x64 {
|
||||||
|
assert isize(-5) >>> 1 == answer_u64
|
||||||
|
assert usize(-5) >>> 1 == answer_u64
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_unsigned_right_shift_expr() {
|
||||||
|
assert i64(-5) >>> 1 == answer_u64
|
||||||
|
assert -5 >>> 1 == answer_u32 // because int literal's size defaults to int's size, without an explicit cast
|
||||||
|
assert int(-5) >>> 1 == answer_u32
|
||||||
|
assert i16(-5) >>> 1 == answer_u16
|
||||||
|
assert i8(-5) >>> 1 == answer_u8
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_unsigned_right_shift_assignment() {
|
||||||
|
mut x, mut y, mut z := i64(-5), -5, int(-5)
|
||||||
|
x >>>= 1
|
||||||
|
y >>>= 1
|
||||||
|
z >>>= 1
|
||||||
|
assert x == answer_u64
|
||||||
|
assert y == answer_u32
|
||||||
|
assert z == answer_u32
|
||||||
|
}
|
|
@ -48,6 +48,7 @@ pub enum Kind {
|
||||||
str_dollar
|
str_dollar
|
||||||
left_shift // <<
|
left_shift // <<
|
||||||
right_shift // >>
|
right_shift // >>
|
||||||
|
unsigned_right_shift // >>>
|
||||||
not_in // !in
|
not_in // !in
|
||||||
not_is // !is
|
not_is // !is
|
||||||
assign // =
|
assign // =
|
||||||
|
@ -62,6 +63,7 @@ pub enum Kind {
|
||||||
and_assign // &=
|
and_assign // &=
|
||||||
right_shift_assign // <<=
|
right_shift_assign // <<=
|
||||||
left_shift_assign // >>=
|
left_shift_assign // >>=
|
||||||
|
unsigned_right_shift_assign // >>>=
|
||||||
lcbr // {
|
lcbr // {
|
||||||
rcbr // }
|
rcbr // }
|
||||||
lpar // (
|
lpar // (
|
||||||
|
@ -131,7 +133,9 @@ pub enum Kind {
|
||||||
|
|
||||||
pub const (
|
pub const (
|
||||||
assign_tokens = [Kind.assign, .plus_assign, .minus_assign, .mult_assign, .div_assign, .xor_assign,
|
assign_tokens = [Kind.assign, .plus_assign, .minus_assign, .mult_assign, .div_assign, .xor_assign,
|
||||||
.mod_assign, .or_assign, .and_assign, .right_shift_assign, .left_shift_assign]
|
.mod_assign, .or_assign, .and_assign, .right_shift_assign, .left_shift_assign,
|
||||||
|
.unsigned_right_shift_assign,
|
||||||
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -238,6 +242,7 @@ fn build_token_str() []string {
|
||||||
s[Kind.or_assign] = '|='
|
s[Kind.or_assign] = '|='
|
||||||
s[Kind.and_assign] = '&='
|
s[Kind.and_assign] = '&='
|
||||||
s[Kind.right_shift_assign] = '>>='
|
s[Kind.right_shift_assign] = '>>='
|
||||||
|
s[Kind.unsigned_right_shift_assign] = '>>>='
|
||||||
s[Kind.left_shift_assign] = '<<='
|
s[Kind.left_shift_assign] = '<<='
|
||||||
s[Kind.lcbr] = '{'
|
s[Kind.lcbr] = '{'
|
||||||
s[Kind.rcbr] = '}'
|
s[Kind.rcbr] = '}'
|
||||||
|
@ -254,6 +259,7 @@ fn build_token_str() []string {
|
||||||
s[Kind.question] = '?'
|
s[Kind.question] = '?'
|
||||||
s[Kind.left_shift] = '<<'
|
s[Kind.left_shift] = '<<'
|
||||||
s[Kind.right_shift] = '>>'
|
s[Kind.right_shift] = '>>'
|
||||||
|
s[Kind.unsigned_right_shift] = '>>>'
|
||||||
s[Kind.comment] = 'comment'
|
s[Kind.comment] = 'comment'
|
||||||
s[Kind.nl] = 'NLL'
|
s[Kind.nl] = 'NLL'
|
||||||
s[Kind.dollar] = '$'
|
s[Kind.dollar] = '$'
|
||||||
|
@ -372,7 +378,7 @@ pub enum Precedence {
|
||||||
eq // == or !=
|
eq // == or !=
|
||||||
// less_greater // > or <
|
// less_greater // > or <
|
||||||
sum // + - | ^
|
sum // + - | ^
|
||||||
product // * / << >> &
|
product // * / << >> >>> &
|
||||||
// mod // %
|
// mod // %
|
||||||
prefix // -X or !X
|
prefix // -X or !X
|
||||||
postfix // ++ or --
|
postfix // ++ or --
|
||||||
|
@ -388,12 +394,13 @@ pub fn build_precedences() []Precedence {
|
||||||
p[Kind.inc] = .postfix
|
p[Kind.inc] = .postfix
|
||||||
p[Kind.dec] = .postfix
|
p[Kind.dec] = .postfix
|
||||||
p[Kind.question] = .postfix
|
p[Kind.question] = .postfix
|
||||||
// `*` | `/` | `%` | `<<` | `>>` | `&`
|
// `*` | `/` | `%` | `<<` | `>>` | `>>>` | `&`
|
||||||
p[Kind.mul] = .product
|
p[Kind.mul] = .product
|
||||||
p[Kind.div] = .product
|
p[Kind.div] = .product
|
||||||
p[Kind.mod] = .product
|
p[Kind.mod] = .product
|
||||||
p[Kind.left_shift] = .product
|
p[Kind.left_shift] = .product
|
||||||
p[Kind.right_shift] = .product
|
p[Kind.right_shift] = .product
|
||||||
|
p[Kind.unsigned_right_shift] = .product
|
||||||
p[Kind.amp] = .product
|
p[Kind.amp] = .product
|
||||||
p[Kind.arrow] = .product
|
p[Kind.arrow] = .product
|
||||||
// `+` | `-` | `|` | `^`
|
// `+` | `-` | `|` | `^`
|
||||||
|
@ -419,6 +426,7 @@ pub fn build_precedences() []Precedence {
|
||||||
// <<= | *= | ...
|
// <<= | *= | ...
|
||||||
p[Kind.left_shift_assign] = .assign
|
p[Kind.left_shift_assign] = .assign
|
||||||
p[Kind.right_shift_assign] = .assign
|
p[Kind.right_shift_assign] = .assign
|
||||||
|
p[Kind.unsigned_right_shift_assign] = .assign
|
||||||
p[Kind.mult_assign] = .assign
|
p[Kind.mult_assign] = .assign
|
||||||
p[Kind.xor_assign] = .assign
|
p[Kind.xor_assign] = .assign
|
||||||
p[Kind.key_in] = .in_as
|
p[Kind.key_in] = .in_as
|
||||||
|
@ -474,7 +482,7 @@ pub fn (kind Kind) is_prefix() bool {
|
||||||
pub fn (kind Kind) is_infix() bool {
|
pub fn (kind Kind) is_infix() bool {
|
||||||
return kind in [.plus, .minus, .mod, .mul, .div, .eq, .ne, .gt, .lt, .key_in, .key_as, .ge,
|
return kind in [.plus, .minus, .mod, .mul, .div, .eq, .ne, .gt, .lt, .key_in, .key_as, .ge,
|
||||||
.le, .logical_or, .xor, .not_in, .key_is, .not_is, .and, .dot, .pipe, .amp, .left_shift,
|
.le, .logical_or, .xor, .not_in, .key_is, .not_is, .and, .dot, .pipe, .amp, .left_shift,
|
||||||
.right_shift, .arrow]
|
.right_shift, .unsigned_right_shift, .arrow]
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass ast.builtin_type_names
|
// Pass ast.builtin_type_names
|
||||||
|
|
Loading…
Reference in New Issue