1mod cursor;
4mod expression;
5mod statement;
6
7pub(crate) mod function;
8
9#[cfg(test)]
10mod tests;
11
12use crate::{
13 Error, Source,
14 error::ParseResult,
15 lexer::{Error as LexError, InputElement},
16 parser::{
17 cursor::Cursor,
18 function::{FormalParameters, FunctionStatementList},
19 },
20 source::ReadChar,
21};
22use boa_ast::{
23 Position, StatementList,
24 function::{FormalParameterList, FunctionBody},
25 operations::{
26 ContainsSymbol, all_private_identifiers_valid, check_labels, contains,
27 contains_invalid_object_literal, lexically_declared_names, var_declared_names,
28 },
29 scope::Scope,
30};
31use boa_interner::{Interner, Sym};
32use rustc_hash::FxHashSet;
33use std::path::Path;
34
35use self::statement::ModuleItemList;
36
37type ScriptParseOutput = (boa_ast::Script, boa_ast::SourceText);
38type ModuleParseOutput = (boa_ast::Module, boa_ast::SourceText);
39
40trait TokenParser<R>: Sized
44where
45 R: ReadChar,
46{
47 type Output; fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output>;
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq)]
62struct AllowYield(bool);
63
64impl From<bool> for AllowYield {
65 fn from(allow: bool) -> Self {
66 Self(allow)
67 }
68}
69
70#[derive(Debug, Clone, Copy, PartialEq, Eq)]
72struct AllowAwait(bool);
73
74impl From<bool> for AllowAwait {
75 fn from(allow: bool) -> Self {
76 Self(allow)
77 }
78}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82struct AllowIn(bool);
83
84impl From<bool> for AllowIn {
85 fn from(allow: bool) -> Self {
86 Self(allow)
87 }
88}
89
90#[derive(Debug, Clone, Copy, PartialEq, Eq)]
92struct AllowReturn(bool);
93
94impl From<bool> for AllowReturn {
95 fn from(allow: bool) -> Self {
96 Self(allow)
97 }
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq)]
102struct AllowDefault(bool);
103
104impl From<bool> for AllowDefault {
105 fn from(allow: bool) -> Self {
106 Self(allow)
107 }
108}
109
110#[derive(Debug)]
120pub struct Parser<'a, R> {
121 #[allow(unused)] path: Option<&'a Path>,
124 cursor: Cursor<R>,
126}
127
128impl<'a, R: ReadChar> Parser<'a, R> {
129 pub fn new(source: Source<'a, R>) -> Self {
131 Self {
132 path: source.path,
133 cursor: Cursor::new(source.reader),
134 }
135 }
136
137 pub fn parse_script(
146 &mut self,
147 scope: &Scope,
148 interner: &mut Interner,
149 ) -> ParseResult<boa_ast::Script> {
150 self.parse_script_with_source(scope, interner).map(|x| x.0)
151 }
152
153 pub fn parse_script_with_source(
162 &mut self,
163 scope: &Scope,
164 interner: &mut Interner,
165 ) -> ParseResult<ScriptParseOutput> {
166 self.cursor.set_goal(InputElement::HashbangOrRegExp);
167 let (mut ast, source) = ScriptParser::new(false).parse(&mut self.cursor, interner)?;
168 if let Err(reason) = ast.analyze_scope(scope, interner) {
169 return Err(Error::scope_analysis(reason));
170 }
171 Ok((ast, source))
172 }
173
174 pub fn parse_module(
183 &mut self,
184 scope: &Scope,
185 interner: &mut Interner,
186 ) -> ParseResult<boa_ast::Module>
187 where
188 R: ReadChar,
189 {
190 self.parse_module_with_source(scope, interner).map(|x| x.0)
191 }
192
193 pub fn parse_module_with_source(
202 &mut self,
203 scope: &Scope,
204 interner: &mut Interner,
205 ) -> ParseResult<ModuleParseOutput>
206 where
207 R: ReadChar,
208 {
209 self.cursor.set_goal(InputElement::HashbangOrRegExp);
210 let (mut module, source) = ModuleParser.parse(&mut self.cursor, interner)?;
211 if let Err(reason) = module.analyze_scope(scope, interner) {
212 return Err(Error::scope_analysis(reason));
213 }
214 Ok((module, source))
215 }
216
217 pub fn parse_eval(
227 &mut self,
228 direct: bool,
229 interner: &mut Interner,
230 ) -> ParseResult<ScriptParseOutput> {
231 self.cursor.set_goal(InputElement::HashbangOrRegExp);
232 ScriptParser::new(direct).parse(&mut self.cursor, interner)
233 }
234
235 pub fn parse_function_body(
243 &mut self,
244 interner: &mut Interner,
245 allow_yield: bool,
246 allow_await: bool,
247 ) -> ParseResult<FunctionBody> {
248 let mut parser = FunctionStatementList::new(allow_yield, allow_await, "function body");
249 parser.parse_full_input(true);
250 parser.parse(&mut self.cursor, interner)
251 }
252
253 pub fn parse_formal_parameters(
261 &mut self,
262 interner: &mut Interner,
263 allow_yield: bool,
264 allow_await: bool,
265 ) -> ParseResult<FormalParameterList> {
266 FormalParameters::new(allow_yield, allow_await).parse(&mut self.cursor, interner)
267 }
268}
269
270impl<R> Parser<'_, R> {
271 pub fn set_strict(&mut self)
273 where
274 R: ReadChar,
275 {
276 self.cursor.set_strict(true);
277 }
278
279 pub fn set_json_parse(&mut self)
281 where
282 R: ReadChar,
283 {
284 self.cursor.set_json_parse(true);
285 }
286
287 pub fn set_identifier(&mut self, identifier: u32)
289 where
290 R: ReadChar,
291 {
292 self.cursor.set_identifier(identifier);
293 }
294}
295
296#[derive(Debug, Clone, Copy)]
303pub struct ScriptParser {
304 direct_eval: bool,
305}
306
307impl ScriptParser {
308 #[inline]
310 const fn new(direct_eval: bool) -> Self {
311 Self { direct_eval }
312 }
313}
314
315impl<R> TokenParser<R> for ScriptParser
316where
317 R: ReadChar,
318{
319 type Output = ScriptParseOutput;
320
321 fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
322 let stmts =
323 ScriptBody::new(true, cursor.strict(), self.direct_eval).parse(cursor, interner)?;
324 let script = boa_ast::Script::new(stmts);
325
326 let mut lexical_names = FxHashSet::default();
328 for name in lexically_declared_names(&script) {
329 if !lexical_names.insert(name) {
330 return Err(Error::general(
331 "lexical name declared multiple times",
332 Position::new(1, 1),
333 ));
334 }
335 }
336
337 for name in var_declared_names(&script) {
339 if lexical_names.contains(&name) {
340 return Err(Error::general(
341 "lexical name declared multiple times",
342 Position::new(1, 1),
343 ));
344 }
345 }
346
347 let source = cursor.take_source();
348 Ok((script, source))
349 }
350}
351
352#[derive(Debug, Clone, Copy)]
359pub struct ScriptBody {
360 directive_prologues: bool,
361 strict: bool,
362 direct_eval: bool,
363}
364
365impl ScriptBody {
366 #[inline]
368 const fn new(directive_prologues: bool, strict: bool, direct_eval: bool) -> Self {
369 Self {
370 directive_prologues,
371 strict,
372 direct_eval,
373 }
374 }
375}
376
377impl<R> TokenParser<R> for ScriptBody
378where
379 R: ReadChar,
380{
381 type Output = StatementList;
382
383 fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
384 let (body, _end) = statement::StatementList::new(
385 false,
386 false,
387 false,
388 &[],
389 self.directive_prologues,
390 self.strict,
391 )
392 .parse(cursor, interner)?;
393
394 if !self.direct_eval {
395 if contains(&body, ContainsSymbol::Super) {
399 return Err(Error::general("invalid super usage", Position::new(1, 1)));
400 }
401 if contains(&body, ContainsSymbol::NewTarget) {
405 return Err(Error::general(
406 "invalid new.target usage",
407 Position::new(1, 1),
408 ));
409 }
410
411 if !all_private_identifiers_valid(&body, Vec::new()) {
415 return Err(Error::general(
416 "invalid private identifier usage",
417 Position::new(1, 1),
418 ));
419 }
420 }
421
422 if let Err(error) = check_labels(&body) {
423 return Err(Error::lex(LexError::Syntax(
424 error.message(interner).into(),
425 Position::new(1, 1),
426 )));
427 }
428
429 if contains_invalid_object_literal(&body) {
430 return Err(Error::lex(LexError::Syntax(
431 "invalid object literal in script statement list".into(),
432 Position::new(1, 1),
433 )));
434 }
435
436 Ok(body)
437 }
438}
439
440#[derive(Debug, Clone, Copy)]
447struct ModuleParser;
448
449impl<R> TokenParser<R> for ModuleParser
450where
451 R: ReadChar,
452{
453 type Output = ModuleParseOutput;
454
455 fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
456 cursor.set_module();
457
458 let module = boa_ast::Module::new(ModuleItemList.parse(cursor, interner)?);
459
460 let mut bindings = FxHashSet::default();
462 for name in lexically_declared_names(&module) {
463 if !bindings.insert(name) {
464 return Err(Error::general(
465 format!(
466 "lexical name `{}` declared multiple times",
467 interner.resolve_expect(name)
468 ),
469 Position::new(1, 1),
470 ));
471 }
472 }
473
474 for name in var_declared_names(&module) {
477 if !bindings.insert(name) {
478 return Err(Error::general(
479 format!(
480 "lexical name `{}` declared multiple times",
481 interner.resolve_expect(name)
482 ),
483 Position::new(1, 1),
484 ));
485 }
486 }
487
488 {
490 let mut exported_names = FxHashSet::default();
491 for name in module.items().exported_names() {
492 if !exported_names.insert(name) {
493 return Err(Error::general(
494 format!(
495 "exported name `{}` declared multiple times",
496 interner.resolve_expect(name)
497 ),
498 Position::new(1, 1),
499 ));
500 }
501 }
502 }
503
504 for name in module.items().exported_bindings() {
507 if !bindings.contains(&name) {
508 return Err(Error::general(
509 format!(
510 "could not find the exported binding `{}` in the declared names of the module",
511 interner.resolve_expect(name)
512 ),
513 Position::new(1, 1),
514 ));
515 }
516 }
517
518 if contains(&module, ContainsSymbol::Super) {
520 return Err(Error::general(
521 "module cannot contain `super` on the top-level",
522 Position::new(1, 1),
523 ));
524 }
525
526 if contains(&module, ContainsSymbol::NewTarget) {
528 return Err(Error::general(
529 "module cannot contain `new.target` on the top-level",
530 Position::new(1, 1),
531 ));
532 }
533
534 check_labels(&module).map_err(|error| {
538 Error::lex(LexError::Syntax(
539 error.message(interner).into(),
540 Position::new(1, 1),
541 ))
542 })?;
543
544 if !all_private_identifiers_valid(&module, Vec::new()) {
546 return Err(Error::general(
547 "invalid private identifier usage",
548 Position::new(1, 1),
549 ));
550 }
551
552 let source = cursor.take_source();
553 Ok((module, source))
554 }
555}
556
557fn name_in_lexically_declared_names(
559 bound_names: &[Sym],
560 lexical_names: &[Sym],
561 position: Position,
562 interner: &Interner,
563) -> ParseResult<()> {
564 for name in bound_names {
565 if lexical_names.contains(name) {
566 return Err(Error::general(
567 format!(
568 "formal parameter `{}` declared in lexically declared names",
569 interner.resolve_expect(*name)
570 ),
571 position,
572 ));
573 }
574 }
575 Ok(())
576}
577
578trait OrAbrupt<T> {
580 fn or_abrupt(self) -> ParseResult<T>;
582}
583
584impl<T> OrAbrupt<T> for ParseResult<Option<T>> {
585 fn or_abrupt(self) -> ParseResult<T> {
586 self?.ok_or(Error::AbruptEnd)
587 }
588}