From c339ea2ce2b6066354b2f4a495d2ae472055a4e0 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Fri, 21 Apr 2023 13:43:47 -0300 Subject: [PATCH] checker, cgen: make comptime field.indirections working with logical operators (#17990) --- vlib/v/checker/comptime.v | 43 +++++++++- vlib/v/gen/c/comptime.v | 82 +++++++++++++++---- .../tests/comptime_field_indirections_test.v | 32 ++++++++ 3 files changed, 138 insertions(+), 19 deletions(-) create mode 100644 vlib/v/tests/comptime_field_indirections_test.v diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index e996bb6133..bfe5779ffd 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -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 { diff --git a/vlib/v/gen/c/comptime.v b/vlib/v/gen/c/comptime.v index 8244b3db97..a5462350ef 100644 --- a/vlib/v/gen/c/comptime.v +++ b/vlib/v/gen/c/comptime.v @@ -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 { diff --git a/vlib/v/tests/comptime_field_indirections_test.v b/vlib/v/tests/comptime_field_indirections_test.v new file mode 100644 index 0000000000..eb3f5e455a --- /dev/null +++ b/vlib/v/tests/comptime_field_indirections_test.v @@ -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)! +}