1
0
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:
Felipe Pena 2023-04-21 13:43:47 -03:00 committed by GitHub
parent 59d91e0514
commit c339ea2ce2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 138 additions and 19 deletions

View File

@ -655,6 +655,19 @@ fn (mut c Checker) comptime_if_branch(cond ast.Expr, pos token.Pos) ComptimeBran
.eq, .ne {
if cond.left is ast.SelectorExpr
&& 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
// $if method.args.len == 1
} 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)
}
}
.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 {
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
}
// 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]
fn (mut c Checker) is_comptime_selector_type(node ast.SelectorExpr) bool {
if c.inside_comptime_for_field && node.expr is ast.Ident {

View File

@ -537,28 +537,43 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) {
.eq, .ne {
// TODO Implement `$if method.args.len == 1`
if cond.left is ast.SelectorExpr
&& (g.comptime_for_field_var.len > 0 || g.comptime_for_method.len > 0)
&& cond.right is ast.StringLiteral {
selector := cond.left as ast.SelectorExpr
if selector.expr is ast.Ident && selector.field_name == 'name' {
if g.comptime_for_method_var.len > 0
&& (selector.expr as ast.Ident).name == g.comptime_for_method_var {
is_equal := g.comptime_for_method == cond.right.val
if is_equal {
&& (g.comptime_for_field_var.len > 0 || g.comptime_for_method.len > 0) {
if cond.right is ast.StringLiteral {
selector := cond.left as ast.SelectorExpr
if selector.expr is ast.Ident && selector.field_name == 'name' {
if g.comptime_for_method_var.len > 0
&& (selector.expr as ast.Ident).name == g.comptime_for_method_var {
is_equal := g.comptime_for_method == cond.right.val
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')
} 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
return is_true, true
}
}
}
@ -611,6 +626,30 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) {
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 {
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()
}
// 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
[inline]
fn (mut g Gen) is_comptime_selector_type(node ast.SelectorExpr) bool {

View 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)!
}