parse_js/parse/
class_or_object.rs

1use super::expr::Asi;
2use super::pattern::is_valid_pattern_identifier;
3use super::pattern::ParsePatternRules;
4use super::ParseCtx;
5use super::Parser;
6use crate::ast::ClassOrObjectMemberKey;
7use crate::ast::ClassOrObjectMemberValue;
8use crate::ast::Node;
9use crate::ast::Syntax;
10use crate::error::SyntaxResult;
11use crate::lex::KEYWORDS_MAPPING;
12use crate::loc::Loc;
13use crate::token::TokenType;
14
15pub struct ParseClassBodyResult {
16  pub members: Vec<Node>, // Always ClassMember.
17  pub end: Loc,
18}
19
20pub struct ParseClassOrObjectMemberResult {
21  pub key: ClassOrObjectMemberKey,
22  pub key_loc: Loc,
23  pub value: ClassOrObjectMemberValue,
24  pub value_loc: Loc,
25}
26
27impl<'a> Parser<'a> {
28  pub fn parse_class_body(&mut self, ctx: ParseCtx) -> SyntaxResult<ParseClassBodyResult> {
29    self.require(TokenType::BraceOpen)?;
30    let mut members = Vec::new();
31    while self.peek()?.typ != TokenType::BraceClose {
32      // `static` must always come first if present.
33      let static_ = self.consume_if(TokenType::KeywordStatic)?.match_loc();
34      let ParseClassOrObjectMemberResult {
35        key,
36        key_loc,
37        value,
38        value_loc,
39      } = self.parse_class_or_object_member(
40        ctx,
41        TokenType::Equals,
42        TokenType::Semicolon,
43        &mut Asi::can(),
44      )?;
45      self.consume_if(TokenType::Semicolon)?;
46      members.push(Node::new(
47        key_loc.add_option(static_) + value_loc,
48        Syntax::ClassMember {
49          key,
50          static_: static_.is_some(),
51          value,
52        },
53      ));
54    }
55    let end = self.require(TokenType::BraceClose)?.loc;
56    Ok(ParseClassBodyResult { members, end })
57  }
58
59  // It's strictly one of these:
60  // <key> [ '=' <expr> ]? [ <asi> | ';' ]
61  // async? '*'? <key> '(' ...
62  // [ get | set ] <key> '(' ...
63  // where <key> = <ident> | <keyword> | <str> | <num> | '[' <expr> ']'
64  pub fn parse_class_or_object_member(
65    &mut self,
66    ctx: ParseCtx,
67    value_delimiter: TokenType,
68    statement_delimiter: TokenType,
69    property_initialiser_asi: &mut Asi,
70  ) -> SyntaxResult<ParseClassOrObjectMemberResult> {
71    let checkpoint = self.checkpoint();
72    let mut is_getter = false;
73    let mut is_setter = false;
74    let mut is_async = false;
75    if self.consume_if(TokenType::KeywordGet)?.is_match() {
76      is_getter = true;
77    } else if self.consume_if(TokenType::KeywordSet)?.is_match() {
78      is_setter = true;
79    } else if self.consume_if(TokenType::KeywordAsync)?.is_match() {
80      is_async = true;
81    }
82    if is_getter || is_setter || is_async {
83      let next_tok = self.peek()?.typ;
84      if next_tok == value_delimiter || next_tok == TokenType::ParenthesisOpen {
85        // Not actually getter/setter, just using `get`/`set` as property name.
86        self.restore_checkpoint(checkpoint);
87        is_getter = false;
88        is_setter = false;
89        is_async = false;
90      };
91    }
92    let is_generator = self.consume_if(TokenType::Asterisk)?.is_match();
93    let (key_loc, key) = if self.consume_if(TokenType::BracketOpen)?.is_match() {
94      let key = self.parse_expr(ctx, TokenType::BracketClose)?;
95      self.require(TokenType::BracketClose)?;
96      (key.loc, ClassOrObjectMemberKey::Computed(key))
97    } else {
98      let loc = if let Some(str) = self.consume_if(TokenType::LiteralString)?.match_loc() {
99        // TODO Do we need to remove quotes and/or decode?
100        str
101      } else if let Some(num) = self.consume_if(TokenType::LiteralNumber)?.match_loc() {
102        // TODO Do we need to normalise?
103        num
104      } else if let Some(loc) = self.consume_if(TokenType::PrivateMember)?.match_loc() {
105        loc
106      } else if let Some(loc) = self
107        .consume_if_pred(|t| is_valid_pattern_identifier(t.typ, ctx.rules))?
108        .match_loc()
109      {
110        loc
111      } else {
112        self
113          .require_predicate(
114            |t| KEYWORDS_MAPPING.contains_key(&t),
115            "keyword or identifier",
116          )?
117          .loc
118      };
119      (loc, ClassOrObjectMemberKey::Direct(self.string(loc)))
120    };
121    // Check is_generator/is_async first so that we don't have to check that they're false in every other branch.
122    let (value_loc, value) =
123      if is_generator || is_async || self.peek()?.typ == TokenType::ParenthesisOpen {
124        let parameters = self.parse_function_parameters(ctx)?;
125        let body = self.parse_function_body(ctx.with_rules(ParsePatternRules {
126          await_allowed: !is_async && ctx.rules.await_allowed,
127          yield_allowed: !is_generator && ctx.rules.yield_allowed,
128        }))?;
129        (body.loc, ClassOrObjectMemberValue::Method {
130          function: Node::new(body.loc, Syntax::Function {
131            arrow: false,
132            async_: is_async,
133            generator: is_generator,
134            parameters,
135            body,
136          }),
137        })
138      } else if is_getter {
139        let mut loc = self.require(TokenType::ParenthesisOpen)?.loc;
140        self.require(TokenType::ParenthesisClose)?;
141        let body = self.parse_function_body(ctx)?;
142        loc += body.loc;
143        (loc, ClassOrObjectMemberValue::Getter {
144          function: Node::new(loc, Syntax::Function {
145            arrow: false,
146            async_: false,
147            body,
148            generator: false,
149            parameters: Vec::new(),
150          }),
151        })
152      } else if is_setter {
153        let mut loc = self.require(TokenType::ParenthesisOpen)?.loc;
154        let param = self.parse_pattern(ctx)?;
155        self.require(TokenType::ParenthesisClose)?;
156        let body = self.parse_function_body(ctx)?;
157        loc += body.loc;
158        (loc, ClassOrObjectMemberValue::Setter {
159          function: Node::new(loc, Syntax::Function {
160            arrow: false,
161            async_: false,
162            generator: false,
163            body,
164            parameters: vec![Node::new(param.loc, Syntax::ParamDecl {
165              rest: false,
166              pattern: param,
167              default_value: None,
168            })],
169          }),
170        })
171      } else if match key {
172        ClassOrObjectMemberKey::Direct(_) => match self.peek()? {
173          // Given `class A {1}`, `"1" in new A`.
174          t if t.typ == TokenType::BraceClose => true,
175          // Given `class A {1;}`, `"1" in new A`.
176          t if t.typ == statement_delimiter => true,
177          // Given `class A {1\n2}`, `"2" in new A`.
178          t if property_initialiser_asi.can_end_with_asi && t.preceded_by_line_terminator => true,
179          _ => false,
180        },
181        _ => false,
182      } {
183        (key_loc, ClassOrObjectMemberValue::Property {
184          initializer: None,
185        })
186      } else {
187        let loc_start = self.require(value_delimiter)?.loc;
188        let value = self.parse_expr_until_either_with_asi(
189          ctx,
190          statement_delimiter,
191          TokenType::BraceClose,
192          property_initialiser_asi,
193        )?;
194        (loc_start + value.loc, ClassOrObjectMemberValue::Property {
195          initializer: Some(value),
196        })
197      };
198    Ok(ParseClassOrObjectMemberResult {
199      key,
200      key_loc,
201      value,
202      value_loc,
203    })
204  }
205}