issue #2 - fix backqouted strings

now it works as template strings
This commit is contained in:
z7zmey 2018-03-30 18:35:18 +03:00
parent 148cf59e9d
commit 0a85cf2e1f
3 changed files with 146 additions and 83 deletions

View File

@ -8604,42 +8604,37 @@ yyrule149: // .|[ \t\n\r]
yyrule150: // .|[ \t\n\r]
{
F2:
currentChar := l.Prev
tb := []lex.Char{currentChar}
for {
switch currentChar.Rune {
case '$':
if c == '{' || isValidFirstVarNameRune(rune(c)) {
l.ungetChars(1)
lval.Token(l.newToken(tb[:len(tb)-1]))
return T_ENCAPSED_AND_WHITESPACE
}
case '{':
if rune(c) == '$' {
l.ungetChars(1)
lval.Token(l.newToken(tb[:len(tb)-1]))
return T_ENCAPSED_AND_WHITESPACE
}
case '\\':
currentChar := l.Last
tb = append(tb, currentChar)
c = l.Next()
}
if rune(c) == '`' {
lval.Token(l.newToken(l.Token()))
return T_ENCAPSED_AND_WHITESPACE
}
currentChar = l.Last
tb = append(tb, currentChar)
c = l.Next()
if c == -1 {
break
}
switch c {
case '`':
lval.Token(l.newToken(l.Token()))
return T_ENCAPSED_AND_WHITESPACE
break F2
case '$':
c = l.Next()
if rune(c) == '{' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z' || c >= '\u007f' && c <= 'ÿ' {
l.ungetChars(1)
tb := l.Token()
lval.Token(l.newToken(tb[:len(tb)-1]))
return T_ENCAPSED_AND_WHITESPACE
break F2
}
l.ungetChars(0)
case '{':
c = l.Next()
if rune(c) == '$' {
l.ungetChars(1)
tb := l.Token()
lval.Token(l.newToken(tb[:len(tb)-1]))
return T_ENCAPSED_AND_WHITESPACE
break F2
}
l.ungetChars(0)
case '\\':
c = l.Next()
}
c = l.Next()
}
goto yystate0
}

View File

@ -531,44 +531,43 @@ NEW_LINE (\r|\n|\r\n)
}
<BACKQUOTE>.|[ \t\n\r]
F2:for {
currentChar := l.Prev
tb := []lex.Char{currentChar}
for {
switch currentChar.Rune {
case '$':
if c == '{' || isValidFirstVarNameRune(rune(c)) {
l.ungetChars(1)
lval.Token(l.newToken(tb[:len(tb)-1]));
return T_ENCAPSED_AND_WHITESPACE
}
case '{':
if rune(c) == '$' {
l.ungetChars(1)
lval.Token(l.newToken(tb[:len(tb)-1]));
return T_ENCAPSED_AND_WHITESPACE
}
case '\\':
currentChar := l.Last
tb = append(tb, currentChar)
c = l.Next();
}
if rune(c) == '`' {
lval.Token(l.newToken(l.Token()));
return T_ENCAPSED_AND_WHITESPACE
}
currentChar = l.Last
tb = append(tb, currentChar)
c = l.Next()
if c == -1 {
break;
}
switch c {
case '`' :
lval.Token(l.newToken(l.Token()));
return T_ENCAPSED_AND_WHITESPACE
break F2;
case '$':
c = l.Next();
if rune(c) == '{' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z' || c >= '\u007f' && c <= 'ÿ' {
l.ungetChars(1)
tb := l.Token()
lval.Token(l.newToken(tb[:len(tb)-1]));
return T_ENCAPSED_AND_WHITESPACE
break F2;
}
l.ungetChars(0)
case '{':
c = l.Next();
if rune(c) == '$' {
l.ungetChars(1)
tb := l.Token()
lval.Token(l.newToken(tb[:len(tb)-1]));
return T_ENCAPSED_AND_WHITESPACE
break F2;
}
l.ungetChars(0)
case '\\':
c = l.Next();
}
c = l.Next()
}
<HEREDOC>.|[ \t\n\r]

View File

@ -433,8 +433,6 @@ func TestTeplateStringTokens(t *testing.T) {
"foo $a{$b}"
` + "`test $var {$var} ${var_name} {s $ \\$a `" + `
"test $var {$var} ${var_name} {s $ \$a "
"{$var}"
@ -460,20 +458,6 @@ func TestTeplateStringTokens(t *testing.T) {
scanner.Rune2Class('}'),
scanner.Rune2Class('"'),
scanner.Rune2Class('`'),
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.T_VARIABLE,
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.T_CURLY_OPEN,
scanner.T_VARIABLE,
scanner.Rune2Class('}'),
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.T_DOLLAR_OPEN_CURLY_BRACES,
scanner.T_STRING_VARNAME,
scanner.Rune2Class('}'),
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.Rune2Class('`'),
scanner.Rune2Class('"'),
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.T_VARIABLE,
@ -531,6 +515,91 @@ func TestTeplateStringTokens(t *testing.T) {
assertEqual(t, expected, actual)
}
func TestBackquoteStringTokens(t *testing.T) {
src := `<?php
` + "`foo $a`" + `
` + "`foo $a{$b}`" + `
` + "`test $var {$var} ${var_name} {s $ \\$a `" + `
` + "`{$var}`" + `
` + "`$foo/`" + `
` + "`$foo/100`" + `
` + "`$/$foo`" + `
` + "`$0$foo`" + `
`
expected := []int{
scanner.Rune2Class('`'),
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.T_VARIABLE,
scanner.Rune2Class('`'),
scanner.Rune2Class('`'),
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.T_VARIABLE,
scanner.T_CURLY_OPEN,
scanner.T_VARIABLE,
scanner.Rune2Class('}'),
scanner.Rune2Class('`'),
scanner.Rune2Class('`'),
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.T_VARIABLE,
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.T_CURLY_OPEN,
scanner.T_VARIABLE,
scanner.Rune2Class('}'),
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.T_DOLLAR_OPEN_CURLY_BRACES,
scanner.T_STRING_VARNAME,
scanner.Rune2Class('}'),
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.Rune2Class('`'),
scanner.Rune2Class('`'),
scanner.T_CURLY_OPEN,
scanner.T_VARIABLE,
scanner.Rune2Class('}'),
scanner.Rune2Class('`'),
scanner.Rune2Class('`'),
scanner.T_VARIABLE,
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.Rune2Class('`'),
scanner.Rune2Class('`'),
scanner.T_VARIABLE,
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.Rune2Class('`'),
scanner.Rune2Class('`'),
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.T_VARIABLE,
scanner.Rune2Class('`'),
scanner.Rune2Class('`'),
scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.T_VARIABLE,
scanner.Rune2Class('`'),
}
lexer := scanner.NewLexer(bytes.NewBufferString(src), "test.php")
lv := &lval{}
actual := []int{}
for {
token := lexer.Lex(lv)
if token < 0 {
break
}
actual = append(actual, token)
}
assertEqual(t, expected, actual)
}
func TestHereDocTokens(t *testing.T) {
src := `<?php
<<<CAT