From 5d44cd28db5ed867a7e41a6197eec1c1914d3c5f Mon Sep 17 00:00:00 2001 From: James Shubin Date: Fri, 6 Jun 2025 00:35:52 -0400 Subject: [PATCH] lang: ast, interpolate: Pass through uninterpolated strings We don't need to make a new reference for nothing. --- lang/ast/structs.go | 3 ++- lang/interpolate/interpolate.go | 25 +++++++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/lang/ast/structs.go b/lang/ast/structs.go index c9f0a1ed..0a56ee2b 100644 --- a/lang/ast/structs.go +++ b/lang/ast/structs.go @@ -7527,7 +7527,8 @@ func (obj *ExprStr) Interpolate() (interfaces.Expr, error) { if err != nil { return nil, err } - if result == nil { + // a nil result means unchanged, string didn't need interpolating done + if result == nil { // we still copy since Interpolate always "copies" return &ExprStr{ Textarea: obj.Textarea, data: obj.data, diff --git a/lang/interpolate/interpolate.go b/lang/interpolate/interpolate.go index 16409006..c825833f 100644 --- a/lang/interpolate/interpolate.go +++ b/lang/interpolate/interpolate.go @@ -55,7 +55,8 @@ const ( UseOptimizedConcat = true ) -// StrInterpolate interpolates a string and returns the representative AST. +// StrInterpolate interpolates a string and returns the representative AST. If +// there was nothing to interpolate, this returns (nil, nil). func StrInterpolate(str string, pos *interfaces.Pos, data *interfaces.Data) (interfaces.Expr, error) { if data.Debug { data.Logf("interpolating: %s", str) @@ -68,13 +69,25 @@ func StrInterpolate(str string, pos *interfaces.Pos, data *interfaces.Data) (int } // RagelInterpolate interpolates a string and returns the representative AST. It -// uses the ragel parser to perform the string interpolation. +// uses the ragel parser to perform the string interpolation. If there was +// nothing to interpolate, this returns (nil, nil). func RagelInterpolate(str string, pos *interfaces.Pos, data *interfaces.Data) (interfaces.Expr, error) { sequence, err := Parse(str) if err != nil { return nil, errwrap.Wrapf(err, "parser failed") } + // If we didn't find anything of value, we got an empty string... + if len(sequence) == 0 && str == "" { // be doubly sure... + return nil, nil // pass through, nothing changed + } + + if len(sequence) == 1 { + if x, ok := sequence[0].(Literal); ok && x.Value == str { + return nil, nil // pass through, nothing changed + } + } + exprs := []interfaces.Expr{} for _, term := range sequence { @@ -95,14 +108,6 @@ func RagelInterpolate(str string, pos *interfaces.Pos, data *interfaces.Data) (i } } - // If we didn't find anything of value, we got an empty string... - if len(sequence) == 0 && str == "" { // be doubly sure... - expr := &ast.ExprStr{ - V: "", - } - exprs = append(exprs, expr) - } - // The parser produces non-optimal results where two strings are next to // each other, when they could be statically combined together. simplified, err := simplifyExprList(exprs)