issue #2 - fix template string scanning

now it correctly check first char of variable
This commit is contained in:
z7zmey 2018-03-30 12:17:25 +03:00
parent 34aba57879
commit 07f02e4497
4 changed files with 74 additions and 2 deletions

View File

@ -36,6 +36,29 @@ func TestSimpleVar(t *testing.T) {
assertEqual(t, expected, actual) assertEqual(t, expected, actual)
} }
func TestSimpleVarOneChar(t *testing.T) {
src := `<? "test $a";`
expected := &stmt.StmtList{
Stmts: []node.Node{
&stmt.Expression{
Expr: &scalar.Encapsed{
Parts: []node.Node{
&scalar.EncapsedStringPart{Value: "test "},
&expr.Variable{VarName: &node.Identifier{Value: "a"}},
},
},
},
},
}
actual, _, _ := php7.Parse(bytes.NewBufferString(src), "test.php")
assertEqual(t, expected, actual)
actual, _, _ = php5.Parse(bytes.NewBufferString(src), "test.php")
assertEqual(t, expected, actual)
}
func TestSimpleVarEndsEcapsed(t *testing.T) { func TestSimpleVarEndsEcapsed(t *testing.T) {
src := `<? "test $var\"";` src := `<? "test $var\"";`
@ -60,6 +83,30 @@ func TestSimpleVarEndsEcapsed(t *testing.T) {
assertEqual(t, expected, actual) assertEqual(t, expected, actual)
} }
func TestStringVarCurveOpen(t *testing.T) {
src := `<? "=$a{$b}";`
expected := &stmt.StmtList{
Stmts: []node.Node{
&stmt.Expression{
Expr: &scalar.Encapsed{
Parts: []node.Node{
&scalar.EncapsedStringPart{Value: "="},
&expr.Variable{VarName: &node.Identifier{Value: "a"}},
&expr.Variable{VarName: &node.Identifier{Value: "b"}},
},
},
},
},
}
actual, _, _ := php7.Parse(bytes.NewBufferString(src), "test.php")
assertEqual(t, expected, actual)
actual, _, _ = php5.Parse(bytes.NewBufferString(src), "test.php")
assertEqual(t, expected, actual)
}
func TestSimpleVarPropertyFetch(t *testing.T) { func TestSimpleVarPropertyFetch(t *testing.T) {
src := `<? "test $foo->bar()";` src := `<? "test $foo->bar()";`

View File

@ -31,6 +31,10 @@ const (
var heredocLabel []lex.Char var heredocLabel []lex.Char
func isValidFirstVarNameRune(r rune) bool {
return r >= 'A' && r <= 'Z' || r == '_' || r >= 'a' && r <= 'z' || r >= '\u007f' && r <= 'ÿ'
}
func (l *Lexer) Lex(lval Lval) int { func (l *Lexer) Lex(lval Lval) int {
l.Comments = nil l.Comments = nil
c := l.Enter() c := l.Enter()
@ -8627,7 +8631,7 @@ yyrule149: // .|[ \t\n\r]
switch l.Prev.Rune { switch l.Prev.Rune {
case '$': case '$':
c = l.Next() c = l.Next()
if l.Prev.Rune == '{' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z' || c >= '\u007f' && c <= 'ÿ' { if l.Prev.Rune == '{' || isValidFirstVarNameRune(l.Prev.Rune) {
l.ungetChars(2) l.ungetChars(2)
tb := l.Token() tb := l.Token()
lval.Token(l.newToken(tb[:len(tb)-2])) lval.Token(l.newToken(tb[:len(tb)-2]))

View File

@ -30,6 +30,10 @@ const (
var heredocLabel []lex.Char var heredocLabel []lex.Char
func isValidFirstVarNameRune(r rune) bool {
return r >= 'A' && r <= 'Z' || r == '_' || r >= 'a' && r <= 'z' || r >= '\u007f' && r <= 'ÿ'
}
func (l *Lexer) Lex(lval Lval) int { func (l *Lexer) Lex(lval Lval) int {
l.Comments = nil l.Comments = nil
c := l.Enter() c := l.Enter()
@ -451,7 +455,7 @@ NEW_LINE (\r|\n|\r\n)
switch l.Prev.Rune { switch l.Prev.Rune {
case '$': case '$':
c = l.Next(); c = l.Next();
if l.Prev.Rune == '{' || c >= 'A' && c <= 'Z' || c == '_' || c >= 'a' && c <= 'z' || c >= '\u007f' && c <= 'ÿ' { if l.Prev.Rune == '{' || isValidFirstVarNameRune(l.Prev.Rune) {
l.ungetChars(2) l.ungetChars(2)
tb := l.Token() tb := l.Token()
lval.Token(l.newToken(tb[:len(tb)-2])); lval.Token(l.newToken(tb[:len(tb)-2]));

View File

@ -427,6 +427,10 @@ func TestTokens(t *testing.T) {
func TestTeplateStringTokens(t *testing.T) { func TestTeplateStringTokens(t *testing.T) {
src := `<?php src := `<?php
"foo $a"
"foo $a{$b}"
` + "`test $var {$var} ${var_name} {s $ \\$a `" + ` ` + "`test $var {$var} ${var_name} {s $ \\$a `" + `
"test $var {$var} ${var_name} {s $ \$a " "test $var {$var} ${var_name} {s $ \$a "
@ -435,6 +439,19 @@ func TestTeplateStringTokens(t *testing.T) {
` `
expected := []int{ 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.Rune2Class('`'),
scanner.T_ENCAPSED_AND_WHITESPACE, scanner.T_ENCAPSED_AND_WHITESPACE,
scanner.T_VARIABLE, scanner.T_VARIABLE,