luau_parser/impl/block/
function.rs

1//! All `impl` blocks for:
2//!
3//! * [`LocalFunction`]
4//! * [`GlobalFunction`]
5//! * [`GlobalFunctionName`]
6
7use luau_lexer::prelude::{Keyword, Lexer, ParseError, PartialKeyword, Symbol, Token, TokenType};
8
9use crate::{
10    force_parse_bracketed, parse_bracketed,
11    types::{
12        Attribute, Block, GetRange, GetRangeError, GlobalFunction, GlobalFunctionName,
13        LocalFunction, Parameter, Parse, ParseWithArgs, Pointer, Range, TableAccessKey, TryParse,
14        TryParseWithArgs, TypeFunction, TypeValue,
15    },
16    utils::{get_token_type_display, get_token_type_display_extended},
17};
18
19impl Parse for LocalFunction {
20    fn parse(token: Token, lexer: &mut Lexer, errors: &mut Vec<ParseError>) -> Option<Self> {
21        let state = lexer.save_state();
22        let attributes;
23        let local_keyword;
24
25        match token.token_type {
26            TokenType::Keyword(Keyword::Local) => {
27                attributes = Vec::new();
28                local_keyword = token;
29            }
30            TokenType::Symbol(Symbol::At) => {
31                attributes = safe_unwrap!(
32                    lexer,
33                    errors,
34                    "Expected <attribute>",
35                    Vec::parse(token, lexer, errors)
36                );
37                local_keyword = lexer.next_token();
38            }
39            _ => return None,
40        }
41        if local_keyword != TokenType::Keyword(Keyword::Local) {
42            lexer.set_state(state);
43
44            return None;
45        }
46
47        parse_function!(
48            let attributes = attributes;
49            lexer.next_token(),
50            lexer,
51            errors,
52            let function_name = {
53                next_token_recoverable!(
54                    lexer,
55                    name,
56                    TokenType::Identifier(_) | TokenType::PartialKeyword(_),
57                    TokenType::Identifier("*error*".into(),),
58                    errors,
59                    "Expected ".to_string()
60                        + get_token_type_display(&TokenType::Identifier("".into(),))
61                );
62
63                name
64            },
65            { attributes, local_keyword, function_name }
66        )
67    }
68}
69impl TryParse for LocalFunction {}
70
71impl Parse for GlobalFunctionName {
72    fn parse(name: Token, lexer: &mut Lexer, errors: &mut Vec<ParseError>) -> Option<Self> {
73        if !matches!(
74            name.token_type,
75            TokenType::Identifier(_) | TokenType::PartialKeyword(_)
76        ) {
77            return None;
78        }
79
80        maybe_next_token!(
81            lexer,
82            dot_or_colon,
83            TokenType::Symbol(Symbol::Dot) | TokenType::Symbol(Symbol::Colon)
84        );
85        if let Some(dot_or_colon) = dot_or_colon {
86            let is_dot = dot_or_colon == TokenType::Symbol(Symbol::Dot);
87
88            let keys = if is_dot {
89                Vec::<TableAccessKey>::parse_with(dot_or_colon.clone(), lexer, errors, false)
90                    .unwrap_or_default()
91            } else {
92                Vec::new()
93            };
94
95            let method = if !is_dot {
96                next_token_recoverable!(
97                    lexer,
98                    parsed_method,
99                    TokenType::Identifier(_),
100                    TokenType::Identifier("*error*".into()),
101                    errors,
102                    "Expected ".to_string()
103                        + get_token_type_display(&TokenType::Identifier("".into()),)
104                );
105
106                Some(Pointer::new((dot_or_colon, parsed_method)))
107            } else {
108                None
109            };
110
111            return Some(Self::Table {
112                table: name,
113                keys,
114                method,
115            });
116        }
117
118        Some(Self::SimpleName(name))
119    }
120}
121impl TryParse for GlobalFunctionName {}
122
123impl Parse for GlobalFunction {
124    fn parse(token: Token, lexer: &mut Lexer, errors: &mut Vec<ParseError>) -> Option<Self> {
125        let attributes;
126        let function_keyword;
127
128        match token.token_type {
129            TokenType::Keyword(Keyword::Function) => {
130                attributes = Vec::new();
131                function_keyword = token;
132            }
133            TokenType::Symbol(Symbol::At) => {
134                attributes = safe_unwrap!(
135                    lexer,
136                    errors,
137                    "Expected <attribute>",
138                    Vec::parse(token, lexer, errors)
139                );
140                function_keyword = lexer.next_token();
141            }
142            _ => return None,
143        }
144
145        parse_function!(
146            let attributes = attributes;
147            function_keyword,
148            lexer,
149            errors,
150            let function_name = {
151                GlobalFunctionName::try_parse(lexer, errors).unwrap_or_else(|| {
152                    GlobalFunctionName::SimpleName(Token::empty(TokenType::Identifier(
153                        "*error*".into(),
154                    )))
155                })
156            },
157            { attributes, function_name }
158        )
159    }
160}
161impl TryParse for GlobalFunction {}
162
163impl Parse for Parameter {
164    fn parse(name: Token, lexer: &mut Lexer, errors: &mut Vec<ParseError>) -> Option<Self> {
165        if !matches!(
166            name.token_type,
167            TokenType::Identifier(_)
168                | TokenType::PartialKeyword(_)
169                | TokenType::Symbol(Symbol::Ellipses)
170        ) {
171            return None;
172        }
173
174        maybe_next_token!(lexer, colon, TokenType::Symbol(Symbol::Colon));
175
176        let r#type = if colon.is_some() {
177            Pointer::<TypeValue>::try_parse(lexer, errors)
178        } else {
179            None
180        };
181
182        Some(Self {
183            name,
184            colon,
185            r#type,
186        })
187    }
188}
189
190impl Parse for Attribute {
191    fn parse(at: Token, lexer: &mut Lexer, errors: &mut Vec<ParseError>) -> Option<Self> {
192        if at != TokenType::Symbol(Symbol::At) {
193            return None;
194        }
195
196        next_token_recoverable!(
197            lexer,
198            attribute,
199            TokenType::Identifier(_) | TokenType::PartialKeyword(_),
200            TokenType::Identifier("*error*".into()),
201            errors,
202            "Expected ".to_string() + get_token_type_display(&TokenType::Identifier("".into()))
203        );
204
205        Some(Self { at, attribute })
206    }
207}
208impl TryParse for Attribute {}
209
210impl GetRange for GlobalFunctionName {
211    fn get_range(&self) -> Result<Range, GetRangeError> {
212        match self {
213            GlobalFunctionName::SimpleName(token) => token.get_range(),
214            GlobalFunctionName::Table {
215                table,
216                keys,
217                method,
218            } => {
219                let table_range = table.get_range();
220                let last_range = match method {
221                    Some(method) => method.1.get_range(),
222                    None => keys.get_range(),
223                };
224
225                if let Ok(last_range) = last_range {
226                    Ok(Range::new(table_range?.start, last_range.end))
227                } else {
228                    table_range
229                }
230            }
231        }
232    }
233}
234
235impl Parse for TypeFunction {
236    fn parse(
237        mut type_keyword: Token,
238        lexer: &mut Lexer,
239        errors: &mut Vec<ParseError>,
240    ) -> Option<Self> {
241        let state = lexer.save_state();
242
243        let export_keyword = if type_keyword == TokenType::PartialKeyword(PartialKeyword::Export) {
244            let temp = type_keyword;
245            type_keyword = lexer.next_token();
246
247            Some(temp)
248        } else {
249            None
250        };
251
252        let function_keyword = lexer.next_token();
253
254        if type_keyword != TokenType::PartialKeyword(PartialKeyword::Type)
255            || function_keyword != TokenType::Keyword(Keyword::Function)
256        {
257            lexer.set_state(state);
258
259            return None;
260        }
261
262        parse_function!(
263            function_keyword,
264            lexer,
265            errors,
266            let function_name = {
267                next_token_recoverable!(
268                    lexer,
269                    name,
270                    TokenType::Identifier(_) | TokenType::PartialKeyword(_),
271                    TokenType::Identifier("*error*".into(),),
272                    errors,
273                    "Expected ".to_string()
274                        + get_token_type_display(&TokenType::Identifier("".into(),))
275                );
276
277                name
278            },
279            { export_keyword, type_keyword, function_name }
280        )
281    }
282}
283impl TryParse for TypeFunction {}