boa/syntax/parser/statement/iteration/
for_statement.rs1use crate::syntax::lexer::TokenKind;
11use crate::{
12 syntax::{
13 ast::{
14 node::{ForInLoop, ForLoop, ForOfLoop, Node},
15 Const, Keyword, Punctuator,
16 },
17 parser::{
18 expression::Expression,
19 statement::declaration::Declaration,
20 statement::{variable::VariableDeclarationList, Statement},
21 AllowAwait, AllowReturn, AllowYield, Cursor, ParseError, TokenParser,
22 },
23 },
24 BoaProfiler,
25};
26
27use std::io::Read;
28
29#[derive(Debug, Clone, Copy)]
38pub(in crate::syntax::parser::statement) struct ForStatement {
39 allow_yield: AllowYield,
40 allow_await: AllowAwait,
41 allow_return: AllowReturn,
42}
43
44impl ForStatement {
45 pub(in crate::syntax::parser::statement) fn new<Y, A, R>(
47 allow_yield: Y,
48 allow_await: A,
49 allow_return: R,
50 ) -> Self
51 where
52 Y: Into<AllowYield>,
53 A: Into<AllowAwait>,
54 R: Into<AllowReturn>,
55 {
56 Self {
57 allow_yield: allow_yield.into(),
58 allow_await: allow_await.into(),
59 allow_return: allow_return.into(),
60 }
61 }
62}
63
64impl<R> TokenParser<R> for ForStatement
65where
66 R: Read,
67{
68 type Output = Node;
69
70 fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
71 let _timer = BoaProfiler::global().start_event("ForStatement", "Parsing");
72 cursor.expect(Keyword::For, "for statement")?;
73 cursor.expect(Punctuator::OpenParen, "for statement")?;
74
75 let init = match cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?.kind() {
76 TokenKind::Keyword(Keyword::Var) => {
77 let _ = cursor.next()?;
78 Some(
79 VariableDeclarationList::new(false, self.allow_yield, self.allow_await)
80 .parse(cursor)
81 .map(Node::from)?,
82 )
83 }
84 TokenKind::Keyword(Keyword::Let) | TokenKind::Keyword(Keyword::Const) => {
85 Some(Declaration::new(self.allow_yield, self.allow_await, false).parse(cursor)?)
86 }
87 TokenKind::Punctuator(Punctuator::Semicolon) => None,
88 _ => Some(Expression::new(false, self.allow_yield, self.allow_await).parse(cursor)?),
89 };
90
91 match cursor.peek(0)? {
92 Some(tok) if tok.kind() == &TokenKind::Keyword(Keyword::In) && init.is_some() => {
93 let _ = cursor.next();
94 let expr =
95 Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?;
96 cursor.expect(Punctuator::CloseParen, "for in statement")?;
97 let body = Statement::new(self.allow_yield, self.allow_await, self.allow_return)
98 .parse(cursor)?;
99 return Ok(ForInLoop::new(init.unwrap(), expr, body).into());
100 }
101 Some(tok) if tok.kind() == &TokenKind::Keyword(Keyword::Of) && init.is_some() => {
102 let _ = cursor.next();
103 let iterable =
104 Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?;
105 cursor.expect(Punctuator::CloseParen, "for of statement")?;
106 let body = Statement::new(self.allow_yield, self.allow_await, self.allow_return)
107 .parse(cursor)?;
108 return Ok(ForOfLoop::new(init.unwrap(), iterable, body).into());
109 }
110 _ => {}
111 }
112
113 cursor.expect(Punctuator::Semicolon, "for statement")?;
114
115 let cond = if cursor.next_if(Punctuator::Semicolon)?.is_some() {
116 Const::from(true).into()
117 } else {
118 let step = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?;
119 cursor.expect(Punctuator::Semicolon, "for statement")?;
120 step
121 };
122
123 let step = if cursor.next_if(Punctuator::CloseParen)?.is_some() {
124 None
125 } else {
126 let step = Expression::new(true, self.allow_yield, self.allow_await).parse(cursor)?;
127 cursor.expect(
128 TokenKind::Punctuator(Punctuator::CloseParen),
129 "for statement",
130 )?;
131 Some(step)
132 };
133
134 let body =
135 Statement::new(self.allow_yield, self.allow_await, self.allow_return).parse(cursor)?;
136
137 Ok(ForLoop::new(init, cond, step, body).into())
139 }
140}