2015-07-15 20:05:46 +03:00
< ? php
2016-04-09 10:36:53 +03:00
namespace GraphQL\Tests\Language ;
2015-07-15 20:05:46 +03:00
2016-04-09 10:36:53 +03:00
use GraphQL\Language\Lexer ;
use GraphQL\Language\Source ;
use GraphQL\Language\Token ;
2016-10-21 12:39:57 +03:00
use GraphQL\Error\SyntaxError ;
2016-04-23 16:43:10 +03:00
use GraphQL\Utils ;
2015-08-16 23:53:11 +03:00
2015-07-15 20:05:46 +03:00
class LexerTest extends \PHPUnit_Framework_TestCase
{
2016-04-23 16:43:10 +03:00
/**
* @ it disallows uncommon control characters
*/
public function testDissallowsUncommonControlCharacters ()
{
try {
$char = Utils :: chr ( 0x0007 );
2016-10-16 22:53:50 +03:00
$this -> lexOne ( $char );
2016-04-23 16:43:10 +03:00
$this -> fail ( 'Expected exception not thrown' );
} catch ( SyntaxError $error ) {
2016-11-19 13:08:20 +03:00
$msg = mb_substr ( $error -> getMessage (), 0 , 72 , 'UTF-8' );
2016-04-23 16:43:10 +03:00
$this -> assertEquals (
2016-11-19 13:08:20 +03:00
'Syntax Error GraphQL (1:1) Cannot contain the invalid character "\u0007"' ,
2016-04-23 16:43:10 +03:00
$msg
);
}
}
/**
* @ it accepts BOM header
*/
public function testAcceptsBomHeader ()
{
$bom = Utils :: chr ( 0xFEFF );
2016-10-16 22:53:50 +03:00
$expected = [
'kind' => Token :: NAME ,
'start' => 2 ,
'end' => 5 ,
'value' => 'foo'
];
$this -> assertArraySubset ( $expected , ( array ) $this -> lexOne ( $bom . ' foo' ));
2016-04-23 16:43:10 +03:00
}
/**
2016-10-16 22:53:50 +03:00
* @ it records line and column
2016-04-23 16:43:10 +03:00
*/
2016-10-16 22:53:50 +03:00
public function testRecordsLineAndColumn ()
{
$expected = [
'kind' => Token :: NAME ,
'start' => 8 ,
'end' => 11 ,
'line' => 4 ,
'column' => 3 ,
'value' => 'foo'
];
$this -> assertArraySubset ( $expected , ( array ) $this -> lexOne ( " \n \r \n \r foo \n " ));
}
/**
* @ it skips whitespace and comments
*/
public function testSkipsWhitespacesAndComments ()
2015-07-15 20:05:46 +03:00
{
$example1 = '
foo
' ;
2016-10-16 22:53:50 +03:00
$expected = [
'kind' => Token :: NAME ,
'start' => 6 ,
'end' => 9 ,
'value' => 'foo'
];
$this -> assertArraySubset ( $expected , ( array ) $this -> lexOne ( $example1 ));
2015-07-15 20:05:46 +03:00
$example2 = '
#comment
foo #comment
' ;
2016-10-16 22:53:50 +03:00
$expected = [
'kind' => Token :: NAME ,
'start' => 18 ,
'end' => 21 ,
'value' => 'foo'
];
$this -> assertArraySubset ( $expected , ( array ) $this -> lexOne ( $example2 ));
$expected = [
'kind' => Token :: NAME ,
'start' => 3 ,
'end' => 6 ,
'value' => 'foo'
];
2015-07-15 20:05:46 +03:00
$example3 = ',,,foo,,,' ;
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset ( $expected , ( array ) $this -> lexOne ( $example3 ));
2015-07-15 20:05:46 +03:00
}
2016-04-23 16:43:10 +03:00
/**
* @ it errors respect whitespace
*/
2015-07-15 20:05:46 +03:00
public function testErrorsRespectWhitespace ()
{
$example = "
?
" ;
try {
2016-10-16 22:53:50 +03:00
$this -> lexOne ( $example );
2015-07-15 20:05:46 +03:00
$this -> fail ( 'Expected exception not thrown' );
2015-08-16 23:53:11 +03:00
} catch ( SyntaxError $e ) {
2015-07-15 20:05:46 +03:00
$this -> assertEquals (
2016-11-19 13:08:20 +03:00
'Syntax Error GraphQL (3:5) Cannot parse the unexpected character "?".' . " \n " .
2015-07-15 20:05:46 +03:00
" \n " .
" 2: \n " .
" 3: ? \n " .
" ^ \n " .
" 4: \n " ,
$e -> getMessage ()
);
}
}
2016-04-23 16:43:10 +03:00
/**
* @ it lexes strings
*/
2015-07-15 20:05:46 +03:00
public function testLexesStrings ()
{
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset ([
'kind' => Token :: STRING ,
'start' => 0 ,
'end' => 8 ,
'value' => 'simple'
], ( array ) $this -> lexOne ( '"simple"' ));
2015-07-15 20:05:46 +03:00
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset ([
'kind' => Token :: STRING ,
'start' => 0 ,
'end' => 15 ,
'value' => ' white space '
], ( array ) $this -> lexOne ( '" white space "' ));
$this -> assertArraySubset ([
'kind' => Token :: STRING ,
'start' => 0 ,
'end' => 10 ,
'value' => 'quote "'
], ( array ) $this -> lexOne ( '"quote \\""' ));
$this -> assertArraySubset ([
'kind' => Token :: STRING ,
'start' => 0 ,
'end' => 25 ,
'value' => 'escaped \n\r\b\t\f'
], ( array ) $this -> lexOne ( '"escaped \\\\n\\\\r\\\\b\\\\t\\\\f"' ));
$this -> assertArraySubset ([
'kind' => Token :: STRING ,
'start' => 0 ,
'end' => 16 ,
'value' => 'slashes \\ \/'
], ( array ) $this -> lexOne ( '"slashes \\\\ \\\\/"' ));
$this -> assertArraySubset ([
'kind' => Token :: STRING ,
'start' => 0 ,
'end' => 13 ,
'value' => 'unicode яуц'
], ( array ) $this -> lexOne ( '"unicode яуц"' ));
2015-07-15 20:05:46 +03:00
$unicode = json_decode ( '"\u1234\u5678\u90AB\uCDEF"' );
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset ([
'kind' => Token :: STRING ,
'start' => 0 ,
'end' => 34 ,
'value' => 'unicode ' . $unicode
], ( array ) $this -> lexOne ( '"unicode \u1234\u5678\u90AB\uCDEF"' ));
$this -> assertArraySubset ([
'kind' => Token :: STRING ,
'start' => 0 ,
'end' => 26 ,
'value' => $unicode
], ( array ) $this -> lexOne ( '"\u1234\u5678\u90AB\uCDEF"' ));
2015-07-15 20:05:46 +03:00
}
2016-04-23 16:43:10 +03:00
/**
* @ it lex reports useful string errors
*/
2015-07-15 20:05:46 +03:00
public function testReportsUsefulErrors ()
{
$run = function ( $num , $str , $expectedMessage ) {
try {
2016-10-16 22:53:50 +03:00
$this -> lexOne ( $str );
2015-07-15 20:05:46 +03:00
$this -> fail ( 'Expected exception not thrown in example: ' . $num );
2015-08-16 23:53:11 +03:00
} catch ( SyntaxError $e ) {
2015-07-15 20:05:46 +03:00
$this -> assertEquals ( $expectedMessage , $e -> getMessage (), " Test case $num failed " );
}
};
2016-11-19 13:08:20 +03:00
$run ( 1 , '"' , " Syntax Error GraphQL (1:2) Unterminated string. \n \n 1: \" \n ^ \n " );
$run ( 2 , '"no end quote' , " Syntax Error GraphQL (1:14) Unterminated string. \n \n 1: \" no end quote \n ^ \n " );
$run ( 3 , " 'single quotes' " , " Syntax Error GraphQL (1:1) Unexpected single quote character ('), did you mean to use a double quote ( \" )? \n \n 1: 'single quotes' \n ^ \n " );
$run ( 4 , '"contains unescaped \u0007 control char"' , " Syntax Error GraphQL (1:21) Invalid character within String: \" \\ u0007 \" \n \n 1: \" contains unescaped \\ u0007 control char \" \n ^ \n " );
$run ( 5 , '"null-byte is not \u0000 end of file"' , 'Syntax Error GraphQL (1:19) Invalid character within String: "\\u0000"' . " \n \n 1: \" null-byte is not \\ u0000 end of file \" \n ^ \n " );
$run ( 6 , '"multi' . " \n " . 'line"' , " Syntax Error GraphQL (1:7) Unterminated string. \n \n 1: \" multi \n ^ \n 2: line \" \n " );
$run ( 7 , '"multi' . " \r " . 'line"' , " Syntax Error GraphQL (1:7) Unterminated string. \n \n 1: \" multi \n ^ \n 2: line \" \n " );
$run ( 8 , '"bad \\z esc"' , " Syntax Error GraphQL (1:7) Invalid character escape sequence: \\ z \n \n 1: \" bad \\ z esc \" \n ^ \n " );
$run ( 9 , '"bad \\x esc"' , " Syntax Error GraphQL (1:7) Invalid character escape sequence: \\ x \n \n 1: \" bad \\ x esc \" \n ^ \n " );
$run ( 10 , '"bad \\u1 esc"' , " Syntax Error GraphQL (1:7) Invalid character escape sequence: \\ u1 es \n \n 1: \" bad \\ u1 esc \" \n ^ \n " );
$run ( 11 , '"bad \\u0XX1 esc"' , " Syntax Error GraphQL (1:7) Invalid character escape sequence: \\ u0XX1 \n \n 1: \" bad \\ u0XX1 esc \" \n ^ \n " );
$run ( 12 , '"bad \\uXXXX esc"' , " Syntax Error GraphQL (1:7) Invalid character escape sequence: \\ uXXXX \n \n 1: \" bad \\ uXXXX esc \" \n ^ \n " );
$run ( 13 , '"bad \\uFXXX esc"' , " Syntax Error GraphQL (1:7) Invalid character escape sequence: \\ uFXXX \n \n 1: \" bad \\ uFXXX esc \" \n ^ \n " );
$run ( 14 , '"bad \\uXXXF esc"' , " Syntax Error GraphQL (1:7) Invalid character escape sequence: \\ uXXXF \n \n 1: \" bad \\ uXXXF esc \" \n ^ \n " );
2015-07-15 20:05:46 +03:00
}
2016-04-23 16:43:10 +03:00
/**
* @ it lexes numbers
*/
2015-07-15 20:05:46 +03:00
public function testLexesNumbers ()
{
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: INT , 'start' => 0 , 'end' => 1 , 'value' => '4' ],
( array ) $this -> lexOne ( '4' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: FLOAT , 'start' => 0 , 'end' => 5 , 'value' => '4.123' ],
( array ) $this -> lexOne ( '4.123' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: INT , 'start' => 0 , 'end' => 2 , 'value' => '-4' ],
( array ) $this -> lexOne ( '-4' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: INT , 'start' => 0 , 'end' => 1 , 'value' => '9' ],
( array ) $this -> lexOne ( '9' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: INT , 'start' => 0 , 'end' => 1 , 'value' => '0' ],
( array ) $this -> lexOne ( '0' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: FLOAT , 'start' => 0 , 'end' => 6 , 'value' => '-4.123' ],
( array ) $this -> lexOne ( '-4.123' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: FLOAT , 'start' => 0 , 'end' => 5 , 'value' => '0.123' ],
( array ) $this -> lexOne ( '0.123' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: FLOAT , 'start' => 0 , 'end' => 5 , 'value' => '123e4' ],
( array ) $this -> lexOne ( '123e4' )
2015-08-16 23:53:11 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: FLOAT , 'start' => 0 , 'end' => 5 , 'value' => '123E4' ],
( array ) $this -> lexOne ( '123E4' )
2015-08-16 23:53:11 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: FLOAT , 'start' => 0 , 'end' => 6 , 'value' => '123e-4' ],
( array ) $this -> lexOne ( '123e-4' )
2015-08-16 23:53:11 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: FLOAT , 'start' => 0 , 'end' => 6 , 'value' => '123e+4' ],
( array ) $this -> lexOne ( '123e+4' )
2015-08-16 23:53:11 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: FLOAT , 'start' => 0 , 'end' => 8 , 'value' => '-1.123e4' ],
( array ) $this -> lexOne ( '-1.123e4' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: FLOAT , 'start' => 0 , 'end' => 8 , 'value' => '-1.123E4' ],
( array ) $this -> lexOne ( '-1.123E4' )
2015-08-16 23:53:11 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: FLOAT , 'start' => 0 , 'end' => 9 , 'value' => '-1.123e-4' ],
( array ) $this -> lexOne ( '-1.123e-4' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: FLOAT , 'start' => 0 , 'end' => 9 , 'value' => '-1.123e+4' ],
( array ) $this -> lexOne ( '-1.123e+4' )
2015-08-16 23:53:11 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: FLOAT , 'start' => 0 , 'end' => 11 , 'value' => '-1.123e4567' ],
( array ) $this -> lexOne ( '-1.123e4567' )
2015-07-15 20:05:46 +03:00
);
}
2016-04-23 16:43:10 +03:00
/**
* @ it lex reports useful number errors
*/
2015-07-15 20:05:46 +03:00
public function testReportsUsefulNumberErrors ()
{
$run = function ( $num , $str , $expectedMessage ) {
try {
$this -> lexOne ( $str );
$this -> fail ( 'Expected exception not thrown in example: ' . $num );
2015-08-16 23:53:11 +03:00
} catch ( SyntaxError $e ) {
2015-07-15 20:05:46 +03:00
$this -> assertEquals ( $expectedMessage , $e -> getMessage (), " Test case $num failed " );
}
};
2016-04-23 16:43:10 +03:00
$run ( 0 , '00' , " Syntax Error GraphQL (1:2) Invalid number, unexpected digit after 0: \" 0 \" \n \n 1: 00 \n ^ \n " );
2016-11-19 13:08:20 +03:00
$run ( 1 , '+1' , " Syntax Error GraphQL (1:1) Cannot parse the unexpected character \" + \" . \n \n 1: +1 \n ^ \n " );
2016-04-23 16:43:10 +03:00
$run ( 2 , '1.' , " Syntax Error GraphQL (1:3) Invalid number, expected digit but got: <EOF> \n \n 1: 1. \n ^ \n " );
2016-11-19 13:08:20 +03:00
$run ( 3 , '.123' , " Syntax Error GraphQL (1:1) Cannot parse the unexpected character \" . \" . \n \n 1: .123 \n ^ \n " );
2016-04-23 16:43:10 +03:00
$run ( 4 , '1.A' , " Syntax Error GraphQL (1:3) Invalid number, expected digit but got: \" A \" \n \n 1: 1.A \n ^ \n " );
$run ( 5 , '-A' , " Syntax Error GraphQL (1:2) Invalid number, expected digit but got: \" A \" \n \n 1: -A \n ^ \n " );
$run ( 6 , '1.0e' , " Syntax Error GraphQL (1:5) Invalid number, expected digit but got: <EOF> \n \n 1: 1.0e \n ^ \n " );
$run ( 7 , '1.0eA' , " Syntax Error GraphQL (1:5) Invalid number, expected digit but got: \" A \" \n \n 1: 1.0eA \n ^ \n " );
2015-07-15 20:05:46 +03:00
}
2016-04-23 16:43:10 +03:00
/**
* @ it lexes punctuation
*/
2015-07-15 20:05:46 +03:00
public function testLexesPunctuation ()
{
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: BANG , 'start' => 0 , 'end' => 1 , 'value' => null ],
( array ) $this -> lexOne ( '!' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: DOLLAR , 'start' => 0 , 'end' => 1 , 'value' => null ],
( array ) $this -> lexOne ( '$' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: PAREN_L , 'start' => 0 , 'end' => 1 , 'value' => null ],
( array ) $this -> lexOne ( '(' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: PAREN_R , 'start' => 0 , 'end' => 1 , 'value' => null ],
( array ) $this -> lexOne ( ')' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: SPREAD , 'start' => 0 , 'end' => 3 , 'value' => null ],
( array ) $this -> lexOne ( '...' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: COLON , 'start' => 0 , 'end' => 1 , 'value' => null ],
( array ) $this -> lexOne ( ':' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: EQUALS , 'start' => 0 , 'end' => 1 , 'value' => null ],
( array ) $this -> lexOne ( '=' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: AT , 'start' => 0 , 'end' => 1 , 'value' => null ],
( array ) $this -> lexOne ( '@' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: BRACKET_L , 'start' => 0 , 'end' => 1 , 'value' => null ],
( array ) $this -> lexOne ( '[' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: BRACKET_R , 'start' => 0 , 'end' => 1 , 'value' => null ],
( array ) $this -> lexOne ( ']' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: BRACE_L , 'start' => 0 , 'end' => 1 , 'value' => null ],
( array ) $this -> lexOne ( '{' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: PIPE , 'start' => 0 , 'end' => 1 , 'value' => null ],
( array ) $this -> lexOne ( '|' )
2015-07-15 20:05:46 +03:00
);
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset (
[ 'kind' => Token :: BRACE_R , 'start' => 0 , 'end' => 1 , 'value' => null ],
( array ) $this -> lexOne ( '}' )
2016-04-23 16:43:10 +03:00
);
2015-07-15 20:05:46 +03:00
}
2016-04-23 16:43:10 +03:00
/**
* @ it lex reports useful unknown character error
*/
2015-07-15 20:05:46 +03:00
public function testReportsUsefulUnknownCharErrors ()
{
$run = function ( $num , $str , $expectedMessage ) {
try {
$this -> lexOne ( $str );
$this -> fail ( 'Expected exception not thrown in example: ' . $num );
2015-08-16 23:53:11 +03:00
} catch ( SyntaxError $e ) {
2015-07-15 20:05:46 +03:00
$this -> assertEquals ( $expectedMessage , $e -> getMessage (), " Test case $num failed " );
}
};
2016-11-19 13:08:20 +03:00
$run ( 1 , '..' , " Syntax Error GraphQL (1:1) Cannot parse the unexpected character \" . \" . \n \n 1: .. \n ^ \n " );
$run ( 2 , '?' , " Syntax Error GraphQL (1:1) Cannot parse the unexpected character \" ? \" . \n \n 1: ? \n ^ \n " );
2015-07-15 20:05:46 +03:00
$unicode = json_decode ( '"\u203B"' );
2016-11-19 13:08:20 +03:00
$run ( 3 , $unicode , " Syntax Error GraphQL (1:1) Cannot parse the unexpected character \" \\ u203b \" . \n \n 1: $unicode\n ^ \n " );
2016-04-23 16:43:10 +03:00
$unicode = json_decode ( '"\u200b"' );
2016-11-19 13:08:20 +03:00
$run ( 4 , $unicode , " Syntax Error GraphQL (1:1) Cannot parse the unexpected character \" \\ u200b \" . \n \n 1: $unicode\n ^ \n " );
2016-04-23 16:43:10 +03:00
}
/**
* @ it lex reports useful information for dashes in names
*/
public function testReportsUsefulDashesInfo ()
{
$q = 'a-b' ;
$lexer = new Lexer ( new Source ( $q ));
2016-10-16 22:53:50 +03:00
$this -> assertArraySubset ([ 'kind' => Token :: NAME , 'start' => 0 , 'end' => 1 , 'value' => 'a' ], ( array ) $lexer -> advance ());
2016-04-23 16:43:10 +03:00
try {
2016-10-16 22:53:50 +03:00
$lexer -> advance ();
2016-04-23 16:43:10 +03:00
$this -> fail ( 'Expected exception not thrown' );
} catch ( SyntaxError $err ) {
$this -> assertEquals ( 'Syntax Error GraphQL (1:3) Invalid number, expected digit but got: "b"' . " \n \n 1: a-b \n ^ \n " , $err -> getMessage ());
}
2015-07-15 20:05:46 +03:00
}
/**
2016-10-16 22:53:50 +03:00
* @ it produces double linked list of tokens , including comments
2015-07-15 20:05:46 +03:00
*/
2016-10-16 22:53:50 +03:00
public function testDoubleLinkedList ()
2015-07-15 20:05:46 +03:00
{
2016-10-16 22:53:50 +03:00
$lexer = new Lexer ( new Source ( ' {
#comment
field
} ' ));
$startToken = $lexer -> token ;
do {
$endToken = $lexer -> advance ();
// Lexer advances over ignored comment tokens to make writing parsers
// easier, but will include them in the linked list result.
$this -> assertNotEquals ( 'Comment' , $endToken -> kind );
} while ( $endToken -> kind !== '<EOF>' );
$this -> assertEquals ( null , $startToken -> prev );
$this -> assertEquals ( null , $endToken -> next );
$tokens = [];
for ( $tok = $startToken ; $tok ; $tok = $tok -> next ) {
if ( ! empty ( $tokens )) {
// Tokens are double-linked, prev should point to last seen token.
$this -> assertSame ( $tokens [ count ( $tokens ) - 1 ], $tok -> prev );
}
$tokens [] = $tok ;
}
$this -> assertEquals ([
'<SOF>' ,
'{' ,
'Comment' ,
'Name' ,
'}' ,
'<EOF>'
], Utils :: map ( $tokens , function ( $tok ) {
return $tok -> kind ;
}));
2015-07-15 20:05:46 +03:00
}
2016-04-23 16:43:10 +03:00
/**
2016-10-16 22:53:50 +03:00
* @ param string $body
2016-04-23 16:43:10 +03:00
* @ return Token
*/
2016-10-16 22:53:50 +03:00
private function lexOne ( $body )
2016-04-23 16:43:10 +03:00
{
$lexer = new Lexer ( new Source ( $body ));
2016-10-16 22:53:50 +03:00
return $lexer -> advance ();
2016-04-23 16:43:10 +03:00
}
2015-07-15 20:05:46 +03:00
}