boa_parser/parser/statement/block/
mod.rs1#[cfg(test)]
11mod tests;
12
13use crate::{
14 Error,
15 lexer::TokenKind,
16 parser::{
17 AllowAwait, AllowReturn, AllowYield, Cursor, OrAbrupt, ParseResult, TokenParser,
18 statement::StatementList,
19 },
20 source::ReadChar,
21};
22use boa_ast::{
23 Punctuator, Spanned,
24 operations::{lexically_declared_names_legacy, var_declared_names},
25 statement,
26};
27use boa_interner::Interner;
28use rustc_hash::FxHashMap;
29
30const BLOCK_BREAK_TOKENS: [TokenKind; 1] = [TokenKind::Punctuator(Punctuator::CloseBlock)];
32
33pub(super) type BlockStatement = Block;
40
41#[derive(Debug, Clone, Copy)]
50pub(super) struct Block {
51 allow_yield: AllowYield,
52 allow_await: AllowAwait,
53 allow_return: AllowReturn,
54}
55
56impl Block {
57 pub(super) fn new<Y, A, R>(allow_yield: Y, allow_await: A, allow_return: R) -> Self
59 where
60 Y: Into<AllowYield>,
61 A: Into<AllowAwait>,
62 R: Into<AllowReturn>,
63 {
64 Self {
65 allow_yield: allow_yield.into(),
66 allow_await: allow_await.into(),
67 allow_return: allow_return.into(),
68 }
69 }
70}
71
72impl<R> TokenParser<R> for Block
73where
74 R: ReadChar,
75{
76 type Output = statement::Block;
77
78 fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
79 cursor.expect(Punctuator::OpenBlock, "block", interner)?;
80 if let Some(tk) = cursor.peek(0, interner)?
81 && tk.kind() == &TokenKind::Punctuator(Punctuator::CloseBlock)
82 {
83 cursor.advance(interner);
84 return Ok(statement::Block::from((vec![], cursor.linear_pos())));
85 }
86 let position = cursor.peek(0, interner).or_abrupt()?.span().start();
87 let (statement_list, _end) = StatementList::new(
88 self.allow_yield,
89 self.allow_await,
90 self.allow_return,
91 &BLOCK_BREAK_TOKENS,
92 false,
93 false,
94 )
95 .parse(cursor, interner)
96 .map(|(statement_list, end)| (statement::Block::from(statement_list), end))?;
97 cursor.expect(Punctuator::CloseBlock, "block", interner)?;
98
99 let mut lexical_names = FxHashMap::default();
103 for (name, is_fn) in lexically_declared_names_legacy(&statement_list) {
104 if let Some(is_fn_previous) = lexical_names.insert(name, is_fn) {
105 match (cursor.strict(), is_fn, is_fn_previous) {
106 (false, true, true) => {}
107 _ => {
108 return Err(Error::general(
109 "lexical name declared multiple times",
110 position,
111 ));
112 }
113 }
114 }
115 }
116
117 for name in var_declared_names(&statement_list) {
120 if lexical_names.contains_key(&name) {
121 return Err(Error::general(
122 "lexical name declared in var names",
123 position,
124 ));
125 }
126 }
127
128 Ok(statement_list)
129 }
130}