1use 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 {}