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, Symbol, Token, TokenType};
8
9use crate::{
10    force_parse_bracketed, parse_bracketed,
11    types::{
12        Block, GetRange, GetRangeError, GlobalFunction, GlobalFunctionName, LocalFunction,
13        Parameter, Parse, ParseWithArgs, Pointer, Range, TableAccessKey, TryParse,
14        TryParseWithArgs, TypeValue,
15    },
16    utils::{get_token_type_display, get_token_type_display_extended},
17};
18
19impl Parse for LocalFunction {
20    fn parse(
21        local_keyword: Token,
22        lexer: &mut Lexer,
23        errors: &mut Vec<ParseError>,
24    ) -> Option<Self> {
25        if local_keyword != TokenType::Keyword(Keyword::Local) {
26            return None;
27        }
28
29        parse_function!(
30            lexer.next_token(),
31            lexer,
32            errors,
33            let function_name = {
34                next_token_recoverable!(
35                    lexer,
36                    name,
37                    TokenType::Identifier(_) | TokenType::PartialKeyword(_),
38                    TokenType::Identifier("*error*".into(),),
39                    errors,
40                    "Expected ".to_string()
41                        + get_token_type_display(&TokenType::Identifier("".into(),))
42                );
43
44                name
45            },
46            { local_keyword, function_name }
47        )
48    }
49}
50impl TryParse for LocalFunction {}
51
52impl Parse for GlobalFunctionName {
53    fn parse(name: Token, lexer: &mut Lexer, errors: &mut Vec<ParseError>) -> Option<Self> {
54        if !matches!(
55            name.token_type,
56            TokenType::Identifier(_) | TokenType::PartialKeyword(_)
57        ) {
58            return None;
59        }
60
61        maybe_next_token!(
62            lexer,
63            dot_or_colon,
64            TokenType::Symbol(Symbol::Dot) | TokenType::Symbol(Symbol::Colon)
65        );
66        if let Some(dot_or_colon) = dot_or_colon {
67            let is_dot = dot_or_colon == TokenType::Symbol(Symbol::Dot);
68
69            let keys = if is_dot {
70                Vec::<TableAccessKey>::parse_with(dot_or_colon.clone(), lexer, errors, false)
71                    .unwrap_or_default()
72            } else {
73                Vec::new()
74            };
75
76            let method = if !is_dot {
77                next_token_recoverable!(
78                    lexer,
79                    parsed_method,
80                    TokenType::Identifier(_),
81                    TokenType::Identifier("*error*".into()),
82                    errors,
83                    "Expected ".to_string()
84                        + get_token_type_display(&TokenType::Identifier("".into()),)
85                );
86
87                Some(Pointer::new((dot_or_colon, parsed_method)))
88            } else {
89                None
90            };
91
92            return Some(Self::Table {
93                table: name,
94                keys,
95                method,
96            });
97        }
98
99        Some(Self::SimpleName(name))
100    }
101}
102impl TryParse for GlobalFunctionName {}
103
104impl Parse for GlobalFunction {
105    fn parse(
106        function_keyword: Token,
107        lexer: &mut Lexer,
108        errors: &mut Vec<ParseError>,
109    ) -> Option<Self> {
110        parse_function!(
111            function_keyword,
112            lexer,
113            errors,
114            let function_name = {
115                GlobalFunctionName::try_parse(lexer, errors).unwrap_or_else(|| {
116                    GlobalFunctionName::SimpleName(Token::empty(TokenType::Identifier(
117                        "*error*".into(),
118                    )))
119                })
120            },
121            { function_name }
122        )
123    }
124}
125impl TryParse for GlobalFunction {}
126
127impl Parse for Parameter {
128    fn parse(name: Token, lexer: &mut Lexer, errors: &mut Vec<ParseError>) -> Option<Self> {
129        if !matches!(
130            name.token_type,
131            TokenType::Identifier(_)
132                | TokenType::PartialKeyword(_)
133                | TokenType::Symbol(Symbol::Ellipses)
134        ) {
135            return None;
136        }
137
138        maybe_next_token!(lexer, colon, TokenType::Symbol(Symbol::Colon));
139
140        let r#type = if colon.is_some() {
141            Pointer::<TypeValue>::try_parse(lexer, errors)
142        } else {
143            None
144        };
145
146        Some(Self {
147            name,
148            colon,
149            r#type,
150        })
151    }
152}
153
154impl GetRange for GlobalFunctionName {
155    fn get_range(&self) -> Result<Range, GetRangeError> {
156        match self {
157            GlobalFunctionName::SimpleName(token) => token.get_range(),
158            GlobalFunctionName::Table {
159                table,
160                keys,
161                method,
162            } => {
163                let table_range = table.get_range();
164                let last_range = match method {
165                    Some(method) => method.1.get_range(),
166                    None => keys.get_range(),
167                };
168
169                if let Ok(last_range) = last_range {
170                    Ok(Range::new(table_range?.start, last_range.end))
171                } else {
172                    table_range
173                }
174            }
175        }
176    }
177}