Skip to content

Commit

Permalink
all: implement &&= and ||= (#21678)
Browse files Browse the repository at this point in the history
  • Loading branch information
Delta456 authored Jun 14, 2024
1 parent 2de0b36 commit add1621
Show file tree
Hide file tree
Showing 7 changed files with 81 additions and 1 deletion.
9 changes: 9 additions & 0 deletions vlib/v/checker/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,15 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
right.pos())
}
}
.boolean_and_assign, .boolean_or_assign {
if c.table.final_sym(left_type_unwrapped).kind != .bool {
c.error('operator ${node.op.str()} not defined on left operand type `${left_sym.name}`',
left.pos())
} else if c.table.final_sym(right_type_unwrapped).kind != .bool {
c.error('operator ${node.op.str()} not defined on right operand type `${right_sym.name}`',
right.pos())
}
}
.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.',
Expand Down
12 changes: 12 additions & 0 deletions vlib/v/checker/tests/mismatch_bool_assign_err.out
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
vlib/v/checker/tests/mismatch_bool_assign_err.vv:2:1: error: operator ||= not defined on left operand type `int`
1 | mut b := 12
2 | b ||= 34
| ^
3 | println(b)
4 |
vlib/v/checker/tests/mismatch_bool_assign_err.vv:6:1: error: operator &&= not defined on left operand type `string`
4 |
5 | mut c := 'str'
6 | c &&= 's'
| ^
7 | println(c)
7 changes: 7 additions & 0 deletions vlib/v/checker/tests/mismatch_bool_assign_err.vv
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
mut b := 12
b ||= 34
println(b)

mut c := 'str'
c &&= 's'
println(c)
22 changes: 22 additions & 0 deletions vlib/v/gen/c/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,28 @@ fn (mut g Gen) assign_stmt(node_ ast.AssignStmt) {
op_overloaded = true
}
}

if left_sym.kind == .bool && right_sym.kind == .bool
&& node.op in [.boolean_or_assign, .boolean_and_assign] {
extracted_op := match node.op {
.boolean_or_assign {
'||'
}
.boolean_and_assign {
'&&'
}
else {
'unknown op'
}
}
g.expr(left)
g.write(' = ')
g.expr(left)
g.write(' ${extracted_op} ')
g.expr(val)
g.writeln(';')
return
}
if right_sym.info is ast.FnType && is_decl {
if is_inside_ternary {
g.out.write_string(util.tabs(g.indent - g.inside_ternary))
Expand Down
10 changes: 10 additions & 0 deletions vlib/v/scanner/scanner.v
Original file line number Diff line number Diff line change
Expand Up @@ -872,6 +872,12 @@ pub fn (mut s Scanner) text_scan() token.Token {
}
}
`&` {
if nextc == `&` {
if s.look_ahead(2) == `=` {
s.pos += 2
return s.new_token(.boolean_and_assign, '', 3)
}
}
if nextc == `=` {
s.pos++
return s.new_token(.and_assign, '', 2)
Expand All @@ -885,6 +891,10 @@ pub fn (mut s Scanner) text_scan() token.Token {
}
`|` {
if nextc == `|` {
if s.look_ahead(2) == `=` {
s.pos += 2
return s.new_token(.boolean_or_assign, '', 3)
}
s.pos++
return s.new_token(.logical_or, '', 2)
}
Expand Down
8 changes: 8 additions & 0 deletions vlib/v/tests/bool_assign_operator_test.v
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
fn test_bool_assign_operator() {
mut flag := true
flag ||= false
assert flag == true

flag &&= false
assert flag == false
}
14 changes: 13 additions & 1 deletion vlib/v/token/token.v
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ pub enum Kind {
right_shift_assign // <<=
left_shift_assign // >>=
unsigned_right_shift_assign // >>>=
boolean_and_assign // &&=
boolean_or_assign // ||=
lcbr // {
rcbr // }
lpar // (
Expand Down Expand Up @@ -186,7 +188,7 @@ pub enum AtKind {

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,
.unsigned_right_shift_assign]
.unsigned_right_shift_assign, .boolean_and_assign, .boolean_or_assign]

pub const valid_at_tokens = ['@VROOT', '@VMODROOT', '@VEXEROOT', '@FN', '@METHOD', '@MOD', '@STRUCT',
'@VEXE', '@FILE', '@LINE', '@COLUMN', '@VHASH', '@VCURRENTHASH', '@VMOD_FILE', '@VMODHASH',
Expand Down Expand Up @@ -261,6 +263,8 @@ fn build_token_str() []string {
s[Kind.right_shift_assign] = '>>='
s[Kind.unsigned_right_shift_assign] = '>>>='
s[Kind.left_shift_assign] = '<<='
s[Kind.boolean_or_assign] = '||='
s[Kind.boolean_and_assign] = '&&='
s[Kind.lcbr] = '{'
s[Kind.rcbr] = '}'
s[Kind.lpar] = '('
Expand Down Expand Up @@ -468,6 +472,8 @@ pub fn build_precedences() []Precedence {
p[Kind.unsigned_right_shift_assign] = .assign
p[Kind.mult_assign] = .assign
p[Kind.xor_assign] = .assign
p[Kind.boolean_or_assign] = .assign
p[Kind.boolean_and_assign] = .assign
p[Kind.key_in] = .in_as
p[Kind.not_in] = .in_as
p[Kind.key_as] = .in_as
Expand Down Expand Up @@ -583,6 +589,8 @@ pub fn kind_to_string(k Kind) string {
.right_shift_assign { 'right_shift_assign' }
.left_shift_assign { 'left_shift_assign' }
.unsigned_right_shift_assign { 'unsigned_right_shift_assign' }
.boolean_and_assign { 'boolean_and_assign' }
.boolean_or_assign { 'boolean_or_assign' }
.lcbr { 'lcbr' }
.rcbr { 'rcbr' }
.lpar { 'lpar' }
Expand Down Expand Up @@ -707,6 +715,8 @@ pub fn kind_from_string(s string) !Kind {
'right_shift_assign' { .right_shift_assign }
'left_shift_assign' { .left_shift_assign }
'unsigned_right_shift_assign' { .unsigned_right_shift_assign }
'boolean_and_assign' { .boolean_and_assign }
'boolean_or_assign' { .boolean_or_assign }
'lcbr' { .lcbr }
'rcbr' { .rcbr }
'lpar' { .lpar }
Expand Down Expand Up @@ -793,6 +803,8 @@ pub fn assign_op_to_infix_op(op Kind) Kind {
.right_shift_assign { .right_shift }
.unsigned_right_shift_assign { .unsigned_right_shift }
.left_shift_assign { .left_shift }
.boolean_and_assign { .and }
.boolean_or_assign { .logical_or }
else { ._end_ }
}
}

0 comments on commit add1621

Please sign in to comment.