diff --git a/node.go b/node.go index 5d66600..e651955 100644 --- a/node.go +++ b/node.go @@ -1614,10 +1614,13 @@ func (this *conversionState) convertNoFreeFloating(n_ node.Node) (string, error) 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 + // But it is still a fragment of a double-quoted string + rawValue, err := phpUnquote(`"` + strings.Replace(n.Value, `"`, `\"`, -1) + `"`) + if err != nil { + return "", parseErr{n, err} + } + + return quoteGoString(rawValue), nil // Go source code quoting format case *scalar.Encapsed: return this.convertEncapsedString(n.Parts) diff --git a/quote.go b/quote.go index 1762917..6ccc8b8 100644 --- a/quote.go +++ b/quote.go @@ -2,6 +2,7 @@ package main import ( "errors" + "fmt" "strconv" "strings" ) @@ -13,10 +14,20 @@ func phpUnquote(s string) (string, error) { if s[0] == '"' { // Quote system is similar enough to Go's that strconv will probably just work - // PHP has some lax parsing for unknown escape sequences + + // PROBLEM 1: PHP has some lax parsing for unknown escape sequences // e.g. regex("foo\.") will be silently parsed as regex("foo.") - return strconv.Unquote(s) + // PROBLEM 2: PHP supports multiline string literals, strconv.Unquote does not + // Apply fixup + s2 := strings.Replace(strings.Replace(s, "\r", `\r`, -1), "\n", `\n`, -1) + + ret, err := strconv.Unquote(s2) + if err != nil { + return "", fmt.Errorf("Parsing string literal `%s`: %v", s, err) + } + + return ret, nil } if s[0] == '\'' {