mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker, cgen: make comptime field.indirections working with logical operators (#17990)
This commit is contained in:
parent
59d91e0514
commit
c339ea2ce2
@ -655,6 +655,19 @@ fn (mut c Checker) comptime_if_branch(cond ast.Expr, pos token.Pos) ComptimeBran
|
|||||||
.eq, .ne {
|
.eq, .ne {
|
||||||
if cond.left is ast.SelectorExpr
|
if cond.left is ast.SelectorExpr
|
||||||
&& cond.right in [ast.IntegerLiteral, ast.StringLiteral] {
|
&& cond.right in [ast.IntegerLiteral, ast.StringLiteral] {
|
||||||
|
if cond.right is ast.IntegerLiteral
|
||||||
|
&& c.is_comptime_selector_field_name(cond.left as ast.SelectorExpr, 'indirections') {
|
||||||
|
ret := match cond.op {
|
||||||
|
.eq { c.comptime_fields_default_type.nr_muls() == cond.right.val.i64() }
|
||||||
|
.ne { c.comptime_fields_default_type.nr_muls() != cond.right.val.i64() }
|
||||||
|
else { false }
|
||||||
|
}
|
||||||
|
return if ret {
|
||||||
|
ComptimeBranchSkipState.eval
|
||||||
|
} else {
|
||||||
|
ComptimeBranchSkipState.skip
|
||||||
|
}
|
||||||
|
}
|
||||||
return .unknown
|
return .unknown
|
||||||
// $if method.args.len == 1
|
// $if method.args.len == 1
|
||||||
} else if cond.left is ast.SelectorExpr
|
} else if cond.left is ast.SelectorExpr
|
||||||
@ -711,6 +724,27 @@ fn (mut c Checker) comptime_if_branch(cond ast.Expr, pos token.Pos) ComptimeBran
|
|||||||
c.error('invalid `\$if` condition', cond.pos)
|
c.error('invalid `\$if` condition', cond.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.gt, .lt, .ge, .le {
|
||||||
|
if cond.left is ast.SelectorExpr && cond.right is ast.IntegerLiteral {
|
||||||
|
if c.is_comptime_selector_field_name(cond.left as ast.SelectorExpr,
|
||||||
|
'indirections')
|
||||||
|
{
|
||||||
|
ret := match cond.op {
|
||||||
|
.gt { c.comptime_fields_default_type.nr_muls() > cond.right.val.i64() }
|
||||||
|
.lt { c.comptime_fields_default_type.nr_muls() < cond.right.val.i64() }
|
||||||
|
.ge { c.comptime_fields_default_type.nr_muls() >= cond.right.val.i64() }
|
||||||
|
.le { c.comptime_fields_default_type.nr_muls() <= cond.right.val.i64() }
|
||||||
|
else { false }
|
||||||
|
}
|
||||||
|
return if ret {
|
||||||
|
ComptimeBranchSkipState.eval
|
||||||
|
} else {
|
||||||
|
ComptimeBranchSkipState.skip
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.error('invalid `\$if` condition', cond.pos)
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
c.error('invalid `\$if` condition', cond.pos)
|
c.error('invalid `\$if` condition', cond.pos)
|
||||||
}
|
}
|
||||||
@ -858,7 +892,14 @@ fn (mut c Checker) get_comptime_selector_type(node ast.ComptimeSelector, default
|
|||||||
return default_type
|
return default_type
|
||||||
}
|
}
|
||||||
|
|
||||||
// check_comptime_is_field_selector checks if the SelectorExpr is related to $for variable accessing .typ field
|
// is_comptime_selector_field_name checks if the SelectorExpr is related to $for variable accessing specific field name provided by `field_name`
|
||||||
|
[inline]
|
||||||
|
fn (mut c Checker) is_comptime_selector_field_name(node ast.SelectorExpr, field_name string) bool {
|
||||||
|
return c.inside_comptime_for_field && node.expr is ast.Ident
|
||||||
|
&& (node.expr as ast.Ident).name == c.comptime_for_field_var && node.field_name == field_name
|
||||||
|
}
|
||||||
|
|
||||||
|
// is_comptime_selector_type checks if the SelectorExpr is related to $for variable accessing .typ field
|
||||||
[inline]
|
[inline]
|
||||||
fn (mut c Checker) is_comptime_selector_type(node ast.SelectorExpr) bool {
|
fn (mut c Checker) is_comptime_selector_type(node ast.SelectorExpr) bool {
|
||||||
if c.inside_comptime_for_field && node.expr is ast.Ident {
|
if c.inside_comptime_for_field && node.expr is ast.Ident {
|
||||||
|
@ -537,28 +537,43 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) {
|
|||||||
.eq, .ne {
|
.eq, .ne {
|
||||||
// TODO Implement `$if method.args.len == 1`
|
// TODO Implement `$if method.args.len == 1`
|
||||||
if cond.left is ast.SelectorExpr
|
if cond.left is ast.SelectorExpr
|
||||||
&& (g.comptime_for_field_var.len > 0 || g.comptime_for_method.len > 0)
|
&& (g.comptime_for_field_var.len > 0 || g.comptime_for_method.len > 0) {
|
||||||
&& cond.right is ast.StringLiteral {
|
if cond.right is ast.StringLiteral {
|
||||||
selector := cond.left as ast.SelectorExpr
|
selector := cond.left as ast.SelectorExpr
|
||||||
if selector.expr is ast.Ident && selector.field_name == 'name' {
|
if selector.expr is ast.Ident && selector.field_name == 'name' {
|
||||||
if g.comptime_for_method_var.len > 0
|
if g.comptime_for_method_var.len > 0
|
||||||
&& (selector.expr as ast.Ident).name == g.comptime_for_method_var {
|
&& (selector.expr as ast.Ident).name == g.comptime_for_method_var {
|
||||||
is_equal := g.comptime_for_method == cond.right.val
|
is_equal := g.comptime_for_method == cond.right.val
|
||||||
if is_equal {
|
if is_equal {
|
||||||
|
g.write('1')
|
||||||
|
} else {
|
||||||
|
g.write('0')
|
||||||
|
}
|
||||||
|
return is_equal, true
|
||||||
|
} else if g.comptime_for_field_var.len > 0
|
||||||
|
&& (selector.expr as ast.Ident).name == g.comptime_for_field_var {
|
||||||
|
is_equal := g.comptime_for_field_value.name == cond.right.val
|
||||||
|
if is_equal {
|
||||||
|
g.write('1')
|
||||||
|
} else {
|
||||||
|
g.write('0')
|
||||||
|
}
|
||||||
|
return is_equal, true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if cond.right is ast.IntegerLiteral {
|
||||||
|
if g.is_comptime_selector_field_name(cond.left, 'indirections') {
|
||||||
|
is_true := match cond.op {
|
||||||
|
.eq { g.comptime_for_field_type.nr_muls() == cond.right.val.i64() }
|
||||||
|
.ne { g.comptime_for_field_type.nr_muls() != cond.right.val.i64() }
|
||||||
|
else { false }
|
||||||
|
}
|
||||||
|
if is_true {
|
||||||
g.write('1')
|
g.write('1')
|
||||||
} else {
|
} else {
|
||||||
g.write('0')
|
g.write('0')
|
||||||
}
|
}
|
||||||
return is_equal, true
|
return is_true, true
|
||||||
} else if g.comptime_for_field_var.len > 0
|
|
||||||
&& (selector.expr as ast.Ident).name == g.comptime_for_field_var {
|
|
||||||
is_equal := g.comptime_for_field_value.name == cond.right.val
|
|
||||||
if is_equal {
|
|
||||||
g.write('1')
|
|
||||||
} else {
|
|
||||||
g.write('0')
|
|
||||||
}
|
|
||||||
return is_equal, true
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -611,6 +626,30 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) {
|
|||||||
return true, true
|
return true, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.gt, .lt, .ge, .le {
|
||||||
|
if cond.left is ast.SelectorExpr && cond.right is ast.IntegerLiteral {
|
||||||
|
if g.is_comptime_selector_field_name(cond.left as ast.SelectorExpr,
|
||||||
|
'indirections')
|
||||||
|
{
|
||||||
|
is_true := match cond.op {
|
||||||
|
.gt { g.comptime_for_field_type.nr_muls() > cond.right.val.i64() }
|
||||||
|
.lt { g.comptime_for_field_type.nr_muls() < cond.right.val.i64() }
|
||||||
|
.ge { g.comptime_for_field_type.nr_muls() >= cond.right.val.i64() }
|
||||||
|
.le { g.comptime_for_field_type.nr_muls() <= cond.right.val.i64() }
|
||||||
|
else { false }
|
||||||
|
}
|
||||||
|
if is_true {
|
||||||
|
g.write('1')
|
||||||
|
} else {
|
||||||
|
g.write('0')
|
||||||
|
}
|
||||||
|
return is_true, true
|
||||||
|
} else {
|
||||||
|
return true, false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true, false
|
||||||
|
}
|
||||||
else {
|
else {
|
||||||
return true, false
|
return true, false
|
||||||
}
|
}
|
||||||
@ -679,6 +718,13 @@ fn (mut g Gen) pop_existing_comptime_values() {
|
|||||||
g.comptime_var_type_map = old.comptime_var_type_map.clone()
|
g.comptime_var_type_map = old.comptime_var_type_map.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// is_comptime_selector_field_name checks if the SelectorExpr is related to $for variable accessing specific field name provided by `field_name`
|
||||||
|
[inline]
|
||||||
|
fn (mut g Gen) is_comptime_selector_field_name(node ast.SelectorExpr, field_name string) bool {
|
||||||
|
return g.inside_comptime_for_field && node.expr is ast.Ident
|
||||||
|
&& (node.expr as ast.Ident).name == g.comptime_for_field_var && node.field_name == field_name
|
||||||
|
}
|
||||||
|
|
||||||
// check_comptime_is_field_selector checks if the SelectorExpr is related to $for variable accessing .typ field
|
// check_comptime_is_field_selector checks if the SelectorExpr is related to $for variable accessing .typ field
|
||||||
[inline]
|
[inline]
|
||||||
fn (mut g Gen) is_comptime_selector_type(node ast.SelectorExpr) bool {
|
fn (mut g Gen) is_comptime_selector_type(node ast.SelectorExpr) bool {
|
||||||
|
32
vlib/v/tests/comptime_field_indirections_test.v
Normal file
32
vlib/v/tests/comptime_field_indirections_test.v
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
struct Encoder {}
|
||||||
|
|
||||||
|
struct Writer {}
|
||||||
|
|
||||||
|
struct StructType[T] {
|
||||||
|
mut:
|
||||||
|
val &T
|
||||||
|
val2 T
|
||||||
|
}
|
||||||
|
|
||||||
|
fn (e &Encoder) encode_struct[U](val U, mut wr Writer) ! {
|
||||||
|
$for field in U.fields {
|
||||||
|
if field.indirections == 1 {
|
||||||
|
assert field.indirections == 1
|
||||||
|
value := val.$(field.name)
|
||||||
|
$if field.indirections == 1 {
|
||||||
|
assert *value == 'ads'
|
||||||
|
} $else {
|
||||||
|
assert false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert field.name == 'val2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_indirection_checking() {
|
||||||
|
e := Encoder{}
|
||||||
|
mut sb := Writer{}
|
||||||
|
mut string_pointer := 'ads'
|
||||||
|
e.encode_struct(StructType[string]{ val: &string_pointer }, mut sb)!
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user