parse_js/parse/
decl.rs

1use super::class_or_object::ParseClassBodyResult;
2use super::expr::Asi;
3use super::pattern::is_valid_pattern_identifier;
4use super::pattern::ParsePatternRules;
5use super::ParseCtx;
6use super::Parser;
7use crate::ast::Node;
8use crate::ast::Syntax;
9use crate::ast::VarDeclMode;
10use crate::ast::VariableDeclarator;
11use crate::error::SyntaxErrorType;
12use crate::error::SyntaxResult;
13use crate::token::TokenType;
14
15#[derive(Clone, Copy, PartialEq, Eq)]
16pub enum VarDeclParseMode {
17  // Standard parsing mode for var/let/const statement.
18  Asi,
19  // Parse as many valid declarators as possible, then break before the first invalid token (i.e. not a comma). Used by for-loop parser.
20  Leftmost,
21}
22
23impl<'a> Parser<'a> {
24  pub fn parse_decl_var(
25    &mut self,
26    ctx: ParseCtx,
27    parse_mode: VarDeclParseMode,
28    export: bool,
29  ) -> SyntaxResult<Node> {
30    let t = self.next()?;
31    let mode = match t.typ {
32      TokenType::KeywordLet => VarDeclMode::Let,
33      TokenType::KeywordConst => VarDeclMode::Const,
34      TokenType::KeywordVar => VarDeclMode::Var,
35      _ => return Err(t.error(SyntaxErrorType::ExpectedSyntax("variable declaration"))),
36    };
37    let mut declarators = Vec::new();
38    let mut loc = t.loc;
39    loop {
40      let pattern = self.parse_pattern(ctx)?;
41      loc.extend(pattern.loc);
42      let mut asi = match parse_mode {
43        VarDeclParseMode::Asi => Asi::can(),
44        VarDeclParseMode::Leftmost => Asi::no(),
45      };
46      let initializer = if self.consume_if(TokenType::Equals)?.is_match() {
47        let expr = self.parse_expr_until_either_with_asi(
48          ctx,
49          TokenType::Semicolon,
50          TokenType::Comma,
51          &mut asi,
52        )?;
53        loc.extend(expr.loc);
54        Some(expr)
55      } else {
56        None
57      };
58      declarators.push(VariableDeclarator {
59        pattern,
60        initializer,
61      });
62      match parse_mode {
63        VarDeclParseMode::Asi => {
64          if self.consume_if(TokenType::Semicolon)?.is_match() || asi.did_end_with_asi {
65            break;
66          }
67          let t = self.peek()?;
68          if t.preceded_by_line_terminator && t.typ != TokenType::Comma {
69            break;
70          };
71          self.require(TokenType::Comma)?;
72        }
73        VarDeclParseMode::Leftmost => {
74          if !self.consume_if(TokenType::Comma)?.is_match() {
75            break;
76          }
77        }
78      }
79    }
80    Ok(Node::new(loc, Syntax::VarDecl {
81      export,
82      mode,
83      declarators,
84    }))
85  }
86
87  pub fn parse_decl_function(
88    &mut self,
89    ctx: ParseCtx,
90    export: bool,
91    export_default: bool,
92  ) -> SyntaxResult<Node> {
93    let is_async = self.consume_if(TokenType::KeywordAsync)?.is_match();
94    let start = self.require(TokenType::KeywordFunction)?.loc;
95    let generator = self.consume_if(TokenType::Asterisk)?.is_match();
96    // The name can only be omitted in default exports.
97    let name = match self
98      .consume_if_pred(|t| is_valid_pattern_identifier(t.typ, ctx.rules))?
99      .match_loc()
100    {
101      Some(name) => Some(Node::new(name, Syntax::ClassOrFunctionName {
102        name: self.string(name),
103      })),
104      _ => {
105        if !export_default {
106          return Err(start.error(SyntaxErrorType::ExpectedSyntax("function name"), None));
107        };
108        None
109      }
110    };
111    let parameters = self.parse_function_parameters(ctx)?;
112    let body = self.parse_function_body(ctx.with_rules(ParsePatternRules {
113      await_allowed: !is_async && ctx.rules.await_allowed,
114      yield_allowed: !generator && ctx.rules.yield_allowed,
115    }))?;
116    Ok(Node::new(start + body.loc, Syntax::FunctionDecl {
117      export,
118      export_default,
119      name,
120      function: Node::new(start + body.loc, Syntax::Function {
121        arrow: false,
122        async_: is_async,
123        generator,
124        parameters,
125        body,
126      }),
127    }))
128  }
129
130  pub fn parse_decl_class(
131    &mut self,
132    ctx: ParseCtx,
133    export: bool,
134    export_default: bool,
135  ) -> SyntaxResult<Node> {
136    let start = self.require(TokenType::KeywordClass)?.loc;
137    // Names can be omitted only in default exports.
138    let name = match self
139      .consume_if_pred(|t| is_valid_pattern_identifier(t.typ, ctx.rules))?
140      .match_loc()
141    {
142      Some(name) => {
143        let name_node = Node::new(name, Syntax::ClassOrFunctionName {
144          name: self.string(name),
145        });
146        Some(name_node)
147      }
148      None => {
149        if !export_default {
150          return Err(start.error(SyntaxErrorType::ExpectedSyntax("class name"), None));
151        };
152        None
153      }
154    };
155    // Unlike functions, classes are scoped to their block.
156    let extends = if self.consume_if(TokenType::KeywordExtends)?.is_match() {
157      Some(self.parse_expr(ctx, TokenType::BraceOpen)?)
158    } else {
159      None
160    };
161    let ParseClassBodyResult { end, members } = self.parse_class_body(ctx)?;
162    Ok(Node::new(start + end, Syntax::ClassDecl {
163      export,
164      export_default,
165      name,
166      extends,
167      members,
168    }))
169  }
170}