luau_parser/impl/block/
function.rs1use 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}