luau_parser/impl/block/
function.rs

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