/** * @dataProvider provideTestHaltCompiler */ public function testHandleHaltCompiler($code, $remaining) { $lexer = new PHPParser_Lexer($code); while (PHPParser_Parser::T_HALT_COMPILER !== $lexer->lex()) { } $this->assertEquals($lexer->handleHaltCompiler(), $remaining); $this->assertEquals(0, $lexer->lex()); }
public function lex(&$value = null, &$line = null, &$docComment = null) { $token = parent::lex($value, $line, $docComment); // replace new keywords by their respective tokens. This is not done // if we currently are in an object access (e.g. in $obj->namespace // "namespace" stays a T_STRING tokens and isn't converted to T_NAMESPACE) if (PHPParser_Parser::T_STRING === $token && !$this->inObjectAccess) { if (isset(self::$keywords[strtolower($value)])) { return self::$keywords[strtolower($value)]; } // backslashes are replaced by T_NS_SEPARATOR tokens } elseif (92 === $token) { // ord('\\') return PHPParser_Parser::T_NS_SEPARATOR; // keep track of whether we currently are in an object access (after ->) } elseif (PHPParser_Parser::T_OBJECT_OPERATOR === $token) { $this->inObjectAccess = true; } else { $this->inObjectAccess = false; } return $token; }
/** * Parses PHP code into a node tree. * * @param PHPParser_Lexer $lexer A lexer * * @return array Array of statements */ public function parse(PHPParser_Lexer $lexer) { $this->lexer = $lexer; $this->yysp = 0; // Stack pos $yysstk = array($yystate = 0); // State stack $this->yyastk = array(); // AST stack (?) $yylstk = array($yyline = 1); // Line stack $yydstk = array($yyDC = null); // Doc comment stack $yychar = -1; for (;;) { if (self::$yybase[$yystate] == 0) { $yyn = self::$yydefault[$yystate]; } else { if ($yychar < 0) { if (($yychar = $lexer->lex($yylval, $yyline, $yyDC)) < 0) { $yychar = 0; } $yychar = $yychar < self::YYMAXLEX ? self::$yytranslate[$yychar] : self::YYBADCH; $yylstk[$this->yysp] = $yyline; $yydstk[$this->yysp] = $yyDC; } if ((($yyn = self::$yybase[$yystate] + $yychar) >= 0 && $yyn < self::YYLAST && self::$yycheck[$yyn] == $yychar || $yystate < self::YY2TBLSTATE && ($yyn = self::$yybase[$yystate + self::YYNLSTATES] + $yychar) >= 0 && $yyn < self::YYLAST && self::$yycheck[$yyn] == $yychar) && ($yyn = self::$yyaction[$yyn]) != self::YYDEFAULT) { /* * >= YYNLSTATE: shift and reduce * > 0: shift * = 0: accept * < 0: reduce * = -YYUNEXPECTED: error */ if ($yyn > 0) { /* shift */ ++$this->yysp; $yysstk[$this->yysp] = $yystate = $yyn; $this->yyastk[$this->yysp] = $yylval; $yylstk[$this->yysp] = $yyline; $yydstk[$this->yysp] = $yyDC; $yychar = -1; if ($yyn < self::YYNLSTATES) { continue; } /* $yyn >= YYNLSTATES means shift-and-reduce */ $yyn -= self::YYNLSTATES; } else { $yyn = -$yyn; } } else { $yyn = self::$yydefault[$yystate]; } } for (;;) { /* reduce/error */ if ($yyn == 0) { /* accept */ return $this->yyval; } elseif ($yyn != self::YYUNEXPECTED) { /* reduce */ try { $this->{'yyn' . $yyn}($yylstk[$this->yysp - self::$yylen[$yyn]], $yydstk[$this->yysp - self::$yylen[$yyn]]); } catch (PHPParser_Error $e) { if (-1 === $e->getRawLine()) { $e->setRawLine($yyline); } throw $e; } /* Goto - shift nonterminal */ $this->yysp -= self::$yylen[$yyn]; $yyn = self::$yylhs[$yyn]; if (($yyp = self::$yygbase[$yyn] + $yysstk[$this->yysp]) >= 0 && $yyp < self::YYGLAST && self::$yygcheck[$yyp] == $yyn) { $yystate = self::$yygoto[$yyp]; } else { $yystate = self::$yygdefault[$yyn]; } ++$this->yysp; $yysstk[$this->yysp] = $yystate; $this->yyastk[$this->yysp] = $this->yyval; $yylstk[$this->yysp] = $yyline; $yydstk[$this->yysp] = $yyDC; } else { /* error */ throw new PHPParser_Error('Unexpected token ' . self::$yyterminals[$yychar], $yyline); } if ($yystate < self::YYNLSTATES) { break; } /* >= YYNLSTATES means shift-and-reduce */ $yyn = $yystate - self::YYNLSTATES; } } }