1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker,cgen: make boolean field.is_<field> accessible at compile-time as well (#16796)

This commit is contained in:
Felipe Pena 2022-12-28 19:19:47 -03:00 committed by GitHub
parent ad9ca349dc
commit 2ebd3f0cdb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 149 additions and 3 deletions

View File

@ -1183,7 +1183,13 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
}
}
}
// evaluates comptime field.<name> (from T.fields)
if c.check_comptime_is_field_selector(node) {
if c.check_comptime_is_field_selector_bool(node) {
node.expr_type = ast.bool_type
return node.expr_type
}
}
old_selector_expr := c.inside_selector_expr
c.inside_selector_expr = true
mut typ := c.expr(node.expr)

View File

@ -562,6 +562,12 @@ fn (mut c Checker) comptime_if_branch(cond ast.Expr, pos token.Pos) ComptimeBran
.eq, .ne {
if cond.left is ast.SelectorExpr && cond.right is ast.IntegerLiteral {
// $if method.args.len == 1
} else if cond.left is ast.SelectorExpr
&& c.check_comptime_is_field_selector_bool(cond.left as ast.SelectorExpr) {
// field.is_public (from T.fields)
} else if cond.right is ast.SelectorExpr
&& c.check_comptime_is_field_selector_bool(cond.right as ast.SelectorExpr) {
// field.is_public (from T.fields)
} else if cond.left is ast.Ident {
// $if version == 2
left_type := c.expr(cond.left)
@ -716,9 +722,37 @@ fn (mut c Checker) comptime_if_branch(cond ast.Expr, pos token.Pos) ComptimeBran
}
return .eval
}
ast.SelectorExpr {
if c.check_comptime_is_field_selector(cond) {
if c.check_comptime_is_field_selector_bool(cond) {
return .eval
}
c.error('unknown field `${cond.field_name}` from ${c.comptime_for_field_var}',
cond.pos)
}
return .unknown
}
else {
c.error('invalid `\$if` condition', pos)
}
}
return .unknown
}
[inline]
fn (mut c Checker) check_comptime_is_field_selector(node ast.SelectorExpr) bool {
if c.inside_comptime_for_field && node.expr is ast.Ident {
return (node.expr as ast.Ident).name == c.comptime_for_field_var
}
return false
}
[inline]
fn (mut c Checker) check_comptime_is_field_selector_bool(node ast.SelectorExpr) bool {
if c.check_comptime_is_field_selector(node) {
bool_fields := ['is_mut', 'is_pub', 'is_shared', 'is_atomic', 'is_optional', 'is_array',
'is_map', 'is_chan', 'is_struct']
return node.field_name in bool_fields
}
return false
}

View File

@ -17,6 +17,25 @@ fn (mut g Gen) get_comptime_selector_var_type(node ast.ComptimeSelector) (ast.St
return field, field_name
}
fn (mut g Gen) get_comptime_selector_bool_field(field_name string) bool {
field := g.comptime_for_field_value
field_typ := g.comptime_for_field_type
field_sym := g.table.sym(g.unwrap_generic(g.comptime_for_field_type))
match field_name {
'is_pub' { return field.is_pub }
'is_mut' { return field.is_mut }
'is_shared' { return field_typ.has_flag(.shared_f) }
'is_atomic' { return field_typ.has_flag(.atomic_f) }
'is_optional' { return field.typ.has_flag(.optional) }
'is_array' { return field_sym.kind in [.array, .array_fixed] }
'is_map' { return field_sym.kind == .map }
'is_chan' { return field_sym.kind == .chan }
'is_struct' { return field_sym.kind == .struct_ }
else { return false }
}
}
fn (mut g Gen) comptime_selector(node ast.ComptimeSelector) {
g.expr(node.left)
if node.left_type.is_ptr() {
@ -443,8 +462,15 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) bool {
}
.eq, .ne {
// TODO Implement `$if method.args.len == 1`
g.write('1')
return true
if cond.left is ast.SelectorExpr || cond.right is ast.SelectorExpr {
l := g.comptime_if_cond(cond.left, pkg_exist)
g.write(' ${cond.op} ')
r := g.comptime_if_cond(cond.right, pkg_exist)
return if cond.op == .eq { l == r } else { l != r }
} else {
g.write('1')
return true
}
}
else {
return true
@ -460,6 +486,17 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) bool {
g.write('${pkg_exist}')
return true
}
ast.SelectorExpr {
if g.inside_comptime_for_field && cond.expr is ast.Ident
&& (cond.expr as ast.Ident).name == g.comptime_for_field_var && cond.field_name in ['is_mut', 'is_pub', 'is_shared', 'is_atomic', 'is_optional', 'is_array', 'is_map', 'is_chan', 'is_struct'] {
ret_bool := g.get_comptime_selector_bool_field(cond.field_name)
g.write(ret_bool.str())
return true
} else {
g.write('1')
return true
}
}
else {
// should be unreachable, but just in case
g.write('1')

View File

@ -0,0 +1,18 @@
field: a
a is mut?: true
field: b
b is mut?: true
b is struct?: true
field: c
c is pub?: true
c is optional?: true
field: d
d is pub?: true
d is map?: true
field: e
e is pub?: true
e is atomic?: true
field: f
f is pub?: true
f is mut?: true
f is array?: true

View File

@ -0,0 +1,51 @@
struct Bb {
mut:
a int
b struct {}
pub:
c ?string
d map[string]int
e atomic int
pub mut:
f []f64
}
fn foo[U](val U) {
$for field in U.fields {
println('field: ${field.name}')
$if field.is_pub == true {
println(field.name + ' is pub?: ${field.is_pub}')
}
$if field.is_mut {
println(field.name + ' is mut?: ${field.is_mut}')
}
$if field.is_struct {
println(field.name + ' is struct?: ${field.is_struct}')
}
$if field.is_chan {
println(field.name + ' is chan?: ${field.is_chan}')
}
$if field.is_array {
println(field.name + ' is array?: ${field.is_array}')
}
$if field.is_map {
println(field.name + ' is map?: ${field.is_map}')
}
$if field.is_shared {
println(field.name + ' is shared?: ${field.is_shared}')
}
$if field.is_optional {
println(field.name + ' is optional?: ${field.is_optional}')
}
$if field.is_atomic {
println(field.name + ' is atomic?: ${field.is_atomic}')
}
}
}
fn main() {
bb := Bb{}
foo(bb)
}