boa/syntax/parser/
mod.rs

1//! Boa parser implementation.
2
3mod cursor;
4pub mod error;
5mod expression;
6mod function;
7mod statement;
8#[cfg(test)]
9mod tests;
10
11pub use self::error::{ParseError, ParseResult};
12use crate::syntax::{ast::node::StatementList, lexer::TokenKind};
13
14use cursor::Cursor;
15
16use std::io::Read;
17
18/// Trait implemented by parsers.
19///
20/// This makes it possible to abstract over the underlying implementation of a parser.
21trait TokenParser<R>: Sized
22where
23    R: Read,
24{
25    /// Output type for the parser.
26    type Output; // = Node; waiting for https://github.com/rust-lang/rust/issues/29661
27
28    /// Parses the token stream using the current parser.
29    ///
30    /// This method needs to be provided by the implementor type.
31    fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError>;
32}
33
34/// Boolean representing if the parser should allow a `yield` keyword.
35#[derive(Debug, Clone, Copy, PartialEq, Eq)]
36struct AllowYield(bool);
37
38impl From<bool> for AllowYield {
39    fn from(allow: bool) -> Self {
40        Self(allow)
41    }
42}
43
44/// Boolean representing if the parser should allow a `await` keyword.
45#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46struct AllowAwait(bool);
47
48impl From<bool> for AllowAwait {
49    fn from(allow: bool) -> Self {
50        Self(allow)
51    }
52}
53
54/// Boolean representing if the parser should allow a `in` keyword.
55#[derive(Debug, Clone, Copy, PartialEq, Eq)]
56struct AllowIn(bool);
57
58impl From<bool> for AllowIn {
59    fn from(allow: bool) -> Self {
60        Self(allow)
61    }
62}
63
64/// Boolean representing if the parser should allow a `return` keyword.
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66struct AllowReturn(bool);
67
68impl From<bool> for AllowReturn {
69    fn from(allow: bool) -> Self {
70        Self(allow)
71    }
72}
73
74/// Boolean representing if the parser should allow a `default` keyword.
75#[derive(Debug, Clone, Copy, PartialEq, Eq)]
76struct AllowDefault(bool);
77
78impl From<bool> for AllowDefault {
79    fn from(allow: bool) -> Self {
80        Self(allow)
81    }
82}
83
84#[derive(Debug)]
85pub struct Parser<R> {
86    /// Cursor of the parser, pointing to the lexer and used to get tokens for the parser.
87    cursor: Cursor<R>,
88}
89
90impl<R> Parser<R> {
91    pub fn new(reader: R, strict_mode: bool) -> Self
92    where
93        R: Read,
94    {
95        let mut cursor = Cursor::new(reader);
96        cursor.set_strict_mode(strict_mode);
97
98        Self { cursor }
99    }
100
101    pub fn parse_all(&mut self) -> Result<StatementList, ParseError>
102    where
103        R: Read,
104    {
105        Script.parse(&mut self.cursor)
106    }
107}
108
109/// Parses a full script.
110///
111/// More information:
112///  - [ECMAScript specification][spec]
113///
114/// [spec]: https://tc39.es/ecma262/#prod-Script
115#[derive(Debug, Clone, Copy)]
116pub struct Script;
117
118impl<R> TokenParser<R> for Script
119where
120    R: Read,
121{
122    type Output = StatementList;
123
124    fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
125        match cursor.peek(0)? {
126            Some(tok) => {
127                let mut strict = false;
128                match tok.kind() {
129                    TokenKind::StringLiteral(string) if string.as_ref() == "use strict" => {
130                        cursor.set_strict_mode(true);
131                        strict = true;
132                    }
133                    _ => {}
134                }
135                let mut statement_list = ScriptBody.parse(cursor)?;
136                statement_list.set_strict(strict);
137                Ok(statement_list)
138            }
139            None => Ok(StatementList::from(Vec::new())),
140        }
141    }
142}
143
144/// Parses a script body.
145///
146/// More information:
147///  - [ECMAScript specification][spec]
148///
149/// [spec]: https://tc39.es/ecma262/#prod-ScriptBody
150#[derive(Debug, Clone, Copy)]
151pub struct ScriptBody;
152
153impl<R> TokenParser<R> for ScriptBody
154where
155    R: Read,
156{
157    type Output = StatementList;
158
159    fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
160        self::statement::StatementList::new(false, false, false, false, &[]).parse(cursor)
161    }
162}