Skip to content

Commit 44e644d

Browse files
committed
parser rewrite: initial rewrite (need to do this with all other Nodes)
1 parent feb4e7d commit 44e644d

File tree

3 files changed

+348
-10
lines changed

3 files changed

+348
-10
lines changed

core/parser/src/parser/mod.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ mod statement;
66

77
pub(crate) mod function;
88

9+
mod parse_loop;
10+
911
#[cfg(test)]
1012
mod tests;
1113

@@ -15,6 +17,7 @@ use crate::{
1517
parser::{
1618
cursor::Cursor,
1719
function::{FormalParameters, FunctionStatementList},
20+
parse_loop::{ControlFlow, ParseLoop, ParsedNode, SavedState, TokenLoopParser},
1821
},
1922
source::ReadChar,
2023
Error, Source,
@@ -387,15 +390,17 @@ where
387390
type Output = StatementList;
388391

389392
fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
390-
let (body, _end) = statement::StatementList::new(
393+
let entry = statement::StatementList::new(
391394
false,
392395
false,
393396
false,
394397
&[],
395398
self.directive_prologues,
396399
self.strict,
397-
)
398-
.parse(cursor, interner)?;
400+
);
401+
let stmt_list_node = ParseLoop::parse_loop(cursor, interner, entry)?;
402+
let (body, _end) = (stmt_list_node.list, stmt_list_node.pos);
403+
// let (body, _end) = entry.parse(cursor, interner)?;
399404

400405
if !self.direct_eval {
401406
// It is a Syntax Error if StatementList Contains super unless the source text containing super is eval
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
use boa_ast::Position;
2+
use boa_interner::Interner;
3+
4+
use boa_ast as ast;
5+
use crate::error::{ParseResult, Error};
6+
use crate::lexer::Token;
7+
use crate::source::ReadChar;
8+
use crate::parser::Cursor;
9+
use crate::parser::statement::{StatementList, StatementListLocal, StatementListNode};
10+
11+
#[macro_export]
12+
macro_rules! parse_cmd {
13+
// or move into `pop_local_state!`
14+
[[POP LOCAL]: $state:ident => $variant:ident] => {{
15+
let Ok($crate::parser::SavedState::$variant(ret)) = $state.pop_local_state() else {
16+
return Err($state.general_error(concat!("expect `", stringify!($variant) ,"Local` saved state")))
17+
};
18+
ret
19+
}};
20+
21+
// or move into `pop_last_node!`
22+
[[POP NODE]: $state:ident => $variant:ident] => {{
23+
let Ok($crate::parser::ParsedNode::$variant(ret)) = $state.pop_node() else {
24+
return Err($state.general_error(concat!("expect `", stringify!($variant) ,"Local` saved state")))
25+
};
26+
ret
27+
}};
28+
29+
// or move into `sub_parse!`
30+
[[SUB PARSE]: $item:expr; $state:ident <= $local:ident as $variant:ident ($point:literal)] => {{
31+
$state.push_local($crate::parser::SavedState::$variant($local));
32+
return ParseResult::Ok($crate::parser::ControlFlow::SubParse { node: Box::new($item), point: $point });
33+
}};
34+
35+
// or move into `parse_done!`
36+
[[DONE]: $state:ident <= $variant:ident($node:expr)] => {{
37+
$state.push_node($crate::parser::ParsedNode::$variant($node));
38+
return Ok($crate::parser::ControlFlow::Done)
39+
}};
40+
}
41+
42+
pub(super) struct ParseLoop;
43+
44+
impl ParseLoop {
45+
pub(super) fn parse_loop<R: ReadChar>(
46+
cursor: &mut Cursor<R>,
47+
interner: &mut Interner,
48+
entry: StatementList
49+
) -> ParseResult<StatementListNode> {
50+
let mut state: ParseState<'_, R> = ParseState::new(cursor, interner);
51+
52+
let mut parse_stack: Vec<Box<dyn TokenLoopParser<R>>> = vec![Box::new(entry)];
53+
let mut continue_points = vec![0];
54+
55+
loop {
56+
debug_assert!(!parse_stack.is_empty());
57+
debug_assert_eq!(continue_points.len(), parse_stack.len());
58+
59+
let continue_point = continue_points.pop().unwrap();
60+
let parser = parse_stack.last_mut().unwrap();
61+
62+
match parser.parse_loop(&mut state, continue_point)? {
63+
ControlFlow::SubParse { node, point } => {
64+
continue_points.push(point); // reinsert current updated `continue_point`
65+
continue_points.push(0); // insert continue point for new sub parsing node
66+
67+
parse_stack.push(node);
68+
}
69+
ControlFlow::Done => {
70+
// remove parsing node from stack (`continue_point` already removed)
71+
parse_stack.pop();
72+
73+
if parse_stack.is_empty() {
74+
let stmt_list_node = parse_cmd![[POP NODE]: state => StatementList];
75+
assert!(state.nodes.is_empty());
76+
return Ok(stmt_list_node)
77+
}
78+
}
79+
}
80+
81+
}
82+
}
83+
}
84+
85+
/// Trait implemented by parsers.
86+
///
87+
/// This makes it possible to abstract over the underlying implementation of a parser.
88+
pub(super) trait TokenLoopParser<R>
89+
where
90+
R: ReadChar,
91+
{
92+
/// Parses the token stream using the current parser.
93+
///
94+
/// This method needs to be provided by the implementor type.
95+
///
96+
/// # Errors
97+
///
98+
/// It will fail if the cursor is not placed at the beginning of the expected non-terminal.
99+
fn parse_loop(&mut self, state: &mut ParseState<'_, R>, continue_point: usize) -> ParseResult<ControlFlow<R>>;
100+
}
101+
102+
pub(super) enum ControlFlow<R>
103+
where R: ReadChar,
104+
{
105+
SubParse{node: Box<dyn TokenLoopParser<R>>, point: usize},
106+
Done,
107+
}
108+
109+
pub(super) struct ParseState<'a, R> {
110+
nodes: Vec<ParsedNode>,
111+
saved_state: Vec<SavedState>,
112+
cursor: &'a mut Cursor<R>,
113+
interner: &'a mut Interner,
114+
}
115+
impl<'a, R: ReadChar> ParseState<'a, R> {
116+
pub(super) fn new(cursor: &'a mut Cursor<R>, interner: &'a mut Interner) -> Self {
117+
Self {
118+
nodes: Vec::new(),
119+
saved_state: Vec::new(),
120+
cursor,
121+
interner,
122+
}
123+
}
124+
pub(super) fn mut_inner(&mut self) -> (&mut Cursor<R>, &mut Interner) {
125+
(&mut self.cursor, &mut self.interner)
126+
}
127+
128+
pub(super) fn cursor(&mut self) -> &Cursor<R> {
129+
&self.cursor
130+
}
131+
pub(super) fn cursor_mut(&mut self) -> &mut Cursor<R> {
132+
&mut self.cursor
133+
}
134+
pub(super) fn interner(&self) -> &Interner {
135+
&self.interner
136+
}
137+
pub(super) fn interner_mut(&mut self) -> &mut Interner {
138+
&mut self.interner
139+
}
140+
141+
pub(super) fn push_node(&mut self, node: ParsedNode) {
142+
self.nodes.push(node);
143+
}
144+
pub(super) fn push_local(&mut self, local: SavedState) {
145+
self.saved_state.push(local);
146+
}
147+
148+
pub(super) fn pop_node(&mut self) -> ParseResult<ParsedNode> {
149+
self.nodes.pop().ok_or_else(||self.general_error("expect parsed node"))
150+
}
151+
152+
pub(super) fn pop_local_state(&mut self) -> ParseResult<SavedState> {
153+
self.saved_state.pop().ok_or_else(||self.general_error("expect saved state"))
154+
}
155+
156+
pub(super) fn continue_point_error<T>(&self, continue_point: usize) -> ParseResult<T> {
157+
Err(self.general_error(format!("unexpected continue point ({continue_point})")))
158+
}
159+
160+
pub(super) fn general_error<S: AsRef<str>>(&self, msg: S) -> Error {
161+
Error::general(
162+
format!("{}; linear position: {}", msg.as_ref(), self.cursor.linear_pos()),
163+
Position::new(1, 1) // TODO: something to take last position see `self.cursor.linear_pos()`
164+
)
165+
}
166+
167+
///Peeks a future token, without consuming it or advancing the cursor. This peeking skips line terminators.
168+
///
169+
/// You can skip some tokens with the `skip_n` option.
170+
pub(super) fn peek(&mut self, skip_n: usize) -> ParseResult<Option<&Token>> {
171+
self.cursor.peek(skip_n, &mut self.interner)
172+
}
173+
}
174+
175+
pub(super) enum ParsedNode {
176+
Empty,
177+
StatementListItem(ast::StatementListItem),
178+
StatementList(StatementListNode),
179+
}
180+
181+
pub(super) enum SavedState {
182+
StatementList(StatementListLocal),
183+
}

0 commit comments

Comments
 (0)