mirror of
https://github.com/danog/parser.git
synced 2024-11-27 04:14:55 +01:00
Merge pull request #80 from ryangjchandler/feature/halt-compiler
This commit is contained in:
commit
0146d3e1d1
@ -4,6 +4,7 @@ use crate::{ByteString, OpenTagKind, Token, TokenKind};
|
||||
pub enum LexerState {
|
||||
Initial,
|
||||
Scripting,
|
||||
Halted,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@ -78,6 +79,16 @@ impl Lexer {
|
||||
|
||||
tokens.push(self.scripting()?);
|
||||
}
|
||||
// The "Halted" state is entered when the `__halt_compiler` token is encountered.
|
||||
// In this state, all the text that follows is no longer parsed as PHP as is collected
|
||||
// into a single "InlineHtml" token (kind of cheating, oh well).
|
||||
LexerState::Halted => {
|
||||
tokens.push(Token {
|
||||
kind: TokenKind::InlineHtml(self.chars[self.cursor..].into()),
|
||||
span: (self.line, self.col),
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -300,8 +311,21 @@ impl Lexer {
|
||||
if qualified {
|
||||
TokenKind::QualifiedIdentifier(buffer.into())
|
||||
} else {
|
||||
identifier_to_keyword(&buffer)
|
||||
.unwrap_or_else(|| TokenKind::Identifier(buffer.into()))
|
||||
let kind = identifier_to_keyword(&buffer)
|
||||
.unwrap_or_else(|| TokenKind::Identifier(buffer.into()));
|
||||
|
||||
if kind == TokenKind::HaltCompiler {
|
||||
match self.peek_buf() {
|
||||
[b'(', b')', b';', ..] => {
|
||||
self.skip(3);
|
||||
self.col += 3;
|
||||
self.enter_state(LexerState::Halted);
|
||||
}
|
||||
_ => return Err(LexerError::InvalidHaltCompiler),
|
||||
}
|
||||
}
|
||||
|
||||
kind
|
||||
}
|
||||
}
|
||||
[b'/', b'*', ..] => {
|
||||
@ -755,6 +779,7 @@ impl Lexer {
|
||||
#[allow(dead_code)]
|
||||
fn identifier_to_keyword(ident: &[u8]) -> Option<TokenKind> {
|
||||
Some(match ident {
|
||||
b"__halt_compiler" | b"__HALT_COMPILER" => TokenKind::HaltCompiler,
|
||||
b"readonly" => TokenKind::Readonly,
|
||||
b"global" => TokenKind::Global,
|
||||
b"match" => TokenKind::Match,
|
||||
@ -817,6 +842,7 @@ fn identifier_to_keyword(ident: &[u8]) -> Option<TokenKind> {
|
||||
pub enum LexerError {
|
||||
UnexpectedEndOfFile,
|
||||
UnexpectedCharacter(u8),
|
||||
InvalidHaltCompiler,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@ -1080,6 +1106,32 @@ function hello_world() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn halt_compiler() {
|
||||
assert_tokens(
|
||||
"<?php __halt_compiler();",
|
||||
&[open!(), TokenKind::HaltCompiler],
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
"<?php __HALT_COMPILER();",
|
||||
&[open!(), TokenKind::HaltCompiler],
|
||||
);
|
||||
|
||||
assert_tokens(
|
||||
"<?php __halt_compiler(); Some jargon that comes after the halt, oops!",
|
||||
&[
|
||||
open!(),
|
||||
TokenKind::HaltCompiler,
|
||||
TokenKind::InlineHtml(
|
||||
" Some jargon that comes after the halt, oops!"
|
||||
.as_bytes()
|
||||
.into(),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
fn assert_tokens<B: ?Sized + AsRef<[u8]>>(source: &B, expected: &[TokenKind]) {
|
||||
let mut kinds = vec![];
|
||||
|
||||
|
@ -11,6 +11,7 @@ pub enum OpenTagKind {
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum TokenKind {
|
||||
HaltCompiler,
|
||||
Readonly,
|
||||
Global,
|
||||
Abstract,
|
||||
@ -172,6 +173,7 @@ impl Default for Token {
|
||||
impl Display for TokenKind {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let s = match self {
|
||||
Self::HaltCompiler => "__halt_compiler",
|
||||
Self::Readonly => "readonly",
|
||||
Self::AsteriskEqual => "*=",
|
||||
Self::ObjectCast => "(object)",
|
||||
|
@ -170,6 +170,9 @@ impl From<&TokenKind> for IncludeKind {
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum Statement {
|
||||
InlineHtml(ByteString),
|
||||
HaltCompiler {
|
||||
content: Option<ByteString>,
|
||||
},
|
||||
Static {
|
||||
vars: Vec<StaticVar>,
|
||||
},
|
||||
|
@ -171,6 +171,18 @@ impl Parser {
|
||||
self.skip_comments();
|
||||
|
||||
let statement = match &self.current.kind {
|
||||
TokenKind::HaltCompiler => {
|
||||
self.next();
|
||||
|
||||
let content = if let TokenKind::InlineHtml(content) = self.current.kind.clone() {
|
||||
self.next();
|
||||
Some(content)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
Statement::HaltCompiler { content }
|
||||
}
|
||||
TokenKind::Declare => {
|
||||
self.next();
|
||||
self.lparen()?;
|
||||
|
Loading…
Reference in New Issue
Block a user