node: implement heredocs + string interpolation
This commit is contained in:
parent
5ba0185bcb
commit
df0061041f
41
node.go
41
node.go
@ -1465,6 +1465,19 @@ func (this *conversionState) convertNoFreeFloating(n_ node.Node) (string, error)
|
||||
|
||||
return quoteGoString(rawValue), nil // Go source code quoting format
|
||||
|
||||
case *scalar.EncapsedStringPart:
|
||||
// The n.Value that we receive here does not contain quotes at all
|
||||
// TODO what happens with embedded escape characters? Did the parser
|
||||
// remove them for us already or do we just have to assume we are in
|
||||
// a double-quoted-equivalent situation?
|
||||
return quoteGoString(n.Value), nil // Go source code quoting format
|
||||
|
||||
case *scalar.Encapsed:
|
||||
return this.convertEncapsedString(n.Parts)
|
||||
|
||||
case *scalar.Heredoc:
|
||||
return this.convertEncapsedString(n.Parts)
|
||||
|
||||
case *scalar.MagicConstant:
|
||||
// magic constants are case-insensitive
|
||||
switch strings.ToLower(n.Value) {
|
||||
@ -1599,6 +1612,13 @@ func removeParens(expr string) string {
|
||||
return expr
|
||||
}
|
||||
|
||||
// asSingleExpression makes the expr into a single expression that is safe for
|
||||
// embedding in a larger statement e.g. multiple string concatenation.
|
||||
func asSingleExpression(expr string) string {
|
||||
return `(` + removeParens(expr) + `)`
|
||||
// TODO simplify this in cases where we can tell it is already a single expression e.g. quoted strings, number literals, variable literals, ...
|
||||
}
|
||||
|
||||
func quoteGoString(s string) string {
|
||||
|
||||
if !strings.Contains(s, "`") && strings.Count(s, "\n") >= 3 { // TODO make the heuristic configurable
|
||||
@ -1611,6 +1631,27 @@ func quoteGoString(s string) string {
|
||||
}
|
||||
|
||||
func (this *conversionState) convertEncapsedString(parts []node.Node) (string, error) {
|
||||
// This is used for string interpolation: `echo "bar $ref";`
|
||||
// And also for heredocs
|
||||
// Child nodes are either EncapsedStringPart or expr.**
|
||||
ret := make([]string, 0, len(parts))
|
||||
for _, part := range parts {
|
||||
pp, err := this.convert(part)
|
||||
if err != nil {
|
||||
return "", parseErr{part, err}
|
||||
}
|
||||
|
||||
if _, ok := part.(*scalar.EncapsedStringPart); !ok {
|
||||
// Subexpression - should probably parenthesise just in case
|
||||
pp = asSingleExpression(pp)
|
||||
}
|
||||
|
||||
ret = append(ret, pp)
|
||||
}
|
||||
|
||||
return `(` + strings.Join(ret, ` + `) + `)`, nil
|
||||
}
|
||||
|
||||
// resolveName turns a `*name.Name` node into a Go string.
|
||||
func (this *conversionState) resolveName(n node.Node) (string, error) {
|
||||
// TODO support namespace lookups
|
||||
|
Loading…
Reference in New Issue
Block a user