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
|
||||
>> right shift integer >> unsigned integer
|
||||
>>> unsigned right shift integer >> unsigned integer
|
||||
|
||||
|
||||
Precedence Operator
|
||||
5 * / % << >> &
|
||||
5 * / % << >> >>> &
|
||||
4 + - | ^
|
||||
3 == != < <= > >=
|
||||
2 &&
|
||||
|
@ -5570,5 +5571,5 @@ Precedence Operator
|
|||
Assignment Operators
|
||||
+= -= *= /= %=
|
||||
&= |= ^=
|
||||
>>= <<=
|
||||
>>= <<= >>>=
|
||||
```
|
||||
|
|
|
@ -1599,6 +1599,50 @@ pub fn (mut c Checker) infix_expr(mut node ast.InfixExpr) ast.Type {
|
|||
.right_shift {
|
||||
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 {
|
||||
right_expr := node.right
|
||||
mut typ := match right_expr {
|
||||
|
@ -4275,6 +4319,60 @@ pub fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
|
|||
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 {}
|
||||
}
|
||||
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 {
|
||||
p.inside_in_array = false
|
||||
}
|
||||
|
||||
p.expecting_type = prev_expecting_type
|
||||
if p.pref.is_vet && op in [.key_in, .not_in] && right is ast.ArrayInit
|
||||
&& (right as ast.ArrayInit).exprs.len == 1 {
|
||||
|
|
|
@ -936,11 +936,31 @@ fn (mut s Scanner) text_scan() token.Token {
|
|||
for typ in typs {
|
||||
// TODO: combine two ifs once logic shortcut with `.all()` is fixed
|
||||
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++
|
||||
return s.new_token(.right_shift, '', 2)
|
||||
}
|
||||
if !(typ[0].is_capital() && typ[1..].bytes().all(it.is_alnum()))
|
||||
&& 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++
|
||||
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)
|
||||
}
|
||||
}
|
||||
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++
|
||||
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
|
||||
left_shift // <<
|
||||
right_shift // >>
|
||||
unsigned_right_shift // >>>
|
||||
not_in // !in
|
||||
not_is // !is
|
||||
assign // =
|
||||
|
@ -62,6 +63,7 @@ pub enum Kind {
|
|||
and_assign // &=
|
||||
right_shift_assign // <<=
|
||||
left_shift_assign // >>=
|
||||
unsigned_right_shift_assign // >>>=
|
||||
lcbr // {
|
||||
rcbr // }
|
||||
lpar // (
|
||||
|
@ -131,7 +133,9 @@ pub enum Kind {
|
|||
|
||||
pub const (
|
||||
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 (
|
||||
|
@ -238,6 +242,7 @@ fn build_token_str() []string {
|
|||
s[Kind.or_assign] = '|='
|
||||
s[Kind.and_assign] = '&='
|
||||
s[Kind.right_shift_assign] = '>>='
|
||||
s[Kind.unsigned_right_shift_assign] = '>>>='
|
||||
s[Kind.left_shift_assign] = '<<='
|
||||
s[Kind.lcbr] = '{'
|
||||
s[Kind.rcbr] = '}'
|
||||
|
@ -254,6 +259,7 @@ fn build_token_str() []string {
|
|||
s[Kind.question] = '?'
|
||||
s[Kind.left_shift] = '<<'
|
||||
s[Kind.right_shift] = '>>'
|
||||
s[Kind.unsigned_right_shift] = '>>>'
|
||||
s[Kind.comment] = 'comment'
|
||||
s[Kind.nl] = 'NLL'
|
||||
s[Kind.dollar] = '$'
|
||||
|
@ -372,7 +378,7 @@ pub enum Precedence {
|
|||
eq // == or !=
|
||||
// less_greater // > or <
|
||||
sum // + - | ^
|
||||
product // * / << >> &
|
||||
product // * / << >> >>> &
|
||||
// mod // %
|
||||
prefix // -X or !X
|
||||
postfix // ++ or --
|
||||
|
@ -388,12 +394,13 @@ pub fn build_precedences() []Precedence {
|
|||
p[Kind.inc] = .postfix
|
||||
p[Kind.dec] = .postfix
|
||||
p[Kind.question] = .postfix
|
||||
// `*` | `/` | `%` | `<<` | `>>` | `&`
|
||||
// `*` | `/` | `%` | `<<` | `>>` | `>>>` | `&`
|
||||
p[Kind.mul] = .product
|
||||
p[Kind.div] = .product
|
||||
p[Kind.mod] = .product
|
||||
p[Kind.left_shift] = .product
|
||||
p[Kind.right_shift] = .product
|
||||
p[Kind.unsigned_right_shift] = .product
|
||||
p[Kind.amp] = .product
|
||||
p[Kind.arrow] = .product
|
||||
// `+` | `-` | `|` | `^`
|
||||
|
@ -419,6 +426,7 @@ pub fn build_precedences() []Precedence {
|
|||
// <<= | *= | ...
|
||||
p[Kind.left_shift_assign] = .assign
|
||||
p[Kind.right_shift_assign] = .assign
|
||||
p[Kind.unsigned_right_shift_assign] = .assign
|
||||
p[Kind.mult_assign] = .assign
|
||||
p[Kind.xor_assign] = .assign
|
||||
p[Kind.key_in] = .in_as
|
||||
|
@ -474,7 +482,7 @@ pub fn (kind Kind) is_prefix() 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,
|
||||
.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
|
||||
|
|
Loading…
Reference in New Issue