#67: skip unexpected character in input
This commit is contained in:
parent
4133a65afe
commit
69e3111221
@ -4,7 +4,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"github.com/z7zmey/php-parser/position"
|
"github.com/z7zmey/php-parser/position"
|
||||||
"github.com/z7zmey/php-parser/scanner"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error parsing error
|
// Error parsing error
|
||||||
@ -14,13 +13,18 @@ type Error struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewError creates and returns new Error
|
// NewError creates and returns new Error
|
||||||
func NewError(msg string, t *scanner.Token) *Error {
|
func NewError(msg string, p *position.Position) *Error {
|
||||||
return &Error{
|
return &Error{
|
||||||
Msg: msg,
|
Msg: msg,
|
||||||
Pos: t.Position,
|
Pos: p,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *Error) String() string {
|
func (e *Error) String() string {
|
||||||
return fmt.Sprintf("%s at line %d", e.Msg, e.Pos.StartLine)
|
atLine := ""
|
||||||
|
if e.Pos != nil {
|
||||||
|
atLine = fmt.Sprintf(" at line %d", e.Pos.StartLine)
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%s%s", e.Msg, atLine)
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"github.com/z7zmey/php-parser/position"
|
"github.com/z7zmey/php-parser/position"
|
||||||
|
|
||||||
"github.com/z7zmey/php-parser/errors"
|
"github.com/z7zmey/php-parser/errors"
|
||||||
"github.com/z7zmey/php-parser/scanner"
|
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
"github.com/kylelemons/godebug/pretty"
|
||||||
)
|
)
|
||||||
@ -27,12 +26,8 @@ func assertEqual(t *testing.T, expected interface{}, actual interface{}) {
|
|||||||
|
|
||||||
func TestConstructor(t *testing.T) {
|
func TestConstructor(t *testing.T) {
|
||||||
pos := position.NewPosition(1, 2, 3, 4)
|
pos := position.NewPosition(1, 2, 3, 4)
|
||||||
token := &scanner.Token{
|
|
||||||
Value: `test`,
|
|
||||||
Position: pos,
|
|
||||||
}
|
|
||||||
|
|
||||||
actual := errors.NewError("message", token)
|
actual := errors.NewError("message", pos)
|
||||||
|
|
||||||
expected := &errors.Error{
|
expected := &errors.Error{
|
||||||
Msg: "message",
|
Msg: "message",
|
||||||
@ -44,12 +39,8 @@ func TestConstructor(t *testing.T) {
|
|||||||
|
|
||||||
func TestPrint(t *testing.T) {
|
func TestPrint(t *testing.T) {
|
||||||
pos := position.NewPosition(1, 2, 3, 4)
|
pos := position.NewPosition(1, 2, 3, 4)
|
||||||
token := &scanner.Token{
|
|
||||||
Value: `test`,
|
|
||||||
Position: pos,
|
|
||||||
}
|
|
||||||
|
|
||||||
Error := errors.NewError("message", token)
|
Error := errors.NewError("message", pos)
|
||||||
|
|
||||||
actual := Error.String()
|
actual := Error.String()
|
||||||
|
|
||||||
@ -57,3 +48,13 @@ func TestPrint(t *testing.T) {
|
|||||||
|
|
||||||
assertEqual(t, expected, actual)
|
assertEqual(t, expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPrintWithotPos(t *testing.T) {
|
||||||
|
Error := errors.NewError("message", nil)
|
||||||
|
|
||||||
|
actual := Error.String()
|
||||||
|
|
||||||
|
expected := "message"
|
||||||
|
|
||||||
|
assertEqual(t, expected, actual)
|
||||||
|
}
|
||||||
|
@ -20,7 +20,6 @@ type Parser struct {
|
|||||||
path string
|
path string
|
||||||
currentToken *scanner.Token
|
currentToken *scanner.Token
|
||||||
positionBuilder *parser.PositionBuilder
|
positionBuilder *parser.PositionBuilder
|
||||||
errors []*errors.Error
|
|
||||||
rootNode node.Node
|
rootNode node.Node
|
||||||
comments parser.Comments
|
comments parser.Comments
|
||||||
positions parser.Positions
|
positions parser.Positions
|
||||||
@ -38,7 +37,6 @@ func NewParser(src io.Reader, path string) *Parser {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,13 +48,13 @@ func (l *Parser) Lex(lval *yySymType) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *Parser) Error(msg string) {
|
func (l *Parser) Error(msg string) {
|
||||||
l.errors = append(l.errors, errors.NewError(msg, l.currentToken))
|
l.Lexer.Errors = append(l.Lexer.Errors, errors.NewError(msg, l.currentToken.Position))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the php7 Parser entrypoint
|
// Parse the php7 Parser entrypoint
|
||||||
func (l *Parser) Parse() int {
|
func (l *Parser) Parse() int {
|
||||||
// init
|
// init
|
||||||
l.errors = nil
|
l.Lexer.Errors = nil
|
||||||
l.rootNode = nil
|
l.rootNode = nil
|
||||||
l.comments = parser.Comments{}
|
l.comments = parser.Comments{}
|
||||||
l.positions = parser.Positions{}
|
l.positions = parser.Positions{}
|
||||||
@ -92,7 +90,7 @@ func (l *Parser) GetRootNode() node.Node {
|
|||||||
|
|
||||||
// GetErrors returns errors list
|
// GetErrors returns errors list
|
||||||
func (l *Parser) GetErrors() []*errors.Error {
|
func (l *Parser) GetErrors() []*errors.Error {
|
||||||
return l.errors
|
return l.Lexer.Errors
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetComments returns comments list
|
// GetComments returns comments list
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Code generated by goyacc -o php5/php5.go php5/php5.y. DO NOT EDIT.
|
||||||
|
|
||||||
//line php5/php5.y:2
|
//line php5/php5.y:2
|
||||||
package php5
|
package php5
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
"github.com/kylelemons/godebug/pretty"
|
||||||
|
"github.com/z7zmey/php-parser/errors"
|
||||||
"github.com/z7zmey/php-parser/node/expr"
|
"github.com/z7zmey/php-parser/node/expr"
|
||||||
"github.com/z7zmey/php-parser/node/expr/assign"
|
"github.com/z7zmey/php-parser/node/expr/assign"
|
||||||
"github.com/z7zmey/php-parser/node/expr/binary"
|
"github.com/z7zmey/php-parser/node/expr/binary"
|
||||||
@ -13,6 +14,7 @@ import (
|
|||||||
"github.com/z7zmey/php-parser/node/name"
|
"github.com/z7zmey/php-parser/node/name"
|
||||||
"github.com/z7zmey/php-parser/node/scalar"
|
"github.com/z7zmey/php-parser/node/scalar"
|
||||||
"github.com/z7zmey/php-parser/php5"
|
"github.com/z7zmey/php-parser/php5"
|
||||||
|
"github.com/z7zmey/php-parser/position"
|
||||||
|
|
||||||
"github.com/z7zmey/php-parser/node"
|
"github.com/z7zmey/php-parser/node"
|
||||||
"github.com/z7zmey/php-parser/node/stmt"
|
"github.com/z7zmey/php-parser/node/stmt"
|
||||||
@ -3750,3 +3752,23 @@ CAD;
|
|||||||
actual := php5parser.GetRootNode()
|
actual := php5parser.GetRootNode()
|
||||||
assertEqual(t, expected, actual)
|
assertEqual(t, expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPhp5ControlCharsErrors(t *testing.T) {
|
||||||
|
src := "<?php \004 echo $b; \"$a[\005test]\";"
|
||||||
|
|
||||||
|
expected := []*errors.Error{
|
||||||
|
{
|
||||||
|
Msg: "WARNING: Unexpected character in input: '\004' (ASCII=4)",
|
||||||
|
Pos: &position.Position{1, 1, 7, 7},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Msg: "WARNING: Unexpected character in input: '\005' (ASCII=5)",
|
||||||
|
Pos: &position.Position{1, 1, 22, 22},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
php5parser := php5.NewParser(bytes.NewBufferString(src), "test.php")
|
||||||
|
php5parser.Parse()
|
||||||
|
actual := php5parser.GetErrors()
|
||||||
|
assertEqual(t, expected, actual)
|
||||||
|
}
|
||||||
|
@ -19,7 +19,6 @@ type Parser struct {
|
|||||||
path string
|
path string
|
||||||
currentToken *scanner.Token
|
currentToken *scanner.Token
|
||||||
positionBuilder *parser.PositionBuilder
|
positionBuilder *parser.PositionBuilder
|
||||||
errors []*errors.Error
|
|
||||||
rootNode node.Node
|
rootNode node.Node
|
||||||
comments parser.Comments
|
comments parser.Comments
|
||||||
positions parser.Positions
|
positions parser.Positions
|
||||||
@ -37,7 +36,6 @@ func NewParser(src io.Reader, path string) *Parser {
|
|||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,13 +47,13 @@ func (l *Parser) Lex(lval *yySymType) int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (l *Parser) Error(msg string) {
|
func (l *Parser) Error(msg string) {
|
||||||
l.errors = append(l.errors, errors.NewError(msg, l.currentToken))
|
l.Lexer.Errors = append(l.Lexer.Errors, errors.NewError(msg, l.currentToken.Position))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the php7 Parser entrypoint
|
// Parse the php7 Parser entrypoint
|
||||||
func (l *Parser) Parse() int {
|
func (l *Parser) Parse() int {
|
||||||
// init
|
// init
|
||||||
l.errors = nil
|
l.Lexer.Errors = nil
|
||||||
l.rootNode = nil
|
l.rootNode = nil
|
||||||
l.comments = parser.Comments{}
|
l.comments = parser.Comments{}
|
||||||
l.positions = parser.Positions{}
|
l.positions = parser.Positions{}
|
||||||
@ -81,7 +79,7 @@ func (l *Parser) GetRootNode() node.Node {
|
|||||||
|
|
||||||
// GetErrors returns errors list
|
// GetErrors returns errors list
|
||||||
func (l *Parser) GetErrors() []*errors.Error {
|
func (l *Parser) GetErrors() []*errors.Error {
|
||||||
return l.errors
|
return l.Lexer.Errors
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetComments returns comments list
|
// GetComments returns comments list
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
// Code generated by goyacc -o php7/php7.go php7/php7.y. DO NOT EDIT.
|
||||||
|
|
||||||
//line php7/php7.y:2
|
//line php7/php7.y:2
|
||||||
package php7
|
package php7
|
||||||
|
|
||||||
|
@ -6,12 +6,14 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/kylelemons/godebug/pretty"
|
"github.com/kylelemons/godebug/pretty"
|
||||||
|
"github.com/z7zmey/php-parser/errors"
|
||||||
"github.com/z7zmey/php-parser/node/expr"
|
"github.com/z7zmey/php-parser/node/expr"
|
||||||
"github.com/z7zmey/php-parser/node/expr/assign"
|
"github.com/z7zmey/php-parser/node/expr/assign"
|
||||||
"github.com/z7zmey/php-parser/node/expr/binary"
|
"github.com/z7zmey/php-parser/node/expr/binary"
|
||||||
"github.com/z7zmey/php-parser/node/expr/cast"
|
"github.com/z7zmey/php-parser/node/expr/cast"
|
||||||
"github.com/z7zmey/php-parser/node/name"
|
"github.com/z7zmey/php-parser/node/name"
|
||||||
"github.com/z7zmey/php-parser/node/scalar"
|
"github.com/z7zmey/php-parser/node/scalar"
|
||||||
|
"github.com/z7zmey/php-parser/position"
|
||||||
|
|
||||||
"github.com/z7zmey/php-parser/node"
|
"github.com/z7zmey/php-parser/node"
|
||||||
"github.com/z7zmey/php-parser/node/stmt"
|
"github.com/z7zmey/php-parser/node/stmt"
|
||||||
@ -3336,3 +3338,23 @@ CAD;
|
|||||||
actual := php7parser.GetRootNode()
|
actual := php7parser.GetRootNode()
|
||||||
assertEqual(t, expected, actual)
|
assertEqual(t, expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPhp7ControlCharsErrors(t *testing.T) {
|
||||||
|
src := "<?php \004 echo $b; \"$a[\005test]\";"
|
||||||
|
|
||||||
|
expected := []*errors.Error{
|
||||||
|
{
|
||||||
|
Msg: "WARNING: Unexpected character in input: '\004' (ASCII=4)",
|
||||||
|
Pos: &position.Position{1, 1, 7, 7},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Msg: "WARNING: Unexpected character in input: '\005' (ASCII=5)",
|
||||||
|
Pos: &position.Position{1, 1, 22, 22},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
php7parser := php7.NewParser(bytes.NewBufferString(src), "test.php")
|
||||||
|
php7parser.Parse()
|
||||||
|
actual := php7parser.GetErrors()
|
||||||
|
assertEqual(t, expected, actual)
|
||||||
|
}
|
||||||
|
@ -9,6 +9,7 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"unicode"
|
"unicode"
|
||||||
|
|
||||||
|
"github.com/z7zmey/php-parser/errors"
|
||||||
"github.com/z7zmey/php-parser/position"
|
"github.com/z7zmey/php-parser/position"
|
||||||
|
|
||||||
"github.com/cznic/golex/lex"
|
"github.com/cznic/golex/lex"
|
||||||
@ -446,6 +447,7 @@ type Lexer struct {
|
|||||||
tokenBytesBuf *bytes.Buffer
|
tokenBytesBuf *bytes.Buffer
|
||||||
TokenPool sync.Pool
|
TokenPool sync.Pool
|
||||||
PositionPool sync.Pool
|
PositionPool sync.Pool
|
||||||
|
Errors []*errors.Error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rune2Class returns the rune integer id
|
// Rune2Class returns the rune integer id
|
||||||
@ -492,6 +494,21 @@ func NewLexer(src io.Reader, fName string) *Lexer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (l *Lexer) Error(msg string) {
|
||||||
|
chars := l.Token()
|
||||||
|
firstChar := chars[0]
|
||||||
|
lastChar := chars[len(chars)-1]
|
||||||
|
|
||||||
|
pos := position.NewPosition(
|
||||||
|
l.File.Line(firstChar.Pos()),
|
||||||
|
l.File.Line(lastChar.Pos()),
|
||||||
|
int(firstChar.Pos()),
|
||||||
|
int(lastChar.Pos()),
|
||||||
|
)
|
||||||
|
|
||||||
|
l.Errors = append(l.Errors, errors.NewError(msg, pos))
|
||||||
|
}
|
||||||
|
|
||||||
func (l *Lexer) ungetChars(n int) []lex.Char {
|
func (l *Lexer) ungetChars(n int) []lex.Char {
|
||||||
l.Unget(l.Lookahead())
|
l.Unget(l.Lookahead())
|
||||||
|
|
||||||
|
5130
scanner/scanner.go
5130
scanner/scanner.go
File diff suppressed because it is too large
Load Diff
@ -54,6 +54,7 @@ EXPONENT_DNUM (({LNUM}|{DNUM})[eE][+-]?{LNUM})
|
|||||||
VAR_NAME [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
|
VAR_NAME [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*
|
||||||
OPERATORS [;:,.\[\]()|\/\^&\+-*=%!~$<>?@]
|
OPERATORS [;:,.\[\]()|\/\^&\+-*=%!~$<>?@]
|
||||||
NEW_LINE (\r|\n|\r\n)
|
NEW_LINE (\r|\n|\r\n)
|
||||||
|
ANY_CHAR .
|
||||||
|
|
||||||
%%
|
%%
|
||||||
c = l.Rule0()
|
c = l.Rule0()
|
||||||
@ -648,13 +649,15 @@ NEW_LINE (\r|\n|\r\n)
|
|||||||
<STRING_VAR_INDEX>\] l.popState(); l.popState();lval.Token(l.createToken(l.Token())); return Rune2Class(rune(l.TokenBytes(nil)[0]))
|
<STRING_VAR_INDEX>\] l.popState(); l.popState();lval.Token(l.createToken(l.Token())); return Rune2Class(rune(l.TokenBytes(nil)[0]))
|
||||||
<STRING_VAR_INDEX>[ \n\r\t\\'#] l.popState(); l.popState();lval.Token(l.createToken(l.Token())); return T_ENCAPSED_AND_WHITESPACE
|
<STRING_VAR_INDEX>[ \n\r\t\\'#] l.popState(); l.popState();lval.Token(l.createToken(l.Token())); return T_ENCAPSED_AND_WHITESPACE
|
||||||
<STRING_VAR_INDEX>{OPERATORS} lval.Token(l.createToken(l.Token())); return Rune2Class(rune(l.TokenBytes(nil)[0]))
|
<STRING_VAR_INDEX>{OPERATORS} lval.Token(l.createToken(l.Token())); return Rune2Class(rune(l.TokenBytes(nil)[0]))
|
||||||
<STRING_VAR_INDEX>. lval.Token(l.createToken(l.Token())); return Rune2Class(rune(l.TokenBytes(nil)[0]))
|
<STRING_VAR_INDEX>{ANY_CHAR} l.Error(fmt.Sprintf("WARNING: Unexpected character in input: '%c' (ASCII=%d)", l.TokenBytes(nil)[0], l.TokenBytes(nil)[0]));l.Abort();
|
||||||
|
|
||||||
<STRING_VAR_NAME>{VAR_NAME}[\[\}] l.popState();l.pushState(PHP);lval.Token(l.createToken(l.ungetChars(1))); return T_STRING_VARNAME
|
<STRING_VAR_NAME>{VAR_NAME}[\[\}] l.popState();l.pushState(PHP);lval.Token(l.createToken(l.ungetChars(1))); return T_STRING_VARNAME
|
||||||
<STRING_VAR_NAME>. l.ungetChars(1);l.popState();l.pushState(PHP)
|
<STRING_VAR_NAME>. l.ungetChars(1);l.popState();l.pushState(PHP)
|
||||||
|
|
||||||
<HALT_COMPILER>.|[ \t\n\r] // do nothing
|
<HALT_COMPILER>.|[ \t\n\r] // do nothing
|
||||||
|
|
||||||
|
<PHP>{ANY_CHAR} l.Error(fmt.Sprintf("WARNING: Unexpected character in input: '%c' (ASCII=%d)", l.TokenBytes(nil)[0], l.TokenBytes(nil)[0]));l.Abort();
|
||||||
|
|
||||||
%%
|
%%
|
||||||
if c, ok := l.Abort(); ok { return int(c) }
|
if c, ok := l.Abort(); ok { return int(c) }
|
||||||
goto yyAction
|
goto yyAction
|
||||||
|
@ -1077,3 +1077,52 @@ func TestEmptyInlineComment2(t *testing.T) {
|
|||||||
|
|
||||||
assertEqual(t, expected, actual)
|
assertEqual(t, expected, actual)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIgnoreControllCharacters(t *testing.T) {
|
||||||
|
src := "<?php \004 echo $b;"
|
||||||
|
|
||||||
|
lexer := scanner.NewLexer(bytes.NewBufferString(src), "test.php")
|
||||||
|
lv := &lval{}
|
||||||
|
|
||||||
|
expected := "echo"
|
||||||
|
lexer.Lex(lv)
|
||||||
|
actual := lv.Tkn.Value
|
||||||
|
assertEqual(t, expected, actual)
|
||||||
|
|
||||||
|
expected = "$b"
|
||||||
|
lexer.Lex(lv)
|
||||||
|
actual = lv.Tkn.Value
|
||||||
|
assertEqual(t, expected, actual)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIgnoreControllCharactersAtStringVarOffset(t *testing.T) {
|
||||||
|
src := "<?php \"$a[test\004]\";"
|
||||||
|
|
||||||
|
lexer := scanner.NewLexer(bytes.NewBufferString(src), "test.php")
|
||||||
|
lv := &lval{}
|
||||||
|
|
||||||
|
expected := "\""
|
||||||
|
lexer.Lex(lv)
|
||||||
|
actual := lv.Tkn.Value
|
||||||
|
assertEqual(t, expected, actual)
|
||||||
|
|
||||||
|
expected = "$a"
|
||||||
|
lexer.Lex(lv)
|
||||||
|
actual = lv.Tkn.Value
|
||||||
|
assertEqual(t, expected, actual)
|
||||||
|
|
||||||
|
expected = "["
|
||||||
|
lexer.Lex(lv)
|
||||||
|
actual = lv.Tkn.Value
|
||||||
|
assertEqual(t, expected, actual)
|
||||||
|
|
||||||
|
expected = "test"
|
||||||
|
lexer.Lex(lv)
|
||||||
|
actual = lv.Tkn.Value
|
||||||
|
assertEqual(t, expected, actual)
|
||||||
|
|
||||||
|
expected = "]"
|
||||||
|
lexer.Lex(lv)
|
||||||
|
actual = lv.Tkn.Value
|
||||||
|
assertEqual(t, expected, actual)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user