package php8 import ( "testing" "gotest.tools/assert" "github.com/VKCOM/php-parser/pkg/conf" "github.com/VKCOM/php-parser/pkg/errors" "github.com/VKCOM/php-parser/pkg/position" "github.com/VKCOM/php-parser/pkg/token" "github.com/VKCOM/php-parser/pkg/version" ) func TestTokens(t *testing.T) { src := `inline html - <=> != <> !== == === <<= >>= >= <= ** << >> ?? # inline comment // inline comment /* multiline comment */ /** * PHP Doc comment */ ; : , . [ ] ( ) | / ^ & + - * = % ! ~ $ < > ? @ { } $var str -> ` + "\t\r\n" + ` ->prop ( array ) ( bool ) ( boolean ) ( double ) ( float ) ( int ) ( integer ) ( object ) ( string ) ( binary ) ` expected := []string{ token.T_INLINE_HTML.String(), token.ID(int(';')).String(), token.T_INLINE_HTML.String(), token.T_ECHO.String(), token.ID(int(';')).String(), token.T_INLINE_HTML.String(), token.T_ABSTRACT.String(), token.T_ARRAY.String(), token.T_AS.String(), token.T_BREAK.String(), token.T_CALLABLE.String(), token.T_CASE.String(), token.T_CATCH.String(), token.T_CLASS.String(), token.T_CLONE.String(), token.T_CONST.String(), token.T_CONTINUE.String(), token.T_DECLARE.String(), token.T_DEFAULT.String(), token.T_DO.String(), token.T_ECHO.String(), token.T_ELSE.String(), token.T_ELSEIF.String(), token.T_EMPTY.String(), token.T_ENDDECLARE.String(), token.T_ENDFOR.String(), token.T_ENDFOREACH.String(), token.T_ENDIF.String(), token.T_ENDSWITCH.String(), token.T_ENDWHILE.String(), token.T_EVAL.String(), token.T_EXIT.String(), token.T_EXTENDS.String(), token.T_FINAL.String(), token.T_FINALLY.String(), token.T_FOR.String(), token.T_FOREACH.String(), token.T_FUNCTION.String(), token.T_FUNCTION.String(), token.T_GLOBAL.String(), token.T_GOTO.String(), token.T_IF.String(), token.T_ISSET.String(), token.T_IMPLEMENTS.String(), token.T_INSTANCEOF.String(), token.T_INSTEADOF.String(), token.T_INTERFACE.String(), token.T_LIST.String(), token.T_NAMESPACE.String(), token.T_PRIVATE.String(), token.T_PUBLIC.String(), token.T_PRINT.String(), token.T_PROTECTED.String(), token.T_RETURN.String(), token.T_STATIC.String(), token.T_SWITCH.String(), token.T_THROW.String(), token.T_TRAIT.String(), token.T_TRY.String(), token.T_UNSET.String(), token.T_USE.String(), token.T_VAR.String(), token.T_WHILE.String(), token.T_YIELD_FROM.String(), token.T_YIELD.String(), token.T_INCLUDE.String(), token.T_INCLUDE_ONCE.String(), token.T_REQUIRE.String(), token.T_REQUIRE_ONCE.String(), token.T_CLASS_C.String(), token.T_DIR.String(), token.T_FILE.String(), token.T_FUNC_C.String(), token.T_LINE.String(), token.T_NS_C.String(), token.T_METHOD_C.String(), token.T_TRAIT_C.String(), token.T_HALT_COMPILER.String(), token.T_NEW.String(), token.T_LOGICAL_AND.String(), token.T_LOGICAL_OR.String(), token.T_LOGICAL_XOR.String(), token.T_NS_SEPARATOR.String(), token.T_ELLIPSIS.String(), token.T_PAAMAYIM_NEKUDOTAYIM.String(), token.T_BOOLEAN_AND.String(), token.T_BOOLEAN_OR.String(), token.T_AND_EQUAL.String(), token.T_OR_EQUAL.String(), token.T_CONCAT_EQUAL.String(), token.T_MUL_EQUAL.String(), token.T_POW_EQUAL.String(), token.T_DIV_EQUAL.String(), token.T_PLUS_EQUAL.String(), token.T_MINUS_EQUAL.String(), token.T_XOR_EQUAL.String(), token.T_MOD_EQUAL.String(), token.T_DEC.String(), token.T_INC.String(), token.T_DOUBLE_ARROW.String(), token.T_SPACESHIP.String(), token.T_IS_NOT_EQUAL.String(), token.T_IS_NOT_EQUAL.String(), token.T_IS_NOT_IDENTICAL.String(), token.T_IS_EQUAL.String(), token.T_IS_IDENTICAL.String(), token.T_SL_EQUAL.String(), token.T_SR_EQUAL.String(), token.T_IS_GREATER_OR_EQUAL.String(), token.T_IS_SMALLER_OR_EQUAL.String(), token.T_POW.String(), token.T_SL.String(), token.T_SR.String(), token.T_COALESCE.String(), token.ID(int(';')).String(), token.ID(int(':')).String(), token.ID(int(',')).String(), token.ID(int('.')).String(), token.ID(int('[')).String(), token.ID(int(']')).String(), token.ID(int('(')).String(), token.ID(int(')')).String(), token.ID(int('|')).String(), token.ID(int('/')).String(), token.ID(int('^')).String(), token.ID(token.T_AMPERSAND_NOT_FOLLOWED_BY_VAR_OR_VARARG).String(), token.ID(int('+')).String(), token.ID(int('-')).String(), token.ID(int('*')).String(), token.ID(int('=')).String(), token.ID(int('%')).String(), token.ID(int('!')).String(), token.ID(int('~')).String(), token.ID(int('$')).String(), token.ID(int('<')).String(), token.ID(int('>')).String(), token.ID(int('?')).String(), token.ID(int('@')).String(), token.ID(int('{')).String(), token.ID(int('}')).String(), token.T_VARIABLE.String(), token.T_STRING.String(), token.T_OBJECT_OPERATOR.String(), token.T_OBJECT_OPERATOR.String(), token.T_STRING.String(), token.T_ARRAY_CAST.String(), token.T_BOOL_CAST.String(), token.T_BOOL_CAST.String(), token.T_DOUBLE_CAST.String(), token.T_DOUBLE_CAST.String(), token.T_INT_CAST.String(), token.T_INT_CAST.String(), token.T_OBJECT_CAST.String(), token.T_STRING_CAST.String(), token.T_STRING_CAST.String(), } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := NewLexer([]byte(src), config) actual := []string{} for { tkn := lexer.Lex() if tkn.ID == 0 { break } actual = append(actual, tkn.ID.String()) } assert.DeepEqual(t, expected, actual) } func TestShebang(t *testing.T) { src := `#!/usr/bin/env php prop $var[1] $var[0x1] $var[0b1] $var[var_name] $var[$var] {$var} ${var_name} {s $ \$a CAT; ` expected := []string{ token.T_START_HEREDOC.String(), token.T_ENCAPSED_AND_WHITESPACE.String(), token.T_END_HEREDOC.String(), token.ID(int(';')).String(), token.T_START_HEREDOC.String(), token.T_ENCAPSED_AND_WHITESPACE.String(), token.T_END_HEREDOC.String(), token.ID(int(';')).String(), token.T_START_HEREDOC.String(), token.T_ENCAPSED_AND_WHITESPACE.String(), token.T_VARIABLE.String(), token.T_OBJECT_OPERATOR.String(), token.T_STRING.String(), token.T_ENCAPSED_AND_WHITESPACE.String(), token.T_VARIABLE.String(), token.ID(int('[')).String(), token.T_NUM_STRING.String(), token.ID(int(']')).String(), token.T_ENCAPSED_AND_WHITESPACE.String(), token.T_VARIABLE.String(), token.ID(int('[')).String(), token.T_NUM_STRING.String(), token.ID(int(']')).String(), token.T_ENCAPSED_AND_WHITESPACE.String(), token.T_VARIABLE.String(), token.ID(int('[')).String(), token.T_NUM_STRING.String(), token.ID(int(']')).String(), token.T_ENCAPSED_AND_WHITESPACE.String(), token.T_VARIABLE.String(), token.ID(int('[')).String(), token.T_STRING.String(), token.ID(int(']')).String(), token.T_ENCAPSED_AND_WHITESPACE.String(), token.T_VARIABLE.String(), token.ID(int('[')).String(), token.T_VARIABLE.String(), token.ID(int(']')).String(), token.T_ENCAPSED_AND_WHITESPACE.String(), token.T_CURLY_OPEN.String(), token.T_VARIABLE.String(), token.ID(int('}')).String(), token.T_ENCAPSED_AND_WHITESPACE.String(), token.T_DOLLAR_OPEN_CURLY_BRACES.String(), token.T_STRING_VARNAME.String(), token.ID(int('}')).String(), token.T_ENCAPSED_AND_WHITESPACE.String(), token.T_END_HEREDOC.String(), token.ID(int(';')).String(), } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := NewLexer([]byte(src), config) actual := []string{} for { tkn := lexer.Lex() if tkn.ID == 0 { break } actual = append(actual, tkn.ID.String()) } assert.DeepEqual(t, expected, actual) } func TestHereDocTokens2(t *testing.T) { src := ` test test ` expected := []string{ token.T_VARIABLE.String(), token.ID(int(';')).String(), token.T_INLINE_HTML.String(), token.T_VARIABLE.String(), token.ID(int(';')).String(), token.T_INLINE_HTML.String(), } config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := NewLexer([]byte(src), config) actual := []string{} for { tkn := lexer.Lex() if tkn.ID == 0 { break } actual = append(actual, tkn.ID.String()) } assert.DeepEqual(t, expected, actual) } func TestStringTokensAfterVariable(t *testing.T) { src := ` test` expected := []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte(" bar ( '' ) ;` config := conf.Config{ Version: &version.Version{ Major: 7, Minor: 4, }, } lexer := NewLexer([]byte(src), config) expected := []*token.Token{ { ID: token.T_OPEN_TAG, Value: []byte("