Rust编写的JavaScript引擎,该项目是一个试验性质的项目。
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

177 lines
4.3 KiB

//! Boa parser implementation.
mod cursor;
pub mod error;
mod expression;
pub(crate) mod function;
mod statement;
#[cfg(test)]
mod tests;
pub use self::error::{ParseError, ParseResult};
use self::cursor::Cursor;
use crate::syntax::{ast::node::StatementList, lexer::TokenKind};
use boa_interner::Interner;
use std::io::Read;
/// Trait implemented by parsers.
///
/// This makes it possible to abstract over the underlying implementation of a parser.
trait TokenParser<R>: Sized
where
R: Read,
{
/// Output type for the parser.
type Output; // = Node; waiting for https://github.com/rust-lang/rust/issues/29661
/// Parses the token stream using the current parser.
///
/// This method needs to be provided by the implementor type.
fn parse(
self,
cursor: &mut Cursor<R>,
interner: &mut Interner,
) -> Result<Self::Output, ParseError>;
}
/// Boolean representing if the parser should allow a `yield` keyword.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct AllowYield(bool);
impl From<bool> for AllowYield {
fn from(allow: bool) -> Self {
Self(allow)
}
}
/// Boolean representing if the parser should allow a `await` keyword.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct AllowAwait(bool);
impl From<bool> for AllowAwait {
fn from(allow: bool) -> Self {
Self(allow)
}
}
/// Boolean representing if the parser should allow a `in` keyword.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct AllowIn(bool);
impl From<bool> for AllowIn {
fn from(allow: bool) -> Self {
Self(allow)
}
}
/// Boolean representing if the parser should allow a `return` keyword.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct AllowReturn(bool);
impl From<bool> for AllowReturn {
fn from(allow: bool) -> Self {
Self(allow)
}
}
/// Boolean representing if the parser should allow a `default` keyword.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct AllowDefault(bool);
impl From<bool> for AllowDefault {
fn from(allow: bool) -> Self {
Self(allow)
}
}
#[derive(Debug)]
pub struct Parser<R> {
/// Cursor of the parser, pointing to the lexer and used to get tokens for the parser.
cursor: Cursor<R>,
}
impl<R> Parser<R> {
pub fn new(reader: R, strict_mode: bool) -> Self
where
R: Read,
{
let mut cursor = Cursor::new(reader);
cursor.set_strict_mode(strict_mode);
Self { cursor }
}
pub fn parse_all(&mut self, interner: &mut Interner) -> Result<StatementList, ParseError>
where
R: Read,
{
Script.parse(&mut self.cursor, interner)
}
}
/// Parses a full script.
///
/// More information:
/// - [ECMAScript specification][spec]
///
/// [spec]: https://tc39.es/ecma262/#prod-Script
#[derive(Debug, Clone, Copy)]
pub struct Script;
impl<R> TokenParser<R> for Script
where
R: Read,
{
type Output = StatementList;
fn parse(
self,
cursor: &mut Cursor<R>,
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
match cursor.peek(0, interner)? {
Some(tok) => {
let mut strict = false;
match tok.kind() {
// Set the strict mode
TokenKind::StringLiteral(string)
if interner.resolve_expect(*string) == "use strict" =>
{
cursor.set_strict_mode(true);
strict = true;
}
_ => {}
}
let mut statement_list = ScriptBody.parse(cursor, interner)?;
statement_list.set_strict(strict);
Ok(statement_list)
}
None => Ok(StatementList::from(Vec::new())),
}
}
}
/// Parses a script body.
///
/// More information:
/// - [ECMAScript specification][spec]
///
/// [spec]: https://tc39.es/ecma262/#prod-ScriptBody
#[derive(Debug, Clone, Copy)]
pub struct ScriptBody;
impl<R> TokenParser<R> for ScriptBody
where
R: Read,
{
type Output = StatementList;
fn parse(
self,
cursor: &mut Cursor<R>,
interner: &mut Interner,
) -> Result<Self::Output, ParseError> {
self::statement::StatementList::new(false, false, false, false, &[]).parse(cursor, interner)
}
}