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::general(
170 format!("invalid scope analysis: {reason}"),
171 Position::new(1, 1),
172 ));
173 }
174 Ok((ast, source))
175 }
176
177 pub fn parse_module(
186 &mut self,
187 scope: &Scope,
188 interner: &mut Interner,
189 ) -> ParseResult<boa_ast::Module>
190 where
191 R: ReadChar,
192 {
193 self.parse_module_with_source(scope, interner).map(|x| x.0)
194 }
195
196 pub fn parse_module_with_source(
205 &mut self,
206 scope: &Scope,
207 interner: &mut Interner,
208 ) -> ParseResult<ModuleParseOutput>
209 where
210 R: ReadChar,
211 {
212 self.cursor.set_goal(InputElement::HashbangOrRegExp);
213 let (mut module, source) = ModuleParser.parse(&mut self.cursor, interner)?;
214 if let Err(reason) = module.analyze_scope(scope, interner) {
215 return Err(Error::general(
216 format!("invalid scope analysis: {reason}"),
217 Position::new(1, 1),
218 ));
219 }
220 Ok((module, source))
221 }
222
223 pub fn parse_eval(
233 &mut self,
234 direct: bool,
235 interner: &mut Interner,
236 ) -> ParseResult<ScriptParseOutput> {
237 self.cursor.set_goal(InputElement::HashbangOrRegExp);
238 ScriptParser::new(direct).parse(&mut self.cursor, interner)
239 }
240
241 pub fn parse_function_body(
249 &mut self,
250 interner: &mut Interner,
251 allow_yield: bool,
252 allow_await: bool,
253 ) -> ParseResult<FunctionBody> {
254 let mut parser = FunctionStatementList::new(allow_yield, allow_await, "function body");
255 parser.parse_full_input(true);
256 parser.parse(&mut self.cursor, interner)
257 }
258
259 pub fn parse_formal_parameters(
267 &mut self,
268 interner: &mut Interner,
269 allow_yield: bool,
270 allow_await: bool,
271 ) -> ParseResult<FormalParameterList> {
272 FormalParameters::new(allow_yield, allow_await).parse(&mut self.cursor, interner)
273 }
274}
275
276impl<R> Parser<'_, R> {
277 pub fn set_strict(&mut self)
279 where
280 R: ReadChar,
281 {
282 self.cursor.set_strict(true);
283 }
284
285 pub fn set_json_parse(&mut self)
287 where
288 R: ReadChar,
289 {
290 self.cursor.set_json_parse(true);
291 }
292
293 pub fn set_identifier(&mut self, identifier: u32)
295 where
296 R: ReadChar,
297 {
298 self.cursor.set_identifier(identifier);
299 }
300}
301
302#[derive(Debug, Clone, Copy)]
309pub struct ScriptParser {
310 direct_eval: bool,
311}
312
313impl ScriptParser {
314 #[inline]
316 const fn new(direct_eval: bool) -> Self {
317 Self { direct_eval }
318 }
319}
320
321impl<R> TokenParser<R> for ScriptParser
322where
323 R: ReadChar,
324{
325 type Output = ScriptParseOutput;
326
327 fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
328 let stmts =
329 ScriptBody::new(true, cursor.strict(), self.direct_eval).parse(cursor, interner)?;
330 let script = boa_ast::Script::new(stmts);
331
332 let mut lexical_names = FxHashSet::default();
334 for name in lexically_declared_names(&script) {
335 if !lexical_names.insert(name) {
336 return Err(Error::general(
337 "lexical name declared multiple times",
338 Position::new(1, 1),
339 ));
340 }
341 }
342
343 for name in var_declared_names(&script) {
345 if lexical_names.contains(&name) {
346 return Err(Error::general(
347 "lexical name declared multiple times",
348 Position::new(1, 1),
349 ));
350 }
351 }
352
353 let source = cursor.take_source();
354 Ok((script, source))
355 }
356}
357
358#[derive(Debug, Clone, Copy)]
365pub struct ScriptBody {
366 directive_prologues: bool,
367 strict: bool,
368 direct_eval: bool,
369}
370
371impl ScriptBody {
372 #[inline]
374 const fn new(directive_prologues: bool, strict: bool, direct_eval: bool) -> Self {
375 Self {
376 directive_prologues,
377 strict,
378 direct_eval,
379 }
380 }
381}
382
383impl<R> TokenParser<R> for ScriptBody
384where
385 R: ReadChar,
386{
387 type Output = StatementList;
388
389 fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
390 let (body, _end) = statement::StatementList::new(
391 false,
392 false,
393 false,
394 &[],
395 self.directive_prologues,
396 self.strict,
397 )
398 .parse(cursor, interner)?;
399
400 if !self.direct_eval {
401 if contains(&body, ContainsSymbol::Super) {
405 return Err(Error::general("invalid super usage", Position::new(1, 1)));
406 }
407 if contains(&body, ContainsSymbol::NewTarget) {
411 return Err(Error::general(
412 "invalid new.target usage",
413 Position::new(1, 1),
414 ));
415 }
416
417 if !all_private_identifiers_valid(&body, Vec::new()) {
421 return Err(Error::general(
422 "invalid private identifier usage",
423 Position::new(1, 1),
424 ));
425 }
426 }
427
428 if let Err(error) = check_labels(&body) {
429 return Err(Error::lex(LexError::Syntax(
430 error.message(interner).into(),
431 Position::new(1, 1),
432 )));
433 }
434
435 if contains_invalid_object_literal(&body) {
436 return Err(Error::lex(LexError::Syntax(
437 "invalid object literal in script statement list".into(),
438 Position::new(1, 1),
439 )));
440 }
441
442 Ok(body)
443 }
444}
445
446#[derive(Debug, Clone, Copy)]
453struct ModuleParser;
454
455impl<R> TokenParser<R> for ModuleParser
456where
457 R: ReadChar,
458{
459 type Output = ModuleParseOutput;
460
461 fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
462 cursor.set_module();
463
464 let module = boa_ast::Module::new(ModuleItemList.parse(cursor, interner)?);
465
466 let mut bindings = FxHashSet::default();
468 for name in lexically_declared_names(&module) {
469 if !bindings.insert(name) {
470 return Err(Error::general(
471 format!(
472 "lexical name `{}` declared multiple times",
473 interner.resolve_expect(name)
474 ),
475 Position::new(1, 1),
476 ));
477 }
478 }
479
480 for name in var_declared_names(&module) {
483 if !bindings.insert(name) {
484 return Err(Error::general(
485 format!(
486 "lexical name `{}` declared multiple times",
487 interner.resolve_expect(name)
488 ),
489 Position::new(1, 1),
490 ));
491 }
492 }
493
494 {
496 let mut exported_names = FxHashSet::default();
497 for name in module.items().exported_names() {
498 if !exported_names.insert(name) {
499 return Err(Error::general(
500 format!(
501 "exported name `{}` declared multiple times",
502 interner.resolve_expect(name)
503 ),
504 Position::new(1, 1),
505 ));
506 }
507 }
508 }
509
510 for name in module.items().exported_bindings() {
513 if !bindings.contains(&name) {
514 return Err(Error::general(
515 format!(
516 "could not find the exported binding `{}` in the declared names of the module",
517 interner.resolve_expect(name)
518 ),
519 Position::new(1, 1),
520 ));
521 }
522 }
523
524 if contains(&module, ContainsSymbol::Super) {
526 return Err(Error::general(
527 "module cannot contain `super` on the top-level",
528 Position::new(1, 1),
529 ));
530 }
531
532 if contains(&module, ContainsSymbol::NewTarget) {
534 return Err(Error::general(
535 "module cannot contain `new.target` on the top-level",
536 Position::new(1, 1),
537 ));
538 }
539
540 check_labels(&module).map_err(|error| {
544 Error::lex(LexError::Syntax(
545 error.message(interner).into(),
546 Position::new(1, 1),
547 ))
548 })?;
549
550 if !all_private_identifiers_valid(&module, Vec::new()) {
552 return Err(Error::general(
553 "invalid private identifier usage",
554 Position::new(1, 1),
555 ));
556 }
557
558 let source = cursor.take_source();
559 Ok((module, source))
560 }
561}
562
563fn name_in_lexically_declared_names(
565 bound_names: &[Sym],
566 lexical_names: &[Sym],
567 position: Position,
568 interner: &Interner,
569) -> ParseResult<()> {
570 for name in bound_names {
571 if lexical_names.contains(name) {
572 return Err(Error::general(
573 format!(
574 "formal parameter `{}` declared in lexically declared names",
575 interner.resolve_expect(*name)
576 ),
577 position,
578 ));
579 }
580 }
581 Ok(())
582}
583
584trait OrAbrupt<T> {
586 fn or_abrupt(self) -> ParseResult<T>;
588}
589
590impl<T> OrAbrupt<T> for ParseResult<Option<T>> {
591 fn or_abrupt(self) -> ParseResult<T> {
592 self?.ok_or(Error::AbruptEnd)
593 }
594}