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::{Error, Keyword, Lexer, 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<Error>) -> 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<Error>) -> 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<Error>) -> 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<Error>) -> 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<Error>) -> 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            Self::SimpleName(token) => token.get_range(),
215            Self::Table {
216                table,
217                keys,
218                method,
219            } => {
220                let table_range = table.get_range();
221                let last_range = method
222                    .as_ref()
223                    .map_or_else(|| keys.get_range(), |method| method.1.get_range());
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(mut type_keyword: Token, lexer: &mut Lexer, errors: &mut Vec<Error>) -> Option<Self> {
237        let state = lexer.save_state();
238
239        let export_keyword = if type_keyword == TokenType::PartialKeyword(PartialKeyword::Export) {
240            let temp = type_keyword;
241            type_keyword = lexer.next_token();
242
243            Some(temp)
244        } else {
245            None
246        };
247
248        let function_keyword = lexer.next_token();
249
250        if type_keyword != TokenType::PartialKeyword(PartialKeyword::Type)
251            || function_keyword != TokenType::Keyword(Keyword::Function)
252        {
253            lexer.set_state(state);
254
255            return None;
256        }
257
258        parse_function!(
259            function_keyword,
260            lexer,
261            errors,
262            let function_name = {
263                next_token_recoverable!(
264                    lexer,
265                    name,
266                    TokenType::Identifier(_) | TokenType::PartialKeyword(_),
267                    TokenType::Identifier("*error*".into(),),
268                    errors,
269                    "Expected ".to_string()
270                        + get_token_type_display(&TokenType::Identifier("".into(),))
271                );
272
273                name
274            },
275            { export_keyword, type_keyword, function_name }
276        )
277    }
278}
279impl TryParse for TypeFunction {}