mirror of
https://github.com/danog/parser.git
synced 2024-11-26 20:04:57 +01:00
feature: allow opening / closing tags in middle of scripting code (#172)
This commit is contained in:
parent
f17fd22cdb
commit
e7c83fe768
@ -37,9 +37,7 @@ impl Lexer {
|
||||
// The "Initial" state is used to parse inline HTML. It is essentially a catch-all
|
||||
// state that will build up a single token buffer until it encounters an open tag
|
||||
// of some description.
|
||||
StackFrame::Initial => {
|
||||
tokens.append(&mut self.initial(&mut state)?);
|
||||
}
|
||||
StackFrame::Initial => self.initial(&mut state, &mut tokens)?,
|
||||
// The scripting state is entered when an open tag is encountered in the source code.
|
||||
// This tells the lexer to start analysing characters at PHP tokens instead of inline HTML.
|
||||
StackFrame::Scripting => {
|
||||
@ -107,18 +105,16 @@ impl Lexer {
|
||||
}
|
||||
}
|
||||
|
||||
fn initial(&self, state: &mut State) -> SyntaxResult<Vec<Token>> {
|
||||
fn initial(&self, state: &mut State, tokens: &mut Vec<Token>) -> SyntaxResult<()> {
|
||||
let inline_span = state.span;
|
||||
let mut buffer = Vec::new();
|
||||
while let Some(char) = state.current {
|
||||
if state.try_read(b"<?php") {
|
||||
let tag_span = state.span;
|
||||
|
||||
state.skip(5);
|
||||
|
||||
state.replace(StackFrame::Scripting);
|
||||
|
||||
let mut tokens = vec![];
|
||||
|
||||
if !buffer.is_empty() {
|
||||
tokens.push(Token {
|
||||
kind: TokenKind::InlineHtml(buffer.into()),
|
||||
@ -131,17 +127,19 @@ impl Lexer {
|
||||
span: tag_span,
|
||||
});
|
||||
|
||||
return Ok(tokens);
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
state.next();
|
||||
buffer.push(char);
|
||||
}
|
||||
|
||||
Ok(vec![Token {
|
||||
tokens.push(Token {
|
||||
kind: TokenKind::InlineHtml(buffer.into()),
|
||||
span: inline_span,
|
||||
}])
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn scripting(&self, state: &mut State) -> SyntaxResult<Token> {
|
||||
|
@ -15,6 +15,11 @@ impl Parser {
|
||||
let mut block = Block::new();
|
||||
|
||||
while !state.is_eof() && &state.current.kind != until {
|
||||
if let TokenKind::OpenTag(_) = state.current.kind {
|
||||
state.next();
|
||||
continue;
|
||||
}
|
||||
|
||||
block.push(self.statement(state)?);
|
||||
state.skip_comments();
|
||||
}
|
||||
|
@ -26,13 +26,21 @@ impl Parser {
|
||||
found,
|
||||
state.current.span,
|
||||
));
|
||||
} else {
|
||||
state.next();
|
||||
}
|
||||
|
||||
Ok(end)
|
||||
}
|
||||
|
||||
pub(in crate::parser) fn left_brace(&self, state: &mut State) -> ParseResult<Span> {
|
||||
self.skip(state, TokenKind::LeftBrace)
|
||||
let span = self.skip(state, TokenKind::LeftBrace)?;
|
||||
// A closing PHP tag is valid after a left brace, since
|
||||
// that typically indicates the start of a block (control structures).
|
||||
if state.current.kind == TokenKind::CloseTag {
|
||||
state.next();
|
||||
}
|
||||
Ok(span)
|
||||
}
|
||||
|
||||
pub(in crate::parser) fn right_brace(&self, state: &mut State) -> ParseResult<Span> {
|
||||
@ -56,6 +64,12 @@ impl Parser {
|
||||
}
|
||||
|
||||
pub(in crate::parser) fn colon(&self, state: &mut State) -> ParseResult<Span> {
|
||||
self.skip(state, TokenKind::Colon)
|
||||
let span = self.skip(state, TokenKind::Colon)?;
|
||||
// A closing PHP tag is valid after a colon, since
|
||||
// that typically indicates the start of a block (control structures).
|
||||
if state.current.kind == TokenKind::CloseTag {
|
||||
state.next();
|
||||
}
|
||||
Ok(span)
|
||||
}
|
||||
}
|
||||
|
@ -177,6 +177,11 @@ impl Parser {
|
||||
|
||||
state.clear_comments();
|
||||
|
||||
// A closing PHP tag is valid after the end of any top-level statement.
|
||||
if state.current.kind == TokenKind::CloseTag {
|
||||
state.next();
|
||||
}
|
||||
|
||||
Ok(statement)
|
||||
}
|
||||
|
||||
@ -706,13 +711,18 @@ impl Parser {
|
||||
// FIXME: Tidy up duplication and make the intent a bit clearer.
|
||||
match state.current.kind {
|
||||
TokenKind::Colon => {
|
||||
state.next();
|
||||
self.colon(state)?;
|
||||
|
||||
let mut then = vec![];
|
||||
while !matches!(
|
||||
state.current.kind,
|
||||
TokenKind::ElseIf | TokenKind::Else | TokenKind::EndIf
|
||||
) {
|
||||
if let TokenKind::OpenTag(_) = state.current.kind {
|
||||
state.next();
|
||||
continue;
|
||||
}
|
||||
|
||||
then.push(self.statement(state)?);
|
||||
}
|
||||
|
||||
@ -735,6 +745,11 @@ impl Parser {
|
||||
state.current.kind,
|
||||
TokenKind::ElseIf | TokenKind::Else | TokenKind::EndIf
|
||||
) {
|
||||
if let TokenKind::OpenTag(_) = state.current.kind {
|
||||
state.next();
|
||||
continue;
|
||||
}
|
||||
|
||||
body.push(self.statement(state)?);
|
||||
}
|
||||
|
||||
@ -746,10 +761,8 @@ impl Parser {
|
||||
state.next();
|
||||
self.colon(state)?;
|
||||
|
||||
let mut body = vec![];
|
||||
while state.current.kind != TokenKind::EndIf {
|
||||
body.push(self.statement(state)?);
|
||||
}
|
||||
let body = self.block(state, &TokenKind::EndIf)?;
|
||||
|
||||
r#else = Some(body);
|
||||
}
|
||||
|
||||
@ -766,8 +779,7 @@ impl Parser {
|
||||
}
|
||||
_ => {
|
||||
let body_end_token = if state.current.kind == TokenKind::LeftBrace {
|
||||
state.next();
|
||||
|
||||
self.left_brace(state)?;
|
||||
TokenKind::RightBrace
|
||||
} else {
|
||||
TokenKind::SemiColon
|
||||
@ -912,6 +924,11 @@ impl Parser {
|
||||
|
||||
state.skip_comments();
|
||||
|
||||
// A closing PHP tag is valid after the end of any top-level statement.
|
||||
if state.current.kind == TokenKind::CloseTag {
|
||||
state.next();
|
||||
}
|
||||
|
||||
Ok(statement)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user