1 //! Simulates parser execution, for a single token of input, without incurring
2 //! any side effects.
3 //!
4 //! This is basically a copy of the parser.rs source code with calls to
5 //! generated_parser::reduce, and stack bookkeeping, omitted.
6 
7 use crate::parser::Parser;
8 use ast::SourceLocation;
9 use generated_parser::{
10     noop_actions, ParseError, ParserTrait, Result, StackValue, Term, TermValue, TerminalId, Token,
11     TABLES,
12 };
13 
14 /// The Simulator is used to check whether we can shift one token, either to
15 /// check what might be accepted, or to check whether we can End parsing now.
16 /// This is used by the REPL to verify whether or not we can end the input.
17 pub struct Simulator<'alloc, 'parser> {
18     /// Define the top of the immutable stack.
19     sp: usize,
20     /// Immutable state stack coming from the forked parser.
21     state_stack: &'parser [usize],
22     /// Immuatable term stack coming from the forked parser.
23     node_stack: &'parser [TermValue<StackValue<'alloc>>],
24     /// Mutable state stack used by the simulator on top of the immutable
25     /// parser's state stack.
26     sim_state_stack: Vec<usize>,
27     /// Mutable term stack used by the simulator on top of the immutable
28     /// parser's term stack.
29     sim_node_stack: Vec<TermValue<()>>,
30     /// Mutable term stack used by the simulator for replaying terms when reducing non-terminals are replaying lookahead terminals.
31     replay_stack: Vec<TermValue<()>>,
32 }
33 
34 impl<'alloc, 'parser> ParserTrait<'alloc, ()> for Simulator<'alloc, 'parser> {
shift(&mut self, tv: TermValue<()>) -> Result<'alloc, bool>35     fn shift(&mut self, tv: TermValue<()>) -> Result<'alloc, bool> {
36         // Shift the new terminal/nonterminal and its associated value.
37         let mut state = self.state();
38         assert!(state < TABLES.shift_count);
39         let mut tv = tv;
40         loop {
41             let term_index: usize = tv.term.into();
42             assert!(term_index < TABLES.shift_width);
43             let index = state * TABLES.shift_width + term_index;
44             let goto = TABLES.shift_table[index];
45             if goto < 0 {
46                 // Error handling is in charge of shifting an ErrorSymbol from the
47                 // current state.
48                 self.try_error_handling(tv)?;
49                 tv = self.replay_stack.pop().unwrap();
50                 continue;
51             }
52             state = goto as usize;
53             self.sim_state_stack.push(state);
54             self.sim_node_stack.push(tv);
55             // Execute any actions, such as reduce actions.
56             if state >= TABLES.shift_count {
57                 assert!(state < TABLES.action_count + TABLES.shift_count);
58                 if noop_actions(self, state)? {
59                     return Ok(true);
60                 }
61                 state = self.state();
62             }
63             assert!(state < TABLES.shift_count);
64             if let Some(tv_temp) = self.replay_stack.pop() {
65                 tv = tv_temp;
66             } else {
67                 break;
68             }
69         }
70         Ok(false)
71     }
unshift(&mut self)72     fn unshift(&mut self) {
73         let tv = self.pop();
74         self.replay(tv)
75     }
pop(&mut self) -> TermValue<()>76     fn pop(&mut self) -> TermValue<()> {
77         if let Some(s) = self.sim_node_stack.pop() {
78             self.sim_state_stack.pop();
79             return s;
80         }
81         let t = self.node_stack[self.sp - 1].term;
82         self.sp -= 1;
83         TermValue { term: t, value: () }
84     }
replay(&mut self, tv: TermValue<()>)85     fn replay(&mut self, tv: TermValue<()>) {
86         self.replay_stack.push(tv)
87     }
epsilon(&mut self, state: usize)88     fn epsilon(&mut self, state: usize) {
89         if self.sim_state_stack.is_empty() {
90             self.sim_state_stack.push(self.state_stack[self.sp]);
91             self.sim_node_stack.push(TermValue {
92                 term: self.node_stack[self.sp - 1].term,
93                 value: (),
94             });
95             self.sp -= 1;
96         }
97         *self.sim_state_stack.last_mut().unwrap() = state;
98     }
check_not_on_new_line(&mut self, _peek: usize) -> Result<'alloc, bool>99     fn check_not_on_new_line(&mut self, _peek: usize) -> Result<'alloc, bool> {
100         Ok(true)
101     }
102 }
103 
104 impl<'alloc, 'parser> Simulator<'alloc, 'parser> {
new( state_stack: &'parser [usize], node_stack: &'parser [TermValue<StackValue<'alloc>>], ) -> Simulator<'alloc, 'parser>105     pub fn new(
106         state_stack: &'parser [usize],
107         node_stack: &'parser [TermValue<StackValue<'alloc>>],
108     ) -> Simulator<'alloc, 'parser> {
109         let sp = state_stack.len() - 1;
110         assert_eq!(state_stack.len(), node_stack.len() + 1);
111         Simulator {
112             sp,
113             state_stack,
114             node_stack,
115             sim_state_stack: vec![],
116             sim_node_stack: vec![],
117             replay_stack: vec![],
118         }
119     }
120 
state(&self) -> usize121     fn state(&self) -> usize {
122         if let Some(res) = self.sim_state_stack.last() {
123             *res
124         } else {
125             self.state_stack[self.sp]
126         }
127     }
128 
write_token(&mut self, t: TerminalId) -> Result<'alloc, ()>129     pub fn write_token(&mut self, t: TerminalId) -> Result<'alloc, ()> {
130         // Shift the token with the associated StackValue.
131         let accept = self.shift(TermValue {
132             term: Term::Terminal(t),
133             value: (),
134         })?;
135         // JavaScript grammar accepts empty inputs, therefore we can never
136         // accept any program before receiving a TerminalId::End.
137         assert!(!accept);
138         Ok(())
139     }
140 
close(&mut self, _position: usize) -> Result<'alloc, ()>141     pub fn close(&mut self, _position: usize) -> Result<'alloc, ()> {
142         // Shift the End terminal with the associated StackValue.
143         let accept = self.shift(TermValue {
144             term: Term::Terminal(TerminalId::End),
145             value: (),
146         })?;
147         // Adding a TerminalId::End would either lead to a parse error, or to
148         // accepting the current input. In which case we return matching node
149         // value.
150         assert!(accept);
151 
152         // We can either reduce a Script/Module, or a Script/Module followed by
153         // an <End> terminal.
154         assert!(self.sp + self.sim_node_stack.len() >= 1);
155         Ok(())
156     }
157 
158     // Simulate the action of Parser::try_error_handling.
try_error_handling(&mut self, t: TermValue<()>) -> Result<'alloc, bool>159     fn try_error_handling(&mut self, t: TermValue<()>) -> Result<'alloc, bool> {
160         if let Term::Terminal(term) = t.term {
161             let bogus_loc = SourceLocation::new(0, 0);
162             let token = &Token::basic_token(term, bogus_loc);
163 
164             // Error tokens might them-self cause more errors to be reported.
165             // This happens due to the fact that the ErrorToken can be replayed,
166             // and while the ErrorToken might be in the lookahead rules, it
167             // might not be in the shifted terms coming after the reduced
168             // nonterminal.
169             if t.term == Term::Terminal(TerminalId::ErrorToken) {
170                 return Err(Parser::parse_error(token).into());
171             }
172 
173             // Otherwise, check if the current rule accept an Automatic
174             // Semi-Colon insertion (ASI).
175             let state = self.state();
176             assert!(state < TABLES.shift_count);
177             let error_code = TABLES.error_codes[state];
178             if let Some(error_code) = error_code {
179                 Parser::recover(token, error_code)?;
180                 self.replay(t);
181                 self.replay(TermValue {
182                     term: Term::Terminal(TerminalId::ErrorToken),
183                     value: (),
184                 });
185                 return Ok(false);
186             }
187             return Err(Parser::parse_error(token).into());
188         }
189         // On error, don't attempt error handling again.
190         Err(ParseError::ParserCannotUnpackToken.into())
191     }
192 }
193