From 9a799fc3be27c0c80169aa179a3cfa2da86e4d45 Mon Sep 17 00:00:00 2001 From: z7zmey Date: Fri, 6 Apr 2018 00:24:00 +0300 Subject: [PATCH] scanner: fix heredoc --- scanner/scanner.go | 40 +++++++++++++--------- scanner/scanner.l | 43 +++++++++++++++--------- scanner/scanner_test.go | 73 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 31 deletions(-) diff --git a/scanner/scanner.go b/scanner/scanner.go index de99fd2..59b1847 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -8720,57 +8720,65 @@ yyrule152: // .|[ \t\n\r] searchLabel := []byte{} tb := []lex.Char{} - HEREDOCFOR: for { if c == -1 { break } + nls := 0 switch c { - case '\n': - fallthrough case '\r': + nls = 1 + c := l.Next() + if c != '\n' { + nls = 0 + l.ungetChars(0) + } + fallthrough + case '\n': if bytes.Equal(append(l.charsToBytes(heredocLabel), ';'), searchLabel) { l.begin(HEREDOC_END) - tb = l.ungetChars(len(heredocLabel) + 1) - break HEREDOCFOR + tb = l.ungetChars(len(heredocLabel) + 1 + nls) + lval.Token(l.newToken(tb)) + return T_ENCAPSED_AND_WHITESPACE } if bytes.Equal(l.charsToBytes(heredocLabel), searchLabel) { l.begin(HEREDOC_END) - tb = l.ungetChars(len(heredocLabel)) - break HEREDOCFOR + tb = l.ungetChars(len(heredocLabel) + nls) + lval.Token(l.newToken(tb)) + return T_ENCAPSED_AND_WHITESPACE } searchLabel = []byte{} case '$': c = l.Next() - if rune(c) == '{' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z' || c >= '\u007f' && c <= 'ÿ' { + if rune(c) == '{' || isValidFirstVarNameRune(rune(c)) { tb = l.ungetChars(1) - break HEREDOCFOR + lval.Token(l.newToken(tb)) + return T_ENCAPSED_AND_WHITESPACE } l.ungetChars(0) - searchLabel = []byte{} case '{': c = l.Next() if rune(c) == '$' { tb = l.ungetChars(1) - break HEREDOCFOR + lval.Token(l.newToken(tb)) + return T_ENCAPSED_AND_WHITESPACE } l.ungetChars(0) - searchLabel = []byte{} case '\\': c = l.Next() - searchLabel = []byte{} + if c == '\n' || c == '\r' { + l.ungetChars(0) + } default: searchLabel = append(searchLabel, byte(rune(c))) } c = l.Next() } - - lval.Token(l.newToken(tb)) - return T_ENCAPSED_AND_WHITESPACE + goto yystate0 } yyrule153: // \${VAR_NAME} { diff --git a/scanner/scanner.l b/scanner/scanner.l index def7b1a..2fa0d22 100644 --- a/scanner/scanner.l +++ b/scanner/scanner.l @@ -578,49 +578,65 @@ NEW_LINE (\r|\n|\r\n) searchLabel := []byte{} tb := []lex.Char{} - HEREDOCFOR:for { + for { if c == -1 { break; } + nls := 0 + switch c { - case '\n': fallthrough case '\r': + nls = 1 + c := l.Next() + + if c != '\n' { + nls = 0 + l.ungetChars(0) + } + + fallthrough + + case '\n': if bytes.Equal(append(l.charsToBytes(heredocLabel), ';'), searchLabel) { l.begin(HEREDOC_END) - tb = l.ungetChars(len(heredocLabel)+1) - break HEREDOCFOR; + tb = l.ungetChars(len(heredocLabel)+1+nls) + lval.Token(l.newToken(tb)); + return T_ENCAPSED_AND_WHITESPACE } if bytes.Equal(l.charsToBytes(heredocLabel), searchLabel) { l.begin(HEREDOC_END) - tb = l.ungetChars(len(heredocLabel)) - break HEREDOCFOR; + tb = l.ungetChars(len(heredocLabel)+nls) + lval.Token(l.newToken(tb)); + return T_ENCAPSED_AND_WHITESPACE } searchLabel = []byte{} case '$': c = l.Next(); - if rune(c) == '{' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z' || c >= '\u007f' && c <= 'ÿ' { + if rune(c) == '{' || isValidFirstVarNameRune(rune(c)) { tb = l.ungetChars(1) - break HEREDOCFOR; + lval.Token(l.newToken(tb)); + return T_ENCAPSED_AND_WHITESPACE } l.ungetChars(0) - searchLabel = []byte{} case '{': c = l.Next(); if rune(c) == '$' { tb = l.ungetChars(1) - break HEREDOCFOR; + lval.Token(l.newToken(tb)); + return T_ENCAPSED_AND_WHITESPACE } l.ungetChars(0) - searchLabel = []byte{} case '\\': c = l.Next(); - searchLabel = []byte{} + if c == '\n' || c == '\r' { + l.ungetChars(0) + } default: searchLabel = append(searchLabel, byte(rune(c))) @@ -628,9 +644,6 @@ NEW_LINE (\r|\n|\r\n) c = l.Next() } - - lval.Token(l.newToken(tb)); - return T_ENCAPSED_AND_WHITESPACE \${VAR_NAME} lval.Token(l.newToken(l.Token())); return T_VARIABLE ->{VAR_NAME} lval.Token(l.newToken(l.ungetChars(len(l.Token())-2))); return T_OBJECT_OPERATOR diff --git a/scanner/scanner_test.go b/scanner/scanner_test.go index 058dad1..8dbc2d2 100644 --- a/scanner/scanner_test.go +++ b/scanner/scanner_test.go @@ -693,6 +693,79 @@ CAT; assertEqual(t, expected, actual) } +func TestHereDocTokens2(t *testing.T) { + src := ` test