handle escaped backslashes (#1997)

This commit is contained in:
Matt Benson 2024-04-14 03:52:08 -05:00 committed by GitHub
parent db6f2dc6a2
commit b54d7eb21c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 54 additions and 26 deletions

View File

@ -54,40 +54,52 @@ func interpolate(d *dataTreeNavigator, context Context, str string) (string, err
for i := 0; i < len(runes); i++ {
char := runes[i]
if !inExpression {
if char == '\\' && i != len(runes)-1 && runes[i+1] == '(' {
inExpression = true
i = i + 1 // skip over the next open bracket
continue
if char == '\\' && i < len(runes)-1 {
switch runes[i+1] {
case '(':
inExpression = true
// skip the lparen
i++
continue
case '\\':
// skip the escaped backslash
i++
default:
log.Debugf("Ignoring non-escaping backslash @ %v[%d]", str, i)
}
}
sb.WriteRune(char)
} else { // we are in an expression
if char == ')' && nestedBracketsCounter == 0 {
// finished the expression!
log.Debugf("Expression is :%v", expSb.String())
value, err := evaluate(d, context, expSb.String())
if err != nil {
return "", err
if char == ')' {
if nestedBracketsCounter == 0 {
// finished the expression!
log.Debugf("Expression is :%v", expSb.String())
value, err := evaluate(d, context, expSb.String())
if err != nil {
return "", err
}
inExpression = false
expSb = strings.Builder{} // reset this
sb.WriteString(value)
continue
}
inExpression = false
expSb = strings.Builder{} // reset this
sb.WriteString(value)
continue
nestedBracketsCounter--
} else if char == '(' {
nestedBracketsCounter++
} else if char == '\\' && i != len(runes)-1 && runes[i+1] == ')' {
// close brackets is escaped, skip over it
expSb.WriteRune(char)
expSb.WriteRune(runes[i+1])
i = i + 1
continue
} else if char == ')' {
nestedBracketsCounter--
} else if char == '\\' && i < len(runes)-1 {
switch esc := runes[i+1]; esc {
case ')', '\\':
// write escaped character
expSb.WriteRune(esc)
i++
continue
default:
log.Debugf("Ignoring non-escaping backslash @ %v[%d]", str, i)
}
}
expSb.WriteRune(char)
}
}
if inExpression {
return "", fmt.Errorf("unclosed interpolation string \\(")

View File

@ -26,7 +26,7 @@ var stringsOperatorScenarios = []expressionScenario{
description: "Interpolation - just escape",
expression: `"\\"`,
expected: []string{
"D0, P[], (!!str)::\\\\\n",
"D0, P[], (!!str)::\\\n",
},
},
{
@ -47,6 +47,15 @@ var stringsOperatorScenarios = []expressionScenario{
"D0, P[], (!!str)::Hi (.value)\n",
},
},
{
skipDoc: true,
description: "Interpolation - don't!",
document: `value: things`,
expression: `"Hi \\(.value)"`,
expected: []string{
"D0, P[], (!!str)::Hi \\(.value)\n",
},
},
{
skipDoc: true,
description: "Interpolation - random close bracket",
@ -63,6 +72,13 @@ var stringsOperatorScenarios = []expressionScenario{
expression: `"Hi \("`,
expectedError: "unclosed interpolation string \\(",
},
{
skipDoc: true,
description: "Interpolation - unclosed interpolation string due to escape",
document: `value: things`,
expression: `"Hi \(\)"`,
expectedError: "unclosed interpolation string \\(",
},
{
description: "To up (upper) case",
subdescription: "Works with unicode characters",