From c0bdb4a47b2a9f61683281f9b7fff5ce19a5da41 Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Sun, 8 Jun 2025 15:21:29 +0530 Subject: [PATCH] v: implement `expr.remove_para` (#24669) --- vlib/v/ast/ast.v | 11 ++++++++++- vlib/v/checker/assign.v | 9 ++------- vlib/v/checker/checker.v | 5 +---- vlib/v/checker/fn.v | 4 +--- vlib/v/fmt/fmt.v | 8 ++------ vlib/v/gen/golang/golang.v | 8 ++------ vlib/v/parser/expr.v | 4 +--- 7 files changed, 19 insertions(+), 30 deletions(-) diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index 943e661be9..18ae4d85c4 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -1571,7 +1571,7 @@ pub: has_len bool has_cap bool has_init bool - has_index bool // true if temp variable index is used + has_index bool // true if temp variable index is used pub mut: exprs []Expr // `[expr, expr]` or `[expr]Type{}` for fixed array len_expr Expr // len: expr @@ -2728,6 +2728,15 @@ pub fn (expr Expr) is_reference() bool { } } +// remove_par removes all parenthesis and gets the innermost Expr +pub fn (mut expr Expr) remove_par() Expr { + mut e := expr + for mut e is ParExpr { + e = e.expr + } + return e +} + // is `expr` a literal, i.e. it does not depend on any other declarations (C compile time constant) pub fn (expr Expr) is_literal() bool { return match expr { diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index d11f5955d0..94b5302fb6 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -339,10 +339,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) { if left is ast.ParExpr && is_decl { c.error('parentheses are not supported on the left side of `:=`', left.pos()) } - - for left is ast.ParExpr { - left = (left as ast.ParExpr).expr - } + left = left.remove_par() is_assign := node.op in [.assign, .decl_assign] match mut left { ast.Ident { @@ -943,9 +940,7 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.', c.inside_ref_lit = old_inside_ref_lit if right_node.op == .amp { mut expr := right_node.right - for mut expr is ast.ParExpr { - expr = expr.expr - } + expr = expr.remove_par() if mut expr is ast.Ident { if mut expr.obj is ast.Var { v := expr.obj diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index a18225b3e9..eca69b8ccc 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -4767,10 +4767,7 @@ fn (mut c Checker) prefix_expr(mut node ast.PrefixExpr) ast.Type { c.inside_ref_lit = old_inside_ref_lit node.right_type = right_type mut expr := node.right - // if ParExpr get the innermost expr - for mut expr is ast.ParExpr { - expr = expr.expr - } + expr = expr.remove_par() if node.op == .amp { if expr is ast.Nil { c.error('invalid operation: cannot take address of nil', expr.pos()) diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index bbc8a23fc8..3f05551496 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -1983,9 +1983,7 @@ fn (mut c Checker) check_type_and_visibility(name string, type_idx int, expected fn (mut c Checker) method_call(mut node ast.CallExpr, mut continue_check &bool) ast.Type { // `(if true { 'foo.bar' } else { 'foo.bar.baz' }).all_after('foo.')` mut left_expr := node.left - for mut left_expr is ast.ParExpr { - left_expr = left_expr.expr - } + left_expr = left_expr.remove_par() if mut left_expr is ast.IfExpr { if left_expr.branches.len > 0 && left_expr.has_else { mut last_stmt := left_expr.branches[0].stmts.last() diff --git a/vlib/v/fmt/fmt.v b/vlib/v/fmt/fmt.v index 850af93b78..00e6a0bd9d 100644 --- a/vlib/v/fmt/fmt.v +++ b/vlib/v/fmt/fmt.v @@ -856,9 +856,7 @@ fn expr_is_single_line(expr ast.Expr) bool { pub fn (mut f Fmt) assert_stmt(node ast.AssertStmt) { f.write('assert ') mut expr := node.expr - for mut expr is ast.ParExpr { - expr = expr.expr - } + expr = expr.remove_par() f.expr(expr) if node.extra !is ast.EmptyExpr { f.write(', ') @@ -2935,9 +2933,7 @@ pub fn (mut f Fmt) or_expr(node ast.OrExpr) { pub fn (mut f Fmt) par_expr(node ast.ParExpr) { mut expr := node.expr - for mut expr is ast.ParExpr { - expr = expr.expr - } + expr = expr.remove_par() requires_paren := expr !is ast.Ident || node.comments.len > 0 if requires_paren { f.par_level++ diff --git a/vlib/v/gen/golang/golang.v b/vlib/v/gen/golang/golang.v index aba2c7e15b..52c6891a0f 100644 --- a/vlib/v/gen/golang/golang.v +++ b/vlib/v/gen/golang/golang.v @@ -729,9 +729,7 @@ fn expr_is_single_line(expr ast.Expr) bool { pub fn (mut f Gen) assert_stmt(node ast.AssertStmt) { f.write('assert ') mut expr := node.expr - for mut expr is ast.ParExpr { - expr = expr.expr - } + expr = expr.remove_par() f.expr(expr) f.writeln('') } @@ -2058,9 +2056,7 @@ pub fn (mut f Gen) par_expr(node ast.ParExpr) { f.write('(') } mut expr := node.expr - for mut expr is ast.ParExpr { - expr = expr.expr - } + expr = expr.remove_par() f.expr(expr) if requires_paren { f.par_level-- diff --git a/vlib/v/parser/expr.v b/vlib/v/parser/expr.v index 707b6e3d5b..a7cc6832d6 100644 --- a/vlib/v/parser/expr.v +++ b/vlib/v/parser/expr.v @@ -790,9 +790,7 @@ fn (mut p Parser) infix_expr(left ast.Expr) ast.Expr { p.inside_assign_rhs = old_assign_rhs if op in [.plus, .minus, .mul, .div, .mod, .lt, .eq] && mut right is ast.PrefixExpr { mut right_expr := right.right - for mut right_expr is ast.ParExpr { - right_expr = right_expr.expr - } + right_expr = right_expr.remove_par() if right.op in [.plus, .minus, .mul, .div, .mod, .lt, .eq] && right_expr.is_pure_literal() { p.error_with_pos('invalid expression: unexpected token `${op}`', right_op_pos) }