Browse Source

Added check to ignore semicolon in parser (#913)

* Added check to ignore semicolon in parser

* Combined parse and parse_general functions for StatementList

* Change to static lifetime, remove break when closing braces, removed script end token

* Revert semicolon cursor skip
pull/931/head
Forest Anderson 4 years ago committed by GitHub
parent
commit
0a0c230a1b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 13
      boa/src/syntax/parser/function/mod.rs
  2. 2
      boa/src/syntax/parser/mod.rs
  3. 5
      boa/src/syntax/parser/statement/block/mod.rs
  4. 83
      boa/src/syntax/parser/statement/mod.rs
  5. 8
      boa/src/syntax/parser/statement/switch/mod.rs

13
boa/src/syntax/parser/function/mod.rs

@ -225,6 +225,9 @@ where
/// [spec]: https://tc39.es/ecma262/#prod-FunctionBody /// [spec]: https://tc39.es/ecma262/#prod-FunctionBody
pub(in crate::syntax::parser) type FunctionBody = FunctionStatementList; pub(in crate::syntax::parser) type FunctionBody = FunctionStatementList;
/// The possible TokenKind which indicate the end of a function statement.
const FUNCTION_BREAK_TOKENS: [TokenKind; 1] = [TokenKind::Punctuator(Punctuator::CloseBlock)];
/// A function statement list /// A function statement list
/// ///
/// More information: /// More information:
@ -275,8 +278,14 @@ where
} }
} }
let stmlist = let stmlist = StatementList::new(
StatementList::new(self.allow_yield, self.allow_await, true, true, true).parse(cursor); self.allow_yield,
self.allow_await,
true,
true,
&FUNCTION_BREAK_TOKENS,
)
.parse(cursor);
// Reset strict mode back to the global scope. // Reset strict mode back to the global scope.
cursor.set_strict_mode(global_strict_mode); cursor.set_strict_mode(global_strict_mode);

2
boa/src/syntax/parser/mod.rs

@ -155,6 +155,6 @@ where
type Output = StatementList; type Output = StatementList;
fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> { fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
self::statement::StatementList::new(false, false, false, false, true).parse(cursor) self::statement::StatementList::new(false, false, false, true, &[]).parse(cursor)
} }
} }

5
boa/src/syntax/parser/statement/block/mod.rs

@ -23,6 +23,9 @@ use crate::{
use std::io::Read; use std::io::Read;
/// The possible TokenKind which indicate the end of a block statement.
const BLOCK_BREAK_TOKENS: [TokenKind; 1] = [TokenKind::Punctuator(Punctuator::CloseBlock)];
/// A `BlockStatement` is equivalent to a `Block`. /// A `BlockStatement` is equivalent to a `Block`.
/// ///
/// More information: /// More information:
@ -83,7 +86,7 @@ where
self.allow_await, self.allow_await,
self.allow_return, self.allow_return,
true, true,
true, &BLOCK_BREAK_TOKENS,
) )
.parse(cursor) .parse(cursor)
.map(node::Block::from)?; .map(node::Block::from)?;

83
boa/src/syntax/parser/statement/mod.rs

@ -207,8 +207,6 @@ where
/// Reads a list of statements. /// Reads a list of statements.
/// ///
/// If `break_when_closingbrase` is `true`, it will stop as soon as it finds a `}` character.
///
/// More information: /// More information:
/// - [ECMAScript specification][spec] /// - [ECMAScript specification][spec]
/// ///
@ -218,8 +216,8 @@ pub(super) struct StatementList {
allow_yield: AllowYield, allow_yield: AllowYield,
allow_await: AllowAwait, allow_await: AllowAwait,
allow_return: AllowReturn, allow_return: AllowReturn,
break_when_closingbraces: bool,
in_block: bool, in_block: bool,
break_nodes: &'static [TokenKind],
} }
impl StatementList { impl StatementList {
@ -228,8 +226,8 @@ impl StatementList {
allow_yield: Y, allow_yield: Y,
allow_await: A, allow_await: A,
allow_return: R, allow_return: R,
break_when_closingbraces: bool,
in_block: bool, in_block: bool,
break_nodes: &'static [TokenKind],
) -> Self ) -> Self
where where
Y: Into<AllowYield>, Y: Into<AllowYield>,
@ -240,59 +238,10 @@ impl StatementList {
allow_yield: allow_yield.into(), allow_yield: allow_yield.into(),
allow_await: allow_await.into(), allow_await: allow_await.into(),
allow_return: allow_return.into(), allow_return: allow_return.into(),
break_when_closingbraces,
in_block, in_block,
break_nodes,
} }
} }
/// The function parses a node::StatementList using the given break_nodes to know when to terminate.
///
/// This ignores the break_when_closingbraces flag.
///
/// Returns a ParseError::AbruptEnd if end of stream is reached before a break token.
///
/// This is a more general version of the TokenParser parse function for StatementList which can exit based on multiple
/// different tokens. This may eventually replace the parse() function but is currently seperate to allow testing the
/// performance impact of this more general mechanism.
///
/// Note that the last token which causes the parse to finish is not consumed.
pub(crate) fn parse_generalised<R>(
self,
cursor: &mut Cursor<R>,
break_nodes: &[TokenKind],
) -> Result<node::StatementList, ParseError>
where
R: Read,
{
let mut items = Vec::new();
loop {
if let Some(token) = cursor.peek(0)? {
if break_nodes.contains(token.kind()) {
break;
}
} else {
return Err(ParseError::AbruptEnd);
}
let item = StatementListItem::new(
self.allow_yield,
self.allow_await,
self.allow_return,
self.in_block,
)
.parse(cursor)?;
items.push(item);
// move the cursor forward for any consecutive semicolon.
while cursor.next_if(Punctuator::Semicolon)?.is_some() {}
}
items.sort_by(Node::hoistable_order);
Ok(items.into())
}
} }
impl<R> TokenParser<R> for StatementList impl<R> TokenParser<R> for StatementList
@ -301,26 +250,24 @@ where
{ {
type Output = node::StatementList; type Output = node::StatementList;
/// The function parses a node::StatementList using the StatementList's
/// break_nodes to know when to terminate.
///
/// Returns a ParseError::AbruptEnd if end of stream is reached before a
/// break token.
///
/// Returns a ParseError::unexpected if an unexpected token is found.
///
/// Note that the last token which causes the parse to finish is not
/// consumed.
fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> { fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
let _timer = BoaProfiler::global().start_event("StatementList", "Parsing"); let _timer = BoaProfiler::global().start_event("StatementList", "Parsing");
let mut items = Vec::new(); let mut items = Vec::new();
loop { loop {
match cursor.peek(0)? { match cursor.peek(0)? {
Some(token) if token.kind() == &TokenKind::Punctuator(Punctuator::CloseBlock) => { Some(token) if self.break_nodes.contains(token.kind()) => break,
if self.break_when_closingbraces { None => break,
break;
} else {
return Err(ParseError::unexpected(token.clone(), None));
}
}
None => {
if self.break_when_closingbraces {
return Err(ParseError::AbruptEnd);
} else {
break;
}
}
_ => {} _ => {}
} }

8
boa/src/syntax/parser/statement/switch/mod.rs

@ -129,10 +129,10 @@ where
self.allow_yield, self.allow_yield,
self.allow_await, self.allow_await,
self.allow_return, self.allow_return,
true,
false, false,
&CASE_BREAK_TOKENS,
) )
.parse_generalised(cursor, &CASE_BREAK_TOKENS)?; .parse(cursor)?;
cases.push(node::Case::new(cond, statement_list)); cases.push(node::Case::new(cond, statement_list));
} }
@ -151,10 +151,10 @@ where
self.allow_yield, self.allow_yield,
self.allow_await, self.allow_await,
self.allow_return, self.allow_return,
true,
false, false,
&CASE_BREAK_TOKENS,
) )
.parse_generalised(cursor, &CASE_BREAK_TOKENS)?; .parse(cursor)?;
default = Some(statement_list); default = Some(statement_list);
} }

Loading…
Cancel
Save