parse_js/parse/
pattern.rs1use super::ParseCtx;
2use super::Parser;
3use crate::ast::ArrayPatternElement;
4use crate::ast::ClassOrObjectMemberKey;
5use crate::ast::Node;
6use crate::ast::Syntax;
7use crate::error::SyntaxErrorType;
8use crate::error::SyntaxResult;
9use crate::token::TokenType;
10use crate::token::UNRESERVED_KEYWORDS;
11
12#[derive(Clone, Copy)]
13pub struct ParsePatternRules {
14 pub await_allowed: bool,
16 pub yield_allowed: bool,
18}
19
20impl ParsePatternRules {
21 pub fn with_await_allowed(&self, await_allowed: bool) -> ParsePatternRules {
22 Self {
23 await_allowed,
24 ..*self
25 }
26 }
27
28 pub fn with_yield_allowed(&self, yield_allowed: bool) -> ParsePatternRules {
29 Self {
30 yield_allowed,
31 ..*self
32 }
33 }
34}
35
36pub fn is_valid_pattern_identifier(typ: TokenType, rules: ParsePatternRules) -> bool {
37 match typ {
38 TokenType::Identifier => true,
39 TokenType::KeywordAwait => rules.await_allowed,
40 TokenType::KeywordYield => rules.yield_allowed,
41 t => UNRESERVED_KEYWORDS.contains(&t),
42 }
43}
44
45impl<'a> Parser<'a> {
46 fn parse_pattern_identifier(&mut self, ctx: ParseCtx) -> SyntaxResult<Node> {
47 if !is_valid_pattern_identifier(self.peek()?.typ, ctx.rules) {
48 return Err(
49 self
50 .peek()?
51 .error(SyntaxErrorType::ExpectedSyntax("identifier")),
52 );
53 }
54 let t = self.next()?;
55 let node = Node::new(t.loc, Syntax::IdentifierPattern {
56 name: self.string(t.loc),
57 });
58 Ok(node)
59 }
60
61 pub fn parse_pattern(&mut self, ctx: ParseCtx) -> SyntaxResult<Node> {
62 let checkpoint = self.checkpoint();
63 let t = self.next()?;
64 Ok(match t.typ {
65 t if is_valid_pattern_identifier(t, ctx.rules) => {
66 self.restore_checkpoint(checkpoint);
67 self.parse_pattern_identifier(ctx)?
68 }
69 TokenType::BraceOpen => {
70 let mut properties = Vec::new();
71 let mut rest = None;
72 loop {
73 if self.peek()?.typ == TokenType::BraceClose {
74 break;
75 };
76 let mut loc = self.peek()?.loc;
77 if self.consume_if(TokenType::DotDotDot)?.is_match() {
79 rest = Some(self.parse_pattern_identifier(ctx)?);
80 break;
81 };
82
83 let (key_loc, key) = if self.consume_if(TokenType::BracketOpen)?.is_match() {
84 let expr = self.parse_expr(ctx, TokenType::BracketClose)?;
85 self.require(TokenType::BracketClose)?;
86 (expr.loc, ClassOrObjectMemberKey::Computed(expr))
87 } else {
88 let name = self.next()?;
89 if !is_valid_pattern_identifier(name.typ, ctx.rules) {
90 return Err(name.error(SyntaxErrorType::ExpectedNotFound));
91 };
92 (
93 name.loc,
94 ClassOrObjectMemberKey::Direct(self.string(name.loc)),
95 )
96 };
97 let (shorthand, target) = if self.consume_if(TokenType::Colon)?.is_match() {
98 (false, self.parse_pattern(ctx)?)
99 } else {
100 match &key {
101 ClassOrObjectMemberKey::Computed(name) => {
102 return Err(name.error(SyntaxErrorType::ExpectedSyntax(
103 "object pattern property subpattern",
104 )));
105 }
106 ClassOrObjectMemberKey::Direct(name) => (
107 true,
108 Node::new(key_loc, Syntax::IdentifierPattern { name: name.clone() }),
109 ),
110 }
111 };
112 let default_value = if self.consume_if(TokenType::Equals)?.is_match() {
113 Some(self.parse_expr_until_either(ctx, TokenType::Comma, TokenType::BraceClose)?)
114 } else {
115 None
116 };
117 loc.extend(default_value.as_ref().unwrap_or(&target).loc);
118 let direct_key_name = match &key {
119 ClassOrObjectMemberKey::Direct(name) => Some(name.clone()),
120 _ => None,
121 };
122 let property = Node::new(loc, Syntax::ObjectPatternProperty {
123 key,
124 target,
125 default_value,
126 shorthand,
127 });
128 properties.push(property);
129 if !self.consume_if(TokenType::Comma)?.is_match() {
131 break;
132 };
133 }
134 let close = self.require(TokenType::BraceClose)?;
135 Node::new(t.loc + close.loc, Syntax::ObjectPattern {
136 properties,
137 rest,
138 })
139 }
140 TokenType::BracketOpen => {
141 let mut elements = Vec::<Option<ArrayPatternElement>>::new();
142 let mut rest = None;
143 loop {
144 if self.consume_if(TokenType::BracketClose)?.is_match() {
145 break;
146 };
147 if self.consume_if(TokenType::DotDotDot)?.is_match() {
149 rest = Some(self.parse_pattern(ctx)?);
150 break;
151 };
152
153 if self.consume_if(TokenType::Comma)?.is_match() {
155 elements.push(None);
156 } else {
157 let target = self.parse_pattern(ctx)?;
158 let default_value = if self.consume_if(TokenType::Equals)?.is_match() {
159 Some(self.parse_expr_until_either(ctx, TokenType::Comma, TokenType::BracketClose)?)
160 } else {
161 None
162 };
163 elements.push(Some(ArrayPatternElement {
164 target,
165 default_value,
166 }));
167 if !self.consume_if(TokenType::Comma)?.is_match() {
169 break;
170 };
171 };
172 }
173 let close = self.require(TokenType::BracketClose)?;
174 Node::new(t.loc + close.loc, Syntax::ArrayPattern { elements, rest })
175 }
176 _ => return Err(t.error(SyntaxErrorType::ExpectedSyntax("pattern"))),
177 })
178 }
179}