Skip to main content

oxc_parser/parser_parse/
slot_parameters.rs

1//! Direct, original-source template parameter goals. No wrapper or retry.
2
3use std::any::Any;
4
5use oxc_ast::ast::FormalParameters;
6use oxc_diagnostics::Diagnostics;
7
8use crate::{
9    Parser, ParserConfig, ParserDiagnostic, ParserImpl, UniquePromise,
10    config::{NoTokensParserConfig, RuntimeParserConfig, TokensParserConfig},
11    diagnostics,
12    lexer::Kind,
13};
14
15impl<'a, C: ParserConfig> Parser<'a, C> {
16    /// Parse the entire original source as an arrow-function parameter list,
17    /// retaining original spans, binding defaults, rest and TS annotations.
18    /// This goal has an EOF delimiter; it adds no synthetic source or AST.
19    pub fn parse_slot_parameters(self) -> Result<FormalParameters<'a>, Diagnostics> {
20        self.parse_template_parameters(false)
21    }
22
23    /// Parse a Vue v-for alias list from its original source, without the
24    /// enclosing tuple parentheses or `in`/`of` iterable. Unlike a slot's
25    /// parameter list, this goal permits omitted alias positions. Elisions
26    /// contribute no items; every retained binding keeps its authored span.
27    /// Rest-last and trailing-comma restrictions remain in force.
28    pub fn parse_v_for_parameters(self) -> Result<FormalParameters<'a>, Diagnostics> {
29        self.parse_template_parameters(true)
30    }
31
32    fn parse_template_parameters(
33        self,
34        allow_elisions: bool,
35    ) -> Result<FormalParameters<'a>, Diagnostics> {
36        let config: &dyn Any = &self.config;
37        if config.is::<NoTokensParserConfig>() {
38            parse_no_tokens(
39                self.allocator,
40                self.source_text,
41                self.source_type,
42                self.options,
43                allow_elisions,
44            )
45        } else if config.is::<TokensParserConfig>() {
46            parse_tokens(
47                self.allocator,
48                self.source_text,
49                self.source_type,
50                self.options,
51                allow_elisions,
52            )
53        } else if let Some(&config) = config.downcast_ref::<RuntimeParserConfig>() {
54            parse_runtime(
55                self.allocator,
56                self.source_text,
57                self.source_type,
58                self.options,
59                config,
60                allow_elisions,
61            )
62        } else {
63            ParserImpl::<C>::new(
64                self.allocator,
65                self.source_text,
66                self.source_type,
67                self.options,
68                self.config,
69                UniquePromise::new(),
70            )
71            .parse_template_parameters(allow_elisions)
72        }
73    }
74}
75
76// Stock goals remain provider-instantiated, as the ordinary expression entry.
77macro_rules! stock_goal {
78    ($name:ident, $config:ident) => {
79        #[inline(never)]
80        fn $name<'a>(
81            allocator: &'a oxc_allocator::Allocator,
82            source: &'a str,
83            source_type: oxc_span::SourceType,
84            options: crate::ParseOptions,
85            allow_elisions: bool,
86        ) -> Result<FormalParameters<'a>, Diagnostics> {
87            ParserImpl::<$config>::new(
88                allocator,
89                source,
90                source_type,
91                options,
92                $config,
93                UniquePromise::new(),
94            )
95            .parse_template_parameters(allow_elisions)
96        }
97    };
98}
99stock_goal!(parse_no_tokens, NoTokensParserConfig);
100stock_goal!(parse_tokens, TokensParserConfig);
101
102#[inline(never)]
103fn parse_runtime<'a>(
104    allocator: &'a oxc_allocator::Allocator,
105    source: &'a str,
106    source_type: oxc_span::SourceType,
107    options: crate::ParseOptions,
108    config: RuntimeParserConfig,
109    allow_elisions: bool,
110) -> Result<FormalParameters<'a>, Diagnostics> {
111    ParserImpl::<RuntimeParserConfig>::new(
112        allocator,
113        source,
114        source_type,
115        options,
116        config,
117        UniquePromise::new(),
118    )
119    .parse_template_parameters(allow_elisions)
120}
121
122impl<'a, C: ParserConfig> ParserImpl<'a, C> {
123    fn parse_template_parameters(
124        mut self,
125        allow_elisions: bool,
126    ) -> Result<FormalParameters<'a>, Diagnostics> {
127        self.bump_any();
128        let parameters = self.parse_template_parameter_items(allow_elisions);
129        if self.fatal_error.is_none() && !self.at(Kind::Eof) {
130            self.error(diagnostics::unexpected_token(self.cur_token().span()));
131        }
132        if let Some(fatal) = self.fatal_error.take() {
133            return Err(fatal.error.into_diagnostic().into());
134        }
135        self.check_unfinished_errors();
136        let errors = self
137            .lexer
138            .errors
139            .into_iter()
140            .chain(self.errors)
141            .map(ParserDiagnostic::into_diagnostic)
142            .collect::<Diagnostics>();
143        if errors.is_empty() { Ok(parameters) } else { Err(errors) }
144    }
145}
146
147#[cfg(test)]
148mod tests;