diff --git a/vlib/v/ast/ast.v b/vlib/v/ast/ast.v index b88d15b479d6d2..ba60ae82f4e6b4 100644 --- a/vlib/v/ast/ast.v +++ b/vlib/v/ast/ast.v @@ -610,6 +610,8 @@ pub mut: scope &Scope = unsafe { nil } label_names []string pos token.Pos // function declaration position + // + is_expand_simple_interpolation bool // true, when @[expand_simple_interpolation] is used on a fn. It should have a single string argument. } pub fn (f &FnDecl) new_method_with_receiver_type(new_type_ Type) FnDecl { @@ -682,6 +684,10 @@ pub mut: ctdefine_idx int // the index of the attribute, containing the compile time define [if mytag] from_embedded_type Type // for interface only, fn from the embedded interface from_embeded_type Type @[deprecated: 'use from_embedded_type instead'; deprecated_after: '2024-03-31'] + // + is_expand_simple_interpolation bool // for tagging b.f(s string), which is then called with `b.f('some $x $y')`, + // when that call, should be expanded to `b.f('some '); b.f(x); b.f(' '); b.f(y);` + // Note: the same type, has to support also a .write_decimal(n i64) method. } fn (f &Fn) method_equals(o &Fn) bool { @@ -805,6 +811,10 @@ pub mut: scope &Scope = unsafe { nil } from_embed_types []Type // holds the type of the embed that the method is called from comments []Comment + // + is_expand_simple_interpolation bool // true, when the function/method is marked as @[expand_simple_interpolation] + // Calls to it with an interpolation argument like `b.f('x ${y}')`, will be converted to `b.f('x ')` followed by `b.f(y)`. + // The same type, has to support also a .write_decimal(n i64) method. } /* diff --git a/vlib/v/checker/fn.v b/vlib/v/checker/fn.v index bcc693e90bf929..6588b76bf05b74 100644 --- a/vlib/v/checker/fn.v +++ b/vlib/v/checker/fn.v @@ -528,6 +528,23 @@ fn (mut c Checker) fn_decl(mut node ast.FnDecl) { } } } + if node.is_expand_simple_interpolation { + match true { + !node.is_method { + c.error('@[expand_simple_interpolation] is supported only on methods', + node.pos) + } + node.params.len != 2 { + c.error('methods tagged with @[expand_simple_interpolation], should have exactly 1 argument', + node.pos) + } + !node.params[1].typ.is_string() { + c.error('methods tagged with @[expand_simple_interpolation], should accept a single string', + node.pos) + } + else {} + } + } } // check_same_type_ignoring_pointers util function to check if the Types are the same, including all @@ -1180,6 +1197,7 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast. } node.is_file_translated = func.is_file_translated node.is_noreturn = func.is_noreturn + node.is_expand_simple_interpolation = func.is_expand_simple_interpolation node.is_ctor_new = func.is_ctor_new if !found_in_args { if node.scope.known_var(fn_name) { @@ -2330,6 +2348,7 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type { c.need_recheck_generic_fns = true } node.is_noreturn = method.is_noreturn + node.is_expand_simple_interpolation = method.is_expand_simple_interpolation node.is_ctor_new = method.is_ctor_new node.return_type = method.return_type if method.return_type.has_flag(.generic) { diff --git a/vlib/v/parser/fn.v b/vlib/v/parser/fn.v index 699779ff515fd7..b91a7eb6d9cbab 100644 --- a/vlib/v/parser/fn.v +++ b/vlib/v/parser/fn.v @@ -197,6 +197,7 @@ fn (mut p Parser) fn_decl() ast.FnDecl { mut is_ctor_new := false mut is_c2v_variadic := false mut is_markused := false + mut is_expand_simple_interpolation := false mut comments := []ast.Comment{} for fna in p.attrs { match fna.name { @@ -254,6 +255,9 @@ fn (mut p Parser) fn_decl() ast.FnDecl { p.prev_tok.pos()) } } + 'expand_simple_interpolation' { + is_expand_simple_interpolation = true + } else {} } } @@ -550,6 +554,8 @@ run them via `v file.v` instead', pos: start_pos name_pos: name_pos language: language + // + is_expand_simple_interpolation: is_expand_simple_interpolation }) } else { name = match language { @@ -603,6 +609,8 @@ run them via `v file.v` instead', pos: start_pos name_pos: name_pos language: language + // + is_expand_simple_interpolation: is_expand_simple_interpolation }) } /* @@ -688,6 +696,8 @@ run them via `v file.v` instead', label_names: p.label_names end_comments: p.eat_comments(same_line: true) comments: comments + // + is_expand_simple_interpolation: is_expand_simple_interpolation } if generic_names.len > 0 { p.table.register_fn_generic_types(fn_decl.fkey()) diff --git a/vlib/v/transformer/transformer.v b/vlib/v/transformer/transformer.v index 1458082bd3009d..279794a73b4969 100644 --- a/vlib/v/transformer/transformer.v +++ b/vlib/v/transformer/transformer.v @@ -248,11 +248,8 @@ pub fn (mut t Transformer) stmt(mut node ast.Stmt) ast.Stmt { t.expr(mut node.expr) } } - if mut node.expr is ast.CallExpr { - if node.expr.is_method && node.expr.left_type == t.strings_builder_type - && node.expr.name == 'write_string' { - t.simplify_nested_interpolation_in_sb(mut onode, mut node.expr, node.typ) - } + if mut node.expr is ast.CallExpr && node.expr.is_expand_simple_interpolation { + t.simplify_nested_interpolation_in_sb(mut onode, mut node.expr, node.typ) } } ast.FnDecl {