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:
parent
ad9ca349dc
commit
2ebd3f0cdb
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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')
|
||||
|
18
vlib/v/tests/inout/comptime_bool_fields.out
Normal file
18
vlib/v/tests/inout/comptime_bool_fields.out
Normal 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
|
51
vlib/v/tests/inout/comptime_bool_fields.vv
Normal file
51
vlib/v/tests/inout/comptime_bool_fields.vv
Normal 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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user