1use std::{fmt, str::FromStr};
2
3use full_moon::{
4 ast,
5 node::Node,
6 tokenizer::{self, InterpolatedStringKind, Symbol, TokenType},
7};
8
9use crate::nodes::*;
10
11#[derive(Debug, Default)]
12pub(crate) struct AstConverter<'a> {
13 hold_token_data: bool,
14 work_stack: Vec<ConvertWork<'a>>,
15 blocks: Vec<Block>,
16 statements: Vec<Statement>,
17 last_statements: Vec<LastStatement>,
18 expressions: Vec<Expression>,
19 prefixes: Vec<Prefix>,
20 arguments: Vec<Arguments>,
21 variables: Vec<Variable>,
22 types: Vec<Type>,
23 function_return_types: Vec<FunctionReturnType>,
24 variadic_type_packs: Vec<VariadicTypePack>,
25 generic_type_packs: Vec<GenericTypePack>,
26 type_parameters: Vec<TypeParameters>,
27 type_packs: Vec<TypePack>,
28}
29
30impl<'a> AstConverter<'a> {
31 pub(crate) fn new(hold_token_data: bool) -> Self {
32 Self {
33 hold_token_data,
34 ..Default::default()
35 }
36 }
37
38 #[inline]
39 fn push_work(&mut self, work: impl Into<ConvertWork<'a>>) {
40 self.work_stack.push(work.into());
41 }
42
43 #[inline]
44 fn pop_block(&mut self) -> Result<Block, ConvertError> {
45 self.blocks
46 .pop()
47 .ok_or(ConvertError::InternalStack { kind: "Block" })
48 }
49
50 #[inline]
51 fn pop_statement(&mut self) -> Result<Statement, ConvertError> {
52 self.statements
53 .pop()
54 .ok_or(ConvertError::InternalStack { kind: "Statement" })
55 }
56
57 #[inline]
58 fn pop_statements(&mut self, n: usize) -> Result<Vec<Statement>, ConvertError> {
59 std::iter::repeat_with(|| self.pop_statement())
60 .take(n)
61 .collect()
62 }
63
64 #[inline]
65 fn pop_last_statement(&mut self) -> Result<LastStatement, ConvertError> {
66 self.last_statements
67 .pop()
68 .ok_or(ConvertError::InternalStack {
69 kind: "LastStatement",
70 })
71 }
72
73 #[inline]
74 fn pop_expression(&mut self) -> Result<Expression, ConvertError> {
75 self.expressions
76 .pop()
77 .ok_or(ConvertError::InternalStack { kind: "Expression" })
78 }
79
80 #[inline]
81 fn pop_expressions(&mut self, n: usize) -> Result<Vec<Expression>, ConvertError> {
82 std::iter::repeat_with(|| self.pop_expression())
83 .take(n)
84 .collect()
85 }
86
87 #[inline]
88 fn pop_prefix(&mut self) -> Result<Prefix, ConvertError> {
89 self.prefixes
90 .pop()
91 .ok_or(ConvertError::InternalStack { kind: "Prefix" })
92 }
93
94 #[inline]
95 fn pop_variable(&mut self) -> Result<Variable, ConvertError> {
96 self.variables
97 .pop()
98 .ok_or(ConvertError::InternalStack { kind: "Variable" })
99 }
100
101 #[inline]
102 fn pop_variables(&mut self, n: usize) -> Result<Vec<Variable>, ConvertError> {
103 std::iter::repeat_with(|| self.pop_variable())
104 .take(n)
105 .collect()
106 }
107
108 #[inline]
109 fn pop_arguments(&mut self) -> Result<Arguments, ConvertError> {
110 self.arguments
111 .pop()
112 .ok_or(ConvertError::InternalStack { kind: "Arguments" })
113 }
114
115 #[inline]
116 fn pop_type(&mut self) -> Result<Type, ConvertError> {
117 self.types
118 .pop()
119 .ok_or(ConvertError::InternalStack { kind: "Type" })
120 }
121
122 #[inline]
123 fn pop_types(&mut self, n: usize) -> Result<Vec<Type>, ConvertError> {
124 std::iter::repeat_with(|| self.pop_type()).take(n).collect()
125 }
126
127 #[inline]
128 fn pop_variadic_type_pack(&mut self) -> Result<VariadicTypePack, ConvertError> {
129 self.variadic_type_packs
130 .pop()
131 .ok_or(ConvertError::InternalStack {
132 kind: "VariadicTypePack",
133 })
134 }
135
136 #[inline]
137 fn pop_generic_type_pack(&mut self) -> Result<GenericTypePack, ConvertError> {
138 self.generic_type_packs
139 .pop()
140 .ok_or(ConvertError::InternalStack {
141 kind: "GenericTypePack",
142 })
143 }
144
145 #[inline]
146 fn pop_function_return_type(&mut self) -> Result<FunctionReturnType, ConvertError> {
147 self.function_return_types
148 .pop()
149 .ok_or(ConvertError::InternalStack {
150 kind: "FunctionReturnType",
151 })
152 }
153
154 #[inline]
155 fn pop_type_parameters(&mut self) -> Result<TypeParameters, ConvertError> {
156 self.type_parameters
157 .pop()
158 .ok_or(ConvertError::InternalStack {
159 kind: "TypeParameters",
160 })
161 }
162
163 #[inline]
164 fn pop_type_pack(&mut self) -> Result<TypePack, ConvertError> {
165 self.type_packs
166 .pop()
167 .ok_or(ConvertError::InternalStack { kind: "TypePack" })
168 }
169
170 pub(crate) fn convert(&mut self, ast: &'a ast::Ast) -> Result<Block, ConvertError> {
171 self.push_work(ast.nodes());
172
173 while let Some(work) = self.work_stack.pop() {
174 match work {
175 ConvertWork::PushVariable(variable) => {
176 self.variables.push(variable);
177 }
178 ConvertWork::PushExpression(expression) => {
179 self.expressions.push(expression);
180 }
181 ConvertWork::PushType(r#type) => {
182 self.types.push(r#type);
183 }
184 ConvertWork::Block(block) => {
185 self.work_stack.push(ConvertWork::MakeBlock { block });
186 for stmt in block.stmts() {
187 self.push_work(stmt);
188 }
189 if let Some(last) = block.last_stmt() {
190 self.push_work(last);
191 }
192 }
193 ConvertWork::Statement(statement) => self.convert_statement(statement)?,
194 ConvertWork::LastStatement(last_statement) => match last_statement {
195 ast::LastStmt::Break(token) => {
196 self.last_statements.push(if self.hold_token_data {
197 LastStatement::Break(Some(self.convert_token(token)?))
198 } else {
199 LastStatement::new_break()
200 });
201 }
202 ast::LastStmt::Continue(token) => {
203 self.last_statements.push(if self.hold_token_data {
204 LastStatement::Continue(Some(self.convert_token(token)?))
205 } else {
206 LastStatement::new_continue()
207 });
208 }
209 ast::LastStmt::Return(return_statement) => {
210 self.work_stack.push(ConvertWork::MakeReturn {
211 statement: return_statement,
212 });
213 for expression in return_statement.returns().iter() {
214 self.push_work(expression);
215 }
216 }
217 _ => {
218 return Err(ConvertError::LastStatement {
219 statement: last_statement.to_string(),
220 })
221 }
222 },
223 ConvertWork::Expression(expression) => self.convert_expression(expression)?,
224 ConvertWork::Prefix(prefix) => match prefix {
225 ast::Prefix::Expression(expression) => {
226 self.work_stack
227 .push(ConvertWork::MakePrefixFromExpression { prefix });
228 self.push_work(expression.as_ref());
229 }
230 ast::Prefix::Name(name) => {
231 self.prefixes
232 .push(self.convert_token_to_identifier(name)?.into());
233 }
234 _ => {
235 return Err(ConvertError::Prefix {
236 prefix: prefix.to_string(),
237 })
238 }
239 },
240 ConvertWork::Arguments(arguments) => match arguments {
241 ast::FunctionArgs::Parentheses {
242 parentheses,
243 arguments,
244 } => {
245 self.work_stack
246 .push(ConvertWork::MakeArgumentsFromExpressions {
247 parentheses,
248 arguments,
249 });
250 for value in arguments.iter() {
251 self.push_work(value);
252 }
253 }
254 ast::FunctionArgs::String(string) => {
255 self.arguments
256 .push(self.convert_string_expression(string)?.into());
257 }
258 ast::FunctionArgs::TableConstructor(table) => {
259 self.work_stack
260 .push(ConvertWork::MakeArgumentsFromTableEntries { table });
261
262 self.convert_table(table)?;
263 }
264 _ => {
265 return Err(ConvertError::FunctionArguments {
266 arguments: arguments.to_string(),
267 })
268 }
269 },
270 ConvertWork::TypeInfo(type_info) => self.convert_type_info(type_info)?,
271 ConvertWork::MakeBlock { block } => {
272 let mut new_block = Block::new(
273 self.pop_statements(block.stmts().count())?,
274 block
275 .last_stmt()
276 .map(|_| self.pop_last_statement())
277 .transpose()?,
278 );
279
280 if self.hold_token_data {
281 let semicolons = block
282 .stmts_with_semicolon()
283 .map(|(_, token)| {
284 token
285 .as_ref()
286 .map(|token| self.convert_token(token))
287 .transpose()
288 })
289 .collect::<Result<Vec<_>, _>>()?;
290 let last_semicolon =
291 block.last_stmt_with_semicolon().and_then(|(_, semicolon)| {
292 semicolon.as_ref().map(|token| self.convert_token(token))
293 });
294
295 new_block.set_tokens(BlockTokens {
296 semicolons,
297 last_semicolon: last_semicolon.transpose()?,
298 final_token: None,
299 });
300 };
301
302 self.blocks.push(new_block);
303 }
304 ConvertWork::MakeDoStatement { statement } => {
305 let block = self.pop_block()?;
306 let mut do_statement = DoStatement::new(block);
307 if self.hold_token_data {
308 do_statement.set_tokens(DoTokens {
309 r#do: self.convert_token(statement.do_token())?,
310 end: self.convert_token(statement.end_token())?,
311 })
312 }
313 self.statements.push(do_statement.into());
314 }
315 ConvertWork::MakeReturn { statement } => {
316 let mut return_statement =
317 ReturnStatement::new(self.pop_expressions(statement.returns().len())?);
318 if self.hold_token_data {
319 let commas = self.extract_tokens_from_punctuation(statement.returns())?;
320 return_statement.set_tokens(ReturnTokens {
321 r#return: self.convert_token(statement.token())?,
322 commas,
323 });
324 }
325 self.last_statements.push(return_statement.into());
326 }
327 ConvertWork::MakeBinaryExpression { operator } => {
328 let left = self.pop_expression()?;
329 let right = self.pop_expression()?;
330 let mut binary =
331 BinaryExpression::new(self.convert_binop(operator)?, left, right);
332 if self.hold_token_data {
333 binary.set_token(self.convert_token(get_binary_operator_token(operator)?)?);
334 }
335 self.expressions.push(binary.into());
336 }
337 ConvertWork::MakeUnaryExpression { operator } => {
338 let mut unary =
339 UnaryExpression::new(self.convert_unop(operator)?, self.pop_expression()?);
340 if self.hold_token_data {
341 unary.set_token(self.convert_token(get_unary_operator_token(operator)?)?);
342 }
343 self.expressions.push(unary.into());
344 }
345 ConvertWork::MakeParentheseExpression { contained_span } => {
346 let mut parenthese = ParentheseExpression::new(self.pop_expression()?);
347 if self.hold_token_data {
348 let (left_parenthese, right_parenthese) =
349 self.extract_contained_span_tokens(contained_span)?;
350 parenthese.set_tokens(ParentheseTokens {
351 left_parenthese,
352 right_parenthese,
353 });
354 }
355 self.expressions.push(parenthese.into());
356 }
357 ConvertWork::MakeIfExpression { if_expression } => {
358 let condition = self.pop_expression()?;
359 let result = self.pop_expression()?;
360 let else_expression = self.pop_expression()?;
361
362 let mut value = IfExpression::new(condition, result, else_expression);
363
364 if let Some(elseifs) = if_expression.else_if_expressions() {
365 for elseif in elseifs.iter() {
366 let elseif_condition = self.pop_expression()?;
367 let elseif_expression = self.pop_expression()?;
368 let mut branch =
369 ElseIfExpressionBranch::new(elseif_condition, elseif_expression);
370 if self.hold_token_data {
371 branch.set_tokens(ElseIfExpressionBranchTokens {
372 elseif: self.convert_token(elseif.else_if_token())?,
373 then: self.convert_token(elseif.then_token())?,
374 });
375 }
376 value.push_branch(branch);
377 }
378 }
379
380 if self.hold_token_data {
381 value.set_tokens(IfExpressionTokens {
382 r#if: self.convert_token(if_expression.if_token())?,
383 then: self.convert_token(if_expression.then_token())?,
384 r#else: self.convert_token(if_expression.else_token())?,
385 });
386 }
387
388 self.expressions.push(value.into());
389 }
390 ConvertWork::MakeInterpolatedString {
391 interpolated_string,
392 } => {
393 let mut segments = Vec::new();
394 let mut segments_iter = interpolated_string.segments().peekable();
395
396 while let Some(segment) = segments_iter.next() {
397 let literal = &segment.literal;
398 if let Some(segment) = self.convert_string_interpolation_segment(literal)? {
399 segments.push(segment.into());
400 }
401
402 let expression = self.pop_expression()?;
403 let mut value_segment = ValueSegment::new(expression);
404
405 if self.hold_token_data {
406 let literal_end = self.convert_token_end_position(literal)?;
407
408 let mut opening_brace = Token::new_with_line(
409 literal_end.0.saturating_sub(1),
410 literal_end.0,
411 literal_end.1,
412 );
413
414 for trivia_token in literal.trailing_trivia() {
415 opening_brace
416 .push_trailing_trivia(self.convert_trivia(trivia_token)?);
417 }
418
419 let next_literal = segments_iter
420 .peek()
421 .map(|next_segment| &next_segment.literal)
422 .unwrap_or(interpolated_string.last_string());
423
424 let next_literal_position =
425 self.convert_token_position(next_literal)?;
426
427 let closing_brace = Token::new_with_line(
428 next_literal_position.0,
429 next_literal_position.0.saturating_add(1),
430 next_literal_position.2,
431 );
432
433 value_segment.set_tokens(ValueSegmentTokens {
434 opening_brace,
435 closing_brace,
436 });
437 }
438
439 segments.push(value_segment.into());
440 }
441
442 if let Some(segment) = self
443 .convert_string_interpolation_segment(interpolated_string.last_string())?
444 {
445 segments.push(segment.into());
446 }
447
448 let mut value = InterpolatedStringExpression::new(segments);
449
450 if self.hold_token_data {
451 let last = interpolated_string.last_string();
452 let first = interpolated_string
453 .segments()
454 .next()
455 .map(|segment| &segment.literal)
456 .unwrap_or(last);
457
458 let (opening_tick, closing_tick) = match first.token_type() {
459 TokenType::InterpolatedString { literal: _, kind } => match kind {
460 InterpolatedStringKind::Begin | InterpolatedStringKind::Simple => {
461 let first_position = self.convert_token_position(first)?;
462 let mut start_token = Token::new_with_line(
463 first_position.0,
464 first_position.0.saturating_add(1),
465 first_position.2,
466 );
467 let last_position = self.convert_token_end_position(last)?;
468 let mut end_token = Token::new_with_line(
469 last_position.0.saturating_sub(1),
470 last_position.0,
471 last_position.1,
472 );
473
474 for trivia_token in first.leading_trivia() {
475 start_token.push_leading_trivia(
476 self.convert_trivia(trivia_token)?,
477 );
478 }
479
480 for trivia_token in last.trailing_trivia() {
481 end_token.push_trailing_trivia(
482 self.convert_trivia(trivia_token)?,
483 );
484 }
485 (start_token, end_token)
486 }
487 InterpolatedStringKind::Middle | InterpolatedStringKind::End => {
488 return Err(ConvertError::InterpolatedString {
489 string: interpolated_string.to_string(),
490 })
491 }
492 },
493 _ => {
494 return Err(ConvertError::InterpolatedString {
495 string: interpolated_string.to_string(),
496 })
497 }
498 };
499
500 let tokens = InterpolatedStringTokens {
501 opening_tick,
502 closing_tick,
503 };
504 value.set_tokens(tokens);
505 }
506
507 self.expressions.push(value.into());
508 }
509 ConvertWork::MakeFunctionExpression { body, token } => {
510 let builder =
511 self.convert_function_body_attributes(body, self.convert_token(token)?)?;
512
513 self.expressions
514 .push(builder.into_function_expression().into());
515 }
516 ConvertWork::MakeRepeatStatement { statement } => {
517 let mut repeat_statement =
518 RepeatStatement::new(self.pop_block()?, self.pop_expression()?);
519 if self.hold_token_data {
520 repeat_statement.set_tokens(RepeatTokens {
521 repeat: self.convert_token(statement.repeat_token())?,
522 until: self.convert_token(statement.until_token())?,
523 });
524 }
525 self.statements.push(repeat_statement.into());
526 }
527 ConvertWork::MakeWhileStatement { statement } => {
528 let block = self.pop_block()?;
529 let mut while_statement = WhileStatement::new(block, self.pop_expression()?);
530 if self.hold_token_data {
531 while_statement.set_tokens(WhileTokens {
532 r#while: self.convert_token(statement.while_token())?,
533 r#do: self.convert_token(statement.do_token())?,
534 end: self.convert_token(statement.end_token())?,
535 });
536 }
537 self.statements.push(while_statement.into());
538 }
539 ConvertWork::MakeNumericForStatement { statement } => {
540 let typed_identifier = self.convert_typed_identifier(
541 statement.index_variable(),
542 statement.type_specifier(),
543 )?;
544
545 let block = self.pop_block()?;
546 let start = self.pop_expression()?;
547 let end = self.pop_expression()?;
548 let step = statement
549 .step()
550 .map(|_| self.pop_expression())
551 .transpose()?;
552
553 let mut numeric_for =
554 NumericForStatement::new(typed_identifier, start, end, step, block);
555
556 if self.hold_token_data {
557 numeric_for.set_tokens(NumericForTokens {
558 r#for: self.convert_token(statement.for_token())?,
559 equal: self.convert_token(statement.equal_token())?,
560 r#do: self.convert_token(statement.do_token())?,
561 end: self.convert_token(statement.end_token())?,
562 end_comma: self.convert_token(statement.start_end_comma())?,
563 step_comma: statement
564 .end_step_comma()
565 .map(|token| self.convert_token(token))
566 .transpose()?,
567 });
568 }
569 self.statements.push(numeric_for.into());
570 }
571 ConvertWork::MakeGenericForStatement { statement } => {
572 let block = self.pop_block()?;
573 let identifiers = statement
574 .names()
575 .iter()
576 .zip(statement.type_specifiers())
577 .map(|(name, type_specifier)| {
578 self.convert_typed_identifier(name, type_specifier)
579 })
580 .collect::<Result<Vec<_>, _>>()?;
581 let mut generic_for = GenericForStatement::new(
582 identifiers,
583 self.pop_expressions(statement.expressions().len())?,
584 block,
585 );
586 if self.hold_token_data {
587 generic_for.set_tokens(GenericForTokens {
588 r#for: self.convert_token(statement.for_token())?,
589 r#in: self.convert_token(statement.in_token())?,
590 r#do: self.convert_token(statement.do_token())?,
591 end: self.convert_token(statement.end_token())?,
592 identifier_commas: self
593 .extract_tokens_from_punctuation(statement.names())?,
594 value_commas: self
595 .extract_tokens_from_punctuation(statement.expressions())?,
596 });
597 }
598 self.statements.push(generic_for.into());
599 }
600 ConvertWork::MakeFunctionDeclaration { statement } => {
601 let builder = self.convert_function_body_attributes(
602 statement.body(),
603 self.convert_token(statement.function_token())?,
604 )?;
605 let name = self.convert_function_name(statement.name())?;
606
607 self.statements
608 .push(builder.into_function_statement(name).into());
609 }
610 ConvertWork::MakeFunctionCallStatement { call } => {
611 let call = self.make_function_call(call)?;
612 self.statements.push(call.into());
613 }
614 ConvertWork::MakePrefixFromExpression { prefix } => match self.pop_expression()? {
615 Expression::Parenthese(parenthese) => {
616 self.prefixes.push(Prefix::Parenthese(*parenthese));
617 }
618 _ => {
619 return Err(ConvertError::Prefix {
620 prefix: prefix.to_string(),
621 })
622 }
623 },
624 ConvertWork::MakeTypeDeclarationStatement {
625 type_declaration,
626 export_token,
627 } => {
628 let mut declaration = TypeDeclarationStatement::new(
629 self.convert_token_to_identifier(type_declaration.type_name())?,
630 self.pop_type()?,
631 );
632
633 if export_token.is_some() {
634 declaration.set_exported();
635 }
636
637 if let Some(generics) = type_declaration.generics() {
638 let mut type_variables = Vec::new();
639 let mut generic_type_packs = Vec::new();
640 let mut type_variables_with_default = Vec::new();
641 let mut generic_type_packs_with_default = Vec::new();
642
643 for parameter in generics.generics() {
644 match parameter.parameter() {
645 ast::luau::GenericParameterInfo::Name(token) => {
646 let name = self.convert_token_to_identifier(token)?;
647
648 if let Some(default_type) = parameter
649 .default_type()
650 .map(|_| self.pop_type())
651 .transpose()?
652 {
653 type_variables_with_default.push(if self.hold_token_data {
654 let equal_token =
655 parameter.equals().ok_or_else(|| {
656 ConvertError::GenericDeclaration {
657 generics: generics.to_string(),
658 }
659 })?;
660 (
661 name,
662 default_type,
663 Some(self.convert_token(equal_token)?),
664 )
665 } else {
666 (name, default_type, None)
667 });
668 } else {
669 type_variables
670 .push(self.convert_token_to_identifier(token)?);
671 }
672 }
673 ast::luau::GenericParameterInfo::Variadic { name, ellipsis } => {
674 let mut generic_pack = GenericTypePack::new(
675 self.convert_token_to_identifier(name)?,
676 );
677
678 if self.hold_token_data {
679 generic_pack.set_token(self.convert_token(ellipsis)?);
680 }
681
682 use ast::luau::TypeInfo;
683
684 if let Some(default_type) = parameter
685 .default_type()
686 .map(|default_type| {
687 if is_variadic_type(default_type).is_some() {
688 self.pop_variadic_type_pack()
689 .map(GenericTypePackDefault::from)
690 } else {
691 match default_type {
692 TypeInfo::GenericPack { .. } => self
693 .pop_generic_type_pack()
694 .map(GenericTypePackDefault::from),
695 TypeInfo::VariadicPack { .. } => self
696 .pop_variadic_type_pack()
697 .map(GenericTypePackDefault::from),
698 TypeInfo::Tuple { .. } => self
699 .pop_type_pack()
700 .map(GenericTypePackDefault::from),
701 _ => Err(ConvertError::GenericDeclaration {
702 generics: generics.to_string(),
703 }),
704 }
705 }
706 })
707 .transpose()?
708 {
709 let mut generic_pack_with_default =
710 GenericTypePackWithDefault::new(
711 generic_pack,
712 default_type,
713 );
714
715 if self.hold_token_data {
716 let equal_token =
717 parameter.equals().ok_or_else(|| {
718 ConvertError::GenericDeclaration {
719 generics: generics.to_string(),
720 }
721 })?;
722 generic_pack_with_default
723 .set_token(self.convert_token(equal_token)?);
724 }
725
726 generic_type_packs_with_default
727 .push(generic_pack_with_default);
728 } else {
729 generic_type_packs.push(generic_pack)
730 }
731 }
732 _ => {
733 return Err(ConvertError::GenericDeclaration {
734 generics: generics.to_string(),
735 })
736 }
737 }
738 }
739
740 let mut type_variable_iter = type_variables.into_iter();
741 let mut type_variable_with_default_iter = type_variables_with_default
742 .into_iter()
743 .map(|(variable, default, token)| {
744 let mut type_variable =
745 TypeVariableWithDefault::new(variable, default);
746
747 if let Some(token) = token {
748 type_variable.set_token(token);
749 }
750
751 type_variable
752 });
753 let mut generic_type_packs_iter = generic_type_packs.into_iter();
754 let mut generic_type_packs_with_default_iter =
755 generic_type_packs_with_default.into_iter();
756
757 let mut generic_parameters = type_variable_iter
758 .next()
759 .map(GenericParametersWithDefaults::from_type_variable)
760 .or_else(|| {
761 type_variable_with_default_iter.next().map(
762 GenericParametersWithDefaults::from_type_variable_with_default,
763 )
764 })
765 .or_else(|| {
766 generic_type_packs_iter
767 .next()
768 .map(GenericParametersWithDefaults::from_generic_type_pack)
769 })
770 .or_else(|| {
771 generic_type_packs_with_default_iter
772 .next()
773 .map(GenericParametersWithDefaults::from_generic_type_pack_with_default)
774 })
775 .ok_or_else(|| ConvertError::GenericDeclaration {
776 generics: generics.to_string(),
777 })?;
778
779 for type_variable in type_variable_iter {
780 generic_parameters.push_type_variable(type_variable);
781 }
782
783 for type_variable_with_default in type_variable_with_default_iter {
784 if !generic_parameters
785 .push_type_variable_with_default(type_variable_with_default)
786 {
787 return Err(ConvertError::GenericDeclaration {
788 generics: generics.to_string(),
789 });
790 }
791 }
792
793 for generic_type_pack in generic_type_packs_iter {
794 if !generic_parameters.push_generic_type_pack(generic_type_pack) {
795 return Err(ConvertError::GenericDeclaration {
796 generics: generics.to_string(),
797 });
798 }
799 }
800
801 for generic_type_pack_with_default in generic_type_packs_with_default_iter {
802 generic_parameters.push_generic_type_pack_with_default(
803 generic_type_pack_with_default,
804 );
805 }
806
807 if self.hold_token_data {
808 let (opening_list, closing_list) =
809 self.extract_contained_span_tokens(generics.arrows())?;
810 generic_parameters.set_tokens(GenericParametersTokens {
811 opening_list,
812 closing_list,
813 commas: self
814 .extract_tokens_from_punctuation(generics.generics())?,
815 });
816 }
817
818 declaration.set_generic_parameters(generic_parameters);
819 }
820
821 if self.hold_token_data {
822 declaration.set_tokens(TypeDeclarationTokens {
823 r#type: self.convert_token(type_declaration.type_token())?,
824 equal: self.convert_token(type_declaration.equal_token())?,
825 export: export_token
826 .map(|token| self.convert_token(token))
827 .transpose()?,
828 });
829 }
830 self.statements.push(declaration.into());
831 }
832 ConvertWork::MakeFunctionCallExpression { call } => {
833 let call = self.make_function_call(call)?;
834 self.expressions.push(call.into());
835 }
836 ConvertWork::MakeLocalFunctionStatement { statement } => {
837 let builder = self.convert_function_body_attributes(
838 statement.body(),
839 self.convert_token(statement.function_token())?,
840 )?;
841 let mut name = Identifier::new(statement.name().token().to_string());
842 let mut local_token = None;
843
844 if self.hold_token_data {
845 name.set_token(self.convert_token(statement.name())?);
846 local_token = Some(self.convert_token(statement.local_token())?);
847 }
848
849 self.statements.push(
850 builder
851 .into_local_function_statement(name, local_token)
852 .into(),
853 );
854 }
855 ConvertWork::MakeLocalAssignStatement { statement } => {
856 let variables = statement
857 .names()
858 .iter()
859 .zip(statement.type_specifiers())
860 .map(|(token_ref, type_specifier)| {
861 self.convert_typed_identifier(token_ref, type_specifier)
862 })
863 .collect::<Result<Vec<_>, _>>()?;
864
865 let mut local_assign = LocalAssignStatement::new(
866 variables,
867 self.pop_expressions(statement.expressions().len())?,
868 );
869
870 if self.hold_token_data {
871 local_assign.set_tokens(LocalAssignTokens {
872 local: self.convert_token(statement.local_token())?,
873 equal: statement
874 .equal_token()
875 .map(|token| self.convert_token(token))
876 .transpose()?,
877 variable_commas: self
878 .extract_tokens_from_punctuation(statement.names())?,
879 value_commas: self
880 .extract_tokens_from_punctuation(statement.expressions())?,
881 })
882 }
883 self.statements.push(local_assign.into());
884 }
885 ConvertWork::MakeArgumentsFromExpressions {
886 arguments,
887 parentheses,
888 } => {
889 let mut tuple = TupleArguments::new(self.pop_expressions(arguments.len())?);
890 if self.hold_token_data {
891 let (opening_parenthese, closing_parenthese) =
892 self.extract_contained_span_tokens(parentheses)?;
893 tuple.set_tokens(TupleArgumentsTokens {
894 opening_parenthese,
895 closing_parenthese,
896 commas: self.extract_tokens_from_punctuation(arguments)?,
897 })
898 }
899 self.arguments.push(tuple.into());
900 }
901 ConvertWork::MakeArgumentsFromTableEntries { table } => {
902 let expression = self.make_table_expression(table)?;
903 self.arguments.push(expression.into());
904 }
905 ConvertWork::MakeTableExpression { table } => {
906 let expression = self.make_table_expression(table)?;
907 self.expressions.push(expression.into());
908 }
909 ConvertWork::MakeAssignStatement { statement } => {
910 let variables = self.pop_variables(statement.variables().len())?;
911 let values = self.pop_expressions(statement.expressions().len())?;
912 let mut assignment = AssignStatement::new(variables, values);
913 if self.hold_token_data {
914 assignment.set_tokens(AssignTokens {
915 equal: self.convert_token(statement.equal_token())?,
916 variable_commas: self
917 .extract_tokens_from_punctuation(statement.variables())?,
918 value_commas: self
919 .extract_tokens_from_punctuation(statement.expressions())?,
920 });
921 }
922 self.statements.push(assignment.into());
923 }
924 ConvertWork::MakeVariable { variable } => {
925 let prefix = self.make_prefix_with_suffixes(variable.suffixes())?;
926 let variable = match prefix {
927 Prefix::Identifier(name) => Variable::Identifier(name),
928 Prefix::Field(field) => Variable::Field(field),
929 Prefix::Index(index) => Variable::Index(index),
930 Prefix::Call(_) | Prefix::Parenthese(_) => {
931 return Err(ConvertError::Variable {
932 variable: variable.to_string(),
933 })
934 }
935 };
936 self.variables.push(variable);
937 }
938 ConvertWork::MakePrefixExpression { variable } => {
939 let prefix = self.make_prefix_with_suffixes(variable.suffixes())?;
940 self.expressions.push(prefix.into());
941 }
942 ConvertWork::MakeCompoundAssignStatement { statement } => {
943 let variable = self.pop_variable()?;
944 let value = self.pop_expression()?;
945 let mut assignment = CompoundAssignStatement::new(
946 self.convert_compound_op(statement.compound_operator())?,
947 variable,
948 value,
949 );
950 if self.hold_token_data {
951 assignment.set_tokens(CompoundAssignTokens {
952 operator: self.convert_token(get_compound_operator_token(
953 statement.compound_operator(),
954 )?)?,
955 });
956 }
957 self.statements.push(assignment.into());
958 }
959 ConvertWork::MakeIfStatement { statement } => {
960 let condition = self.pop_expression()?;
961 let block = self.pop_block()?;
962 let mut if_statement = IfStatement::create(condition, block);
963 if let Some(elseifs) = statement.else_if() {
964 for else_if in elseifs {
965 let elseif_condition = self.pop_expression()?;
966 let elseif_block = self.pop_block()?;
967 let mut branch = IfBranch::new(elseif_condition, elseif_block);
968 if self.hold_token_data {
969 branch.set_tokens(IfBranchTokens {
970 elseif: self.convert_token(else_if.else_if_token())?,
971 then: self.convert_token(else_if.then_token())?,
972 });
973 }
974 if_statement.push_branch(branch);
975 }
976 }
977 if statement.else_block().is_some() {
978 if_statement.set_else_block(self.pop_block()?);
979 }
980 if self.hold_token_data {
981 if_statement.set_tokens(IfStatementTokens {
982 r#if: self.convert_token(statement.if_token())?,
983 then: self.convert_token(statement.then_token())?,
984 end: self.convert_token(statement.end_token())?,
985 r#else: statement
986 .else_token()
987 .map(|token| self.convert_token(token))
988 .transpose()?,
989 })
990 }
991 self.statements.push(if_statement.into());
992 }
993 ConvertWork::MakeFunctionReturnType { type_info } => {
994 use ast::luau::TypeInfo;
995
996 let return_type = if is_variadic_type(type_info).is_some() {
997 self.pop_variadic_type_pack()?.into()
998 } else {
999 match type_info {
1000 TypeInfo::Tuple { .. } => self.pop_type_pack()?.into(),
1001 TypeInfo::GenericPack { .. } => self.pop_generic_type_pack()?.into(),
1002 _ => self.pop_type()?.into(),
1003 }
1004 };
1005
1006 self.function_return_types.push(return_type);
1007 }
1008 ConvertWork::MakeVariadicTypePack { ellipsis } => {
1009 let mut variadic_type_pack = VariadicTypePack::new(self.pop_type()?);
1010
1011 if self.hold_token_data {
1012 variadic_type_pack.set_token(self.convert_token(ellipsis)?);
1013 }
1014
1015 self.variadic_type_packs.push(variadic_type_pack);
1016 }
1017 ConvertWork::MakeArrayType { braces } => {
1018 let mut array_type = ArrayType::new(self.pop_type()?);
1019
1020 if self.hold_token_data {
1021 let (opening_brace, closing_brace) =
1022 self.extract_contained_span_tokens(braces)?;
1023
1024 array_type.set_tokens(ArrayTypeTokens {
1025 opening_brace,
1026 closing_brace,
1027 })
1028 }
1029
1030 self.types.push(array_type.into());
1031 }
1032 ConvertWork::MakeOptionalType { question_mark } => {
1033 let mut optional_type = OptionalType::new(self.pop_type()?);
1034
1035 if self.hold_token_data {
1036 optional_type.set_token(self.convert_token(question_mark)?);
1037 }
1038
1039 self.types.push(optional_type.into());
1040 }
1041 ConvertWork::MakeIntersectionType {
1042 length,
1043 leading_token,
1044 separators,
1045 } => {
1046 let types = self.pop_types(length)?;
1047
1048 let mut intersection_type = IntersectionType::from(types);
1049
1050 if self.hold_token_data {
1051 intersection_type.set_tokens(IntersectionTypeTokens {
1052 leading_token: leading_token
1053 .map(|token| self.convert_token(token))
1054 .transpose()?,
1055 separators: self.extract_tokens_from_punctuation(separators)?,
1056 });
1057 } else if leading_token.is_some() {
1058 intersection_type.put_leading_token();
1059 }
1060
1061 self.types.push(intersection_type.into());
1062 }
1063 ConvertWork::MakeUnionType {
1064 length,
1065 leading_token,
1066 separators,
1067 } => {
1068 let types = self.pop_types(length)?;
1069
1070 let mut union_type = UnionType::from(types);
1071
1072 if self.hold_token_data {
1073 union_type.set_tokens(UnionTypeTokens {
1074 leading_token: leading_token
1075 .map(|token| self.convert_token(token))
1076 .transpose()?,
1077 separators: self.extract_tokens_from_punctuation(separators)?,
1078 });
1079 } else if leading_token.is_some() {
1080 union_type.put_leading_token();
1081 }
1082
1083 self.types.push(union_type.into());
1084 }
1085 ConvertWork::MakeTableType { braces, fields } => {
1086 let mut table_type = TableType::default();
1087
1088 for field in fields {
1089 use ast::luau::TypeFieldKey;
1090
1091 match field.key() {
1092 TypeFieldKey::Name(property_name) => {
1093 let mut property_type = TablePropertyType::new(
1094 self.convert_token_to_identifier(property_name)?,
1095 self.pop_type()?,
1096 );
1097
1098 if self.hold_token_data {
1099 property_type
1100 .set_token(self.convert_token(field.colon_token())?);
1101 }
1102
1103 table_type.push_property(property_type);
1104 }
1105 TypeFieldKey::IndexSignature { brackets, .. } => {
1106 let mut indexer_type =
1107 TableIndexerType::new(self.pop_type()?, self.pop_type()?);
1108
1109 if self.hold_token_data {
1110 let (opening_bracket, closing_bracket) =
1111 self.extract_contained_span_tokens(brackets)?;
1112
1113 indexer_type.set_tokens(TableIndexTypeTokens {
1114 opening_bracket,
1115 closing_bracket,
1116 colon: self.convert_token(field.colon_token())?,
1117 })
1118 }
1119
1120 table_type.set_indexer_type(indexer_type);
1121 }
1122 key => {
1123 return Err(ConvertError::TableTypeProperty {
1124 property: key.to_string(),
1125 });
1126 }
1127 }
1128 }
1129
1130 if self.hold_token_data {
1131 let (opening_brace, closing_brace) =
1132 self.extract_contained_span_tokens(braces)?;
1133
1134 table_type.set_tokens(TableTypeTokens {
1135 opening_brace,
1136 closing_brace,
1137 separators: self.extract_tokens_from_punctuation(fields)?,
1138 })
1139 }
1140
1141 self.types.push(table_type.into());
1142 }
1143 ConvertWork::MakeExpressionType {
1144 typeof_token,
1145 parentheses,
1146 } => {
1147 let mut expression_type = ExpressionType::new(self.pop_expression()?);
1148
1149 if self.hold_token_data {
1150 let (opening_parenthese, closing_parenthese) =
1151 self.extract_contained_span_tokens(parentheses)?;
1152
1153 expression_type.set_tokens(ExpressionTypeTokens {
1154 r#typeof: self.convert_token(typeof_token)?,
1155 opening_parenthese,
1156 closing_parenthese,
1157 });
1158 }
1159
1160 self.types.push(expression_type.into());
1161 }
1162 ConvertWork::MakeFunctionType {
1163 generics,
1164 parentheses,
1165 arguments,
1166 arrow,
1167 } => {
1168 let mut function_type = FunctionType::new(self.pop_function_return_type()?);
1169
1170 for argument in arguments {
1171 use ast::luau::TypeInfo;
1172
1173 if is_variadic_type(argument.type_info()).is_some() {
1174 function_type.set_variadic_type(self.pop_variadic_type_pack()?);
1175 } else {
1176 match argument.type_info() {
1177 TypeInfo::Variadic { .. } | TypeInfo::VariadicPack { .. } => {
1178 function_type.set_variadic_type(self.pop_variadic_type_pack()?);
1179 }
1180 TypeInfo::GenericPack { .. } => {
1181 function_type.set_variadic_type(self.pop_generic_type_pack()?);
1182 }
1183 _ => {
1184 let mut argument_type =
1185 FunctionArgumentType::new(self.pop_type()?);
1186
1187 if let Some((name, colon)) = argument.name() {
1188 argument_type
1189 .set_name(self.convert_token_to_identifier(name)?);
1190
1191 if self.hold_token_data {
1192 argument_type.set_token(self.convert_token(colon)?);
1193 }
1194 }
1195
1196 function_type.push_argument(argument_type);
1197 }
1198 };
1199 }
1200 }
1201
1202 if let Some(generics) = generics {
1203 let generic_parameters = self.convert_generic_type_parameters(generics)?;
1204
1205 function_type.set_generic_parameters(generic_parameters);
1206 }
1207
1208 if self.hold_token_data {
1209 let (opening_parenthese, closing_parenthese) =
1210 self.extract_contained_span_tokens(parentheses)?;
1211
1212 function_type.set_tokens(FunctionTypeTokens {
1213 opening_parenthese,
1214 closing_parenthese,
1215 arrow: self.convert_token(arrow)?,
1216 commas: self.extract_tokens_from_punctuation(arguments)?,
1217 });
1218 }
1219
1220 self.types.push(function_type.into());
1221 }
1222 ConvertWork::MakeGenericType { base, module } => {
1223 let type_name = TypeName::new(self.convert_token_to_identifier(base)?)
1224 .with_type_parameters(self.pop_type_parameters()?);
1225
1226 self.types
1227 .push(if let Some((module, punctuation)) = module {
1228 let mut type_field = TypeField::new(
1229 self.convert_token_to_identifier(module)?,
1230 type_name,
1231 );
1232
1233 if self.hold_token_data {
1234 type_field.set_token(self.convert_token(punctuation)?);
1235 }
1236
1237 type_field.into()
1238 } else {
1239 type_name.into()
1240 });
1241 }
1242 ConvertWork::MakeTypeParameters { arrows, generics } => {
1243 use ast::luau::TypeInfo;
1244
1245 let mut parameters = generics
1246 .iter()
1247 .map(|type_parameter| {
1248 if is_variadic_type(type_parameter).is_some() {
1249 self.pop_variadic_type_pack().map(TypeParameter::from)
1250 } else {
1251 match type_parameter {
1252 TypeInfo::GenericPack { .. } => {
1253 self.pop_generic_type_pack().map(TypeParameter::from)
1254 }
1255 TypeInfo::VariadicPack { .. } | TypeInfo::Variadic { .. } => {
1256 self.pop_variadic_type_pack().map(TypeParameter::from)
1257 }
1258 TypeInfo::Tuple { .. } => {
1259 self.pop_type_pack().map(TypeParameter::from)
1260 }
1261 TypeInfo::Array { .. }
1262 | TypeInfo::Basic(_)
1263 | TypeInfo::String(_)
1264 | TypeInfo::Boolean(_)
1265 | TypeInfo::Callback { .. }
1266 | TypeInfo::Generic { .. }
1267 | TypeInfo::Intersection { .. }
1268 | TypeInfo::Module { .. }
1269 | TypeInfo::Optional { .. }
1270 | TypeInfo::Table { .. }
1271 | TypeInfo::Typeof { .. }
1272 | TypeInfo::Union { .. } => {
1273 self.pop_type().map(TypeParameter::from)
1274 }
1275 _ => Err(ConvertError::TypeInfo {
1276 type_info: type_parameter.to_string(),
1277 }),
1278 }
1279 }
1280 })
1281 .collect::<Result<TypeParameters, ConvertError>>()?;
1282
1283 if self.hold_token_data {
1284 let (opening_list, closing_list) =
1285 self.extract_contained_span_tokens(arrows)?;
1286
1287 let commas = self.extract_tokens_from_punctuation(generics)?;
1288
1289 parameters.set_tokens(TypeParametersTokens {
1290 opening_list,
1291 closing_list,
1292 commas,
1293 })
1294 }
1295
1296 self.type_parameters.push(parameters);
1297 }
1298 ConvertWork::MakeTypeCast { type_assertion } => {
1299 let r#type = self.pop_type()?;
1300 let expression = self.pop_expression()?;
1301
1302 let mut type_cast = TypeCastExpression::new(expression, r#type);
1303
1304 if self.hold_token_data {
1305 type_cast.set_token(self.convert_token(type_assertion.assertion_op())?);
1306 }
1307
1308 self.expressions.push(type_cast.into());
1309 }
1310 ConvertWork::MakeParentheseType { parentheses } => {
1311 let r#type = self.pop_type()?;
1312
1313 let mut parenthese_type = ParentheseType::new(r#type);
1314
1315 if self.hold_token_data {
1316 let (left_parenthese, right_parenthese) =
1317 self.extract_contained_span_tokens(parentheses)?;
1318 parenthese_type.set_tokens(ParentheseTypeTokens {
1319 left_parenthese,
1320 right_parenthese,
1321 });
1322 }
1323
1324 self.types.push(parenthese_type.into());
1325 }
1326 ConvertWork::MakeTypePack { types, parentheses } => {
1327 use ast::luau::TypeInfo;
1328
1329 let mut type_pack = TypePack::default();
1330
1331 let last_index = types.len().saturating_sub(1);
1332 for (i, r#type) in types.iter().enumerate() {
1333 if i == last_index && is_variadic_type(r#type).is_some() {
1334 type_pack.set_variadic_type(self.pop_variadic_type_pack()?);
1335 } else {
1336 match r#type {
1337 TypeInfo::GenericPack { .. } => {
1338 type_pack.set_variadic_type(self.pop_generic_type_pack()?);
1339 }
1340 _ => {
1341 type_pack.push_type(self.pop_type()?);
1342 }
1343 }
1344 }
1345 }
1346
1347 if self.hold_token_data {
1348 let (left_parenthese, right_parenthese) =
1349 self.extract_contained_span_tokens(parentheses)?;
1350 let commas = self.extract_tokens_from_punctuation(types)?;
1351 type_pack.set_tokens(TypePackTokens {
1352 left_parenthese,
1353 right_parenthese,
1354 commas,
1355 });
1356 }
1357
1358 self.type_packs.push(type_pack);
1359 }
1360 }
1361 }
1362
1363 let mut block = self.blocks.pop().expect("root block should be converted");
1364
1365 if self.hold_token_data {
1366 if let Some(tokens) = block.mutate_tokens() {
1367 let token = self.convert_token(ast.eof())?;
1368 if token.has_trivia() {
1369 tokens.final_token = Some(token);
1370 }
1371 }
1372 }
1373
1374 Ok(block)
1375 }
1376
1377 fn convert_generic_type_parameters(
1378 &mut self,
1379 generics: &ast::luau::GenericDeclaration,
1380 ) -> Result<GenericParameters, ConvertError> {
1381 let mut type_variables = Vec::new();
1382 let mut generic_type_packs = Vec::new();
1383 for parameter in generics.generics() {
1384 match parameter.parameter() {
1385 ast::luau::GenericParameterInfo::Name(name) => {
1386 if !generic_type_packs.is_empty() {
1387 return Err(ConvertError::GenericDeclaration {
1388 generics: generics.to_string(),
1389 });
1390 }
1391 type_variables.push(self.convert_token_to_identifier(name)?);
1392 }
1393 ast::luau::GenericParameterInfo::Variadic { name, ellipsis } => {
1394 let mut generic_pack =
1395 GenericTypePack::new(self.convert_token_to_identifier(name)?);
1396
1397 if self.hold_token_data {
1398 generic_pack.set_token(self.convert_token(ellipsis)?);
1399 }
1400
1401 generic_type_packs.push(generic_pack);
1402 }
1403 _ => {
1404 return Err(ConvertError::GenericDeclaration {
1405 generics: generics.to_string(),
1406 })
1407 }
1408 }
1409 }
1410 let mut type_variables_iter = type_variables.into_iter();
1411 let mut generic_type_packs_iter = generic_type_packs.into_iter();
1412 let mut generic_parameters = type_variables_iter
1413 .next()
1414 .map(GenericParameters::from_type_variable)
1415 .or_else(|| {
1416 generic_type_packs_iter
1417 .next()
1418 .map(GenericParameters::from_generic_type_pack)
1419 })
1420 .ok_or_else(|| ConvertError::GenericDeclaration {
1421 generics: generics.to_string(),
1422 })?;
1423
1424 for type_variable in type_variables_iter {
1425 generic_parameters.push_type_variable(type_variable);
1426 }
1427
1428 for generic_pack in generic_type_packs_iter {
1429 generic_parameters.push_generic_type_pack(generic_pack);
1430 }
1431
1432 if self.hold_token_data {
1433 let (opening_list, closing_list) =
1434 self.extract_contained_span_tokens(generics.arrows())?;
1435 let commas = self.extract_tokens_from_punctuation(generics.generics())?;
1436 generic_parameters.set_tokens(GenericParametersTokens {
1437 opening_list,
1438 closing_list,
1439 commas,
1440 });
1441 }
1442
1443 Ok(generic_parameters)
1444 }
1445
1446 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
1447 fn convert_statement(&mut self, statement: &'a ast::Stmt) -> Result<(), ConvertError> {
1448 match statement {
1449 ast::Stmt::Assignment(assignment) => {
1450 self.work_stack.push(ConvertWork::MakeAssignStatement {
1451 statement: assignment,
1452 });
1453 for variable in assignment.variables() {
1454 self.convert_variable(variable)?;
1455 }
1456 for expression in assignment.expressions() {
1457 self.push_work(expression);
1458 }
1459 }
1460 ast::Stmt::Do(do_statement) => {
1461 self.work_stack.push(ConvertWork::MakeDoStatement {
1462 statement: do_statement,
1463 });
1464 self.push_work(do_statement.block());
1465 }
1466 ast::Stmt::FunctionCall(call) => {
1467 self.work_stack
1468 .push(ConvertWork::MakeFunctionCallStatement { call });
1469 self.convert_function_call(call)?;
1470 }
1471 ast::Stmt::FunctionDeclaration(function) => {
1472 self.work_stack.push(ConvertWork::MakeFunctionDeclaration {
1473 statement: function,
1474 });
1475 self.push_function_body_work(function.body());
1476 }
1477 ast::Stmt::GenericFor(generic_for) => {
1478 self.work_stack.push(ConvertWork::MakeGenericForStatement {
1479 statement: generic_for,
1480 });
1481 self.push_work(generic_for.block());
1482 for type_specifier in generic_for.type_specifiers().flatten() {
1483 self.push_work(type_specifier.type_info());
1484 }
1485 for expression in generic_for.expressions().iter() {
1486 self.push_work(expression);
1487 }
1488 }
1489 ast::Stmt::If(if_statement) => {
1490 self.work_stack.push(ConvertWork::MakeIfStatement {
1491 statement: if_statement,
1492 });
1493 self.push_work(if_statement.condition());
1494 self.push_work(if_statement.block());
1495 if let Some(elseifs) = if_statement.else_if() {
1496 for branch in elseifs {
1497 self.push_work(branch.condition());
1498 self.push_work(branch.block());
1499 }
1500 }
1501 if let Some(block) = if_statement.else_block() {
1502 self.push_work(block);
1503 }
1504 }
1505 ast::Stmt::LocalAssignment(local_assign) => {
1506 self.work_stack.push(ConvertWork::MakeLocalAssignStatement {
1507 statement: local_assign,
1508 });
1509 for type_specifier in local_assign.type_specifiers().flatten() {
1510 self.push_work(type_specifier.type_info());
1511 }
1512 for expression in local_assign.expressions().iter() {
1513 self.push_work(expression);
1514 }
1515 }
1516 ast::Stmt::LocalFunction(local_function) => {
1517 self.work_stack
1518 .push(ConvertWork::MakeLocalFunctionStatement {
1519 statement: local_function,
1520 });
1521 self.push_function_body_work(local_function.body());
1522 }
1523 ast::Stmt::NumericFor(numeric_for) => {
1524 self.work_stack.push(ConvertWork::MakeNumericForStatement {
1525 statement: numeric_for,
1526 });
1527 if let Some(type_info) = numeric_for.type_specifier() {
1528 self.push_work(type_info.type_info());
1529 }
1530 self.push_work(numeric_for.block());
1531 self.work_stack
1532 .push(ConvertWork::Expression(numeric_for.start()));
1533 self.work_stack
1534 .push(ConvertWork::Expression(numeric_for.end()));
1535 if let Some(step) = numeric_for.step() {
1536 self.push_work(step);
1537 }
1538 }
1539 ast::Stmt::Repeat(repeat) => {
1540 self.work_stack
1541 .push(ConvertWork::MakeRepeatStatement { statement: repeat });
1542 self.push_work(repeat.block());
1543 self.push_work(repeat.until());
1544 }
1545 ast::Stmt::While(while_statement) => {
1546 self.work_stack.push(ConvertWork::MakeWhileStatement {
1547 statement: while_statement,
1548 });
1549 self.push_work(while_statement.block());
1550 self.push_work(while_statement.condition());
1551 }
1552 ast::Stmt::CompoundAssignment(assignment) => {
1553 self.work_stack
1554 .push(ConvertWork::MakeCompoundAssignStatement {
1555 statement: assignment,
1556 });
1557 self.convert_variable(assignment.lhs())?;
1558 self.push_work(assignment.rhs());
1559 }
1560 ast::Stmt::ExportedTypeDeclaration(exported_type_declaration) => {
1561 let type_declaration = exported_type_declaration.type_declaration();
1562
1563 self.convert_type_declaration(
1564 type_declaration,
1565 Some(exported_type_declaration.export_token()),
1566 );
1567 }
1568 ast::Stmt::TypeDeclaration(type_declaration) => {
1569 self.convert_type_declaration(type_declaration, None);
1570 }
1571 _ => {
1572 return Err(ConvertError::Statement {
1573 statement: statement.to_string(),
1574 })
1575 }
1576 }
1577 Ok(())
1578 }
1579
1580 fn convert_type_declaration(
1581 &mut self,
1582 type_declaration: &'a ast::luau::TypeDeclaration,
1583 export_token: Option<&'a tokenizer::TokenReference>,
1584 ) {
1585 self.work_stack
1586 .push(ConvertWork::MakeTypeDeclarationStatement {
1587 type_declaration,
1588 export_token,
1589 });
1590 self.push_work(type_declaration.type_definition());
1591
1592 if let Some(generics) = type_declaration.generics() {
1593 for parameter in generics.generics() {
1594 if let Some(default_type) = parameter.default_type() {
1595 match (parameter.parameter(), default_type) {
1596 (
1597 ast::luau::GenericParameterInfo::Variadic { .. },
1598 ast::luau::TypeInfo::Tuple { parentheses, types },
1599 ) => {
1600 self.push_type_pack_work(types, parentheses);
1601 }
1602 _ => {
1603 self.push_maybe_variadic_type(default_type);
1604 }
1605 }
1606 }
1607 }
1608 }
1609 }
1610
1611 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
1612 fn convert_table(&mut self, table: &'a ast::TableConstructor) -> Result<(), ConvertError> {
1613 for field in table.fields() {
1614 match field {
1615 ast::Field::ExpressionKey {
1616 brackets: _,
1617 key,
1618 equal: _,
1619 value,
1620 } => {
1621 self.push_work(key);
1622 self.push_work(value);
1623 }
1624 ast::Field::NameKey {
1625 key: _,
1626 equal: _,
1627 value,
1628 } => {
1629 self.push_work(value);
1630 }
1631 ast::Field::NoKey(value) => {
1632 self.push_work(value);
1633 }
1634 _ => {
1635 return Err(ConvertError::TableEntry {
1636 entry: field.to_string(),
1637 })
1638 }
1639 }
1640 }
1641 Ok(())
1642 }
1643
1644 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
1645 fn make_table_expression(
1646 &mut self,
1647 table: &ast::TableConstructor,
1648 ) -> Result<TableExpression, ConvertError> {
1649 let entries: Result<_, _> = table
1650 .fields()
1651 .iter()
1652 .map(|field| match field {
1653 ast::Field::ExpressionKey {
1654 brackets,
1655 key: _,
1656 equal,
1657 value: _,
1658 } => {
1659 let key = self.pop_expression()?;
1660 let value = self.pop_expression()?;
1661 let mut entry = TableIndexEntry::new(key, value);
1662 if self.hold_token_data {
1663 let (opening_bracket, closing_bracket) =
1664 self.extract_contained_span_tokens(brackets)?;
1665 entry.set_tokens(TableIndexEntryTokens {
1666 opening_bracket,
1667 closing_bracket,
1668 equal: self.convert_token(equal)?,
1669 })
1670 }
1671 Ok(entry.into())
1672 }
1673 ast::Field::NameKey {
1674 key,
1675 equal,
1676 value: _,
1677 } => {
1678 let mut entry = TableFieldEntry::new(
1679 self.convert_token_to_identifier(key)?,
1680 self.pop_expression()?,
1681 );
1682 if self.hold_token_data {
1683 entry.set_token(self.convert_token(equal)?);
1684 }
1685 Ok(entry.into())
1686 }
1687 ast::Field::NoKey(_) => Ok(TableEntry::Value(self.pop_expression()?)),
1688 _ => Err(ConvertError::TableEntry {
1689 entry: field.to_string(),
1690 }),
1691 })
1692 .collect();
1693 let mut expression = TableExpression::new(entries?);
1694 if self.hold_token_data {
1695 let (opening_brace, closing_brace) =
1696 self.extract_contained_span_tokens(table.braces())?;
1697 expression.set_tokens(TableTokens {
1698 opening_brace,
1699 closing_brace,
1700 separators: self.extract_tokens_from_punctuation(table.fields())?,
1701 });
1702 }
1703 Ok(expression)
1704 }
1705
1706 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
1707 fn make_function_call(
1708 &mut self,
1709 call: &'a ast::FunctionCall,
1710 ) -> Result<FunctionCall, ConvertError> {
1711 let prefix = self.make_prefix_with_suffixes(call.suffixes())?;
1712 match prefix {
1713 Prefix::Call(call) => Ok(call),
1714 _ => panic!(
1715 "FunctionCall should convert to a call statement, but got {:#?}",
1716 prefix,
1717 ),
1718 }
1719 }
1720
1721 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
1722 fn make_prefix_with_suffixes(
1723 &mut self,
1724 suffixes: impl Iterator<Item = &'a ast::Suffix>,
1725 ) -> Result<Prefix, ConvertError> {
1726 let mut prefix = self.pop_prefix()?;
1727
1728 for suffix in suffixes {
1729 match suffix {
1730 ast::Suffix::Call(call_suffix) => match call_suffix {
1731 ast::Call::AnonymousCall(_) => {
1732 let mut call = FunctionCall::new(prefix, self.pop_arguments()?, None);
1733 if self.hold_token_data {
1734 call.set_tokens(FunctionCallTokens { colon: None })
1735 }
1736 prefix = call.into();
1737 }
1738 ast::Call::MethodCall(method_call) => {
1739 let mut call = FunctionCall::new(
1740 prefix,
1741 self.pop_arguments()?,
1742 Some(self.convert_token_to_identifier(method_call.name())?),
1743 );
1744 if self.hold_token_data {
1745 call.set_tokens(FunctionCallTokens {
1746 colon: Some(self.convert_token(method_call.colon_token())?),
1747 });
1748 }
1749 prefix = call.into();
1750 }
1751 _ => {
1752 return Err(ConvertError::Call {
1753 call: call_suffix.to_string(),
1754 });
1755 }
1756 },
1757 ast::Suffix::Index(index) => match index {
1758 ast::Index::Brackets {
1759 brackets,
1760 expression: _,
1761 } => {
1762 let mut index = IndexExpression::new(prefix, self.pop_expression()?);
1763 if self.hold_token_data {
1764 let (opening_bracket, closing_bracket) =
1765 self.extract_contained_span_tokens(brackets)?;
1766 index.set_tokens(IndexExpressionTokens {
1767 opening_bracket,
1768 closing_bracket,
1769 });
1770 }
1771 prefix = index.into();
1772 }
1773 ast::Index::Dot { name, dot } => {
1774 let mut field =
1775 FieldExpression::new(prefix, self.convert_token_to_identifier(name)?);
1776 if self.hold_token_data {
1777 field.set_token(self.convert_token(dot)?);
1778 }
1779 prefix = field.into();
1780 }
1781 _ => {
1782 return Err(ConvertError::Index {
1783 index: index.to_string(),
1784 });
1785 }
1786 },
1787 _ => {
1788 return Err(ConvertError::Suffix {
1789 suffix: suffix.to_string(),
1790 });
1791 }
1792 }
1793 }
1794
1795 Ok(prefix)
1796 }
1797
1798 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
1799 fn convert_expression(&mut self, expression: &'a ast::Expression) -> Result<(), ConvertError> {
1800 match expression {
1801 ast::Expression::BinaryOperator { lhs, binop, rhs } => {
1802 self.work_stack
1803 .push(ConvertWork::MakeBinaryExpression { operator: binop });
1804 self.work_stack.push(ConvertWork::Expression(lhs));
1805 self.work_stack.push(ConvertWork::Expression(rhs));
1806 }
1807 ast::Expression::Parentheses {
1808 contained,
1809 expression: inner_expression,
1810 } => {
1811 self.work_stack.push(ConvertWork::MakeParentheseExpression {
1812 contained_span: contained,
1813 });
1814 self.work_stack
1815 .push(ConvertWork::Expression(inner_expression));
1816 }
1817 ast::Expression::UnaryOperator { unop, expression } => {
1818 self.work_stack
1819 .push(ConvertWork::MakeUnaryExpression { operator: unop });
1820 self.work_stack.push(ConvertWork::Expression(expression));
1821 }
1822 ast::Expression::TypeAssertion {
1823 expression,
1824 type_assertion,
1825 } => {
1826 self.work_stack
1827 .push(ConvertWork::MakeTypeCast { type_assertion });
1828 self.push_work(type_assertion.cast_to());
1829 self.push_work(expression.as_ref());
1830 }
1831 ast::Expression::Function(function) => {
1832 let (token, body) = function.as_ref();
1833 self.work_stack
1834 .push(ConvertWork::MakeFunctionExpression { body, token });
1835
1836 self.push_function_body_work(body);
1837 }
1838 ast::Expression::FunctionCall(call) => {
1839 self.work_stack
1840 .push(ConvertWork::MakeFunctionCallExpression { call });
1841 self.convert_function_call(call)?;
1842 }
1843 ast::Expression::TableConstructor(table) => {
1844 self.work_stack
1845 .push(ConvertWork::MakeTableExpression { table });
1846 self.convert_table(table)?;
1847 }
1848 ast::Expression::Number(number) => {
1849 let mut expression = NumberExpression::from_str(&number.token().to_string())
1850 .map_err(|err| ConvertError::Number {
1851 number: number.to_string(),
1852 parsing_error: err.to_string(),
1853 })?;
1854 if self.hold_token_data {
1855 expression.set_token(self.convert_token(number)?);
1856 }
1857 self.work_stack
1858 .push(ConvertWork::PushExpression(expression.into()));
1859 }
1860 ast::Expression::String(token_ref) => {
1861 self.work_stack.push(ConvertWork::PushExpression(
1862 self.convert_string_expression(token_ref)?.into(),
1863 ));
1864 }
1865 ast::Expression::Symbol(symbol_token) => match symbol_token.token().token_type() {
1866 TokenType::Symbol { symbol } => {
1867 let token = if self.hold_token_data {
1868 Some(self.convert_token(symbol_token)?)
1869 } else {
1870 None
1871 };
1872 let expression = match symbol {
1873 Symbol::True => Expression::True(token),
1874 Symbol::False => Expression::False(token),
1875 Symbol::Nil => Expression::Nil(token),
1876 Symbol::Ellipsis => Expression::VariableArguments(token),
1877 _ => {
1878 return Err(ConvertError::Expression {
1879 expression: expression.to_string(),
1880 })
1881 }
1882 };
1883 self.work_stack
1884 .push(ConvertWork::PushExpression(expression));
1885 }
1886 _ => {
1887 return Err(ConvertError::Expression {
1888 expression: expression.to_string(),
1889 })
1890 }
1891 },
1892 ast::Expression::Var(var) => match var {
1893 ast::Var::Expression(var_expression) => {
1894 self.work_stack.push(ConvertWork::MakePrefixExpression {
1895 variable: var_expression,
1896 });
1897 self.push_work(var_expression.prefix());
1898 self.convert_suffixes(var_expression.suffixes())?;
1899 }
1900 ast::Var::Name(token_ref) => {
1901 self.work_stack
1902 .push(ConvertWork::PushExpression(Expression::Identifier(
1903 self.convert_token_to_identifier(token_ref)?,
1904 )));
1905 }
1906 _ => {
1907 return Err(ConvertError::Expression {
1908 expression: expression.to_string(),
1909 })
1910 }
1911 },
1912 ast::Expression::IfExpression(if_expression) => {
1913 self.push_work(ConvertWork::MakeIfExpression { if_expression });
1914 self.push_work(if_expression.condition());
1915 self.push_work(if_expression.if_expression());
1916 self.push_work(if_expression.else_expression());
1917 if let Some(elseif_expressions) = if_expression.else_if_expressions() {
1918 for elseif in elseif_expressions {
1919 self.push_work(elseif.condition());
1920 self.push_work(elseif.expression());
1921 }
1922 }
1923 }
1924 ast::Expression::InterpolatedString(interpolated_string) => {
1925 self.push_work(ConvertWork::MakeInterpolatedString {
1926 interpolated_string,
1927 });
1928 for segment in interpolated_string.segments() {
1929 self.push_work(&segment.expression);
1930 }
1931 }
1932 _ => {
1933 return Err(ConvertError::Expression {
1934 expression: expression.to_string(),
1935 })
1936 }
1937 }
1938 Ok(())
1939 }
1940
1941 fn push_function_body_work(&mut self, body: &'a ast::FunctionBody) {
1942 self.push_work(body.block());
1943 if let Some(return_type) = body.return_type() {
1944 self.push_function_return_type(return_type.type_info());
1945 }
1946 for type_specifier in body.type_specifiers().flatten() {
1947 self.push_work(type_specifier.type_info());
1948 }
1949 }
1950
1951 fn push_function_return_type(&mut self, return_type: &'a ast::luau::TypeInfo) {
1952 self.push_work(ConvertWork::MakeFunctionReturnType {
1953 type_info: return_type,
1954 });
1955 match return_type {
1956 ast::luau::TypeInfo::Tuple { types, parentheses } => {
1957 self.push_type_pack_work(types, parentheses);
1958 }
1959 _ => {
1960 self.push_maybe_variadic_type(return_type);
1961 }
1962 };
1963 }
1964
1965 fn push_type_pack_work(
1966 &mut self,
1967 types: &'a ast::punctuated::Punctuated<ast::luau::TypeInfo>,
1968 parentheses: &'a ast::span::ContainedSpan,
1969 ) {
1970 self.work_stack
1971 .push(ConvertWork::MakeTypePack { types, parentheses });
1972
1973 let last_index = types.len().saturating_sub(1);
1974 for (i, r#type) in types.iter().enumerate() {
1975 if i == last_index {
1976 self.push_maybe_variadic_type(r#type);
1977 } else {
1978 self.push_work(r#type)
1979 }
1980 }
1981 }
1982
1983 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
1984 fn convert_type_info(
1985 &mut self,
1986 type_info: &'a ast::luau::TypeInfo,
1987 ) -> Result<(), ConvertError> {
1988 use ast::luau::TypeInfo;
1989
1990 match type_info {
1991 TypeInfo::Array {
1992 braces,
1993 type_info,
1994 access: _,
1995 } => {
1996 self.work_stack.push(ConvertWork::MakeArrayType { braces });
1997
1998 self.push_work(type_info.as_ref());
1999 }
2000 TypeInfo::Basic(token_ref) => {
2001 if let TokenType::Symbol { symbol } = token_ref.token_type() {
2002 let token = if self.hold_token_data {
2003 Some(self.convert_token(token_ref)?)
2004 } else {
2005 None
2006 };
2007 let new_type = match symbol {
2008 Symbol::Nil => Type::Nil(token),
2009 _ => {
2010 return Err(ConvertError::TypeInfo {
2011 type_info: type_info.to_string(),
2012 })
2013 }
2014 };
2015 self.work_stack.push(ConvertWork::PushType(new_type));
2016 } else {
2017 self.work_stack.push(ConvertWork::PushType(
2018 TypeName::new(self.convert_token_to_identifier(token_ref)?).into(),
2019 ));
2020 }
2021 }
2022 TypeInfo::String(token) => {
2023 self.work_stack.push(ConvertWork::PushType(
2024 self.convert_string_type(token)?.into(),
2025 ));
2026 }
2027 TypeInfo::Boolean(token_ref) => {
2028 if let TokenType::Symbol { symbol } = token_ref.token_type() {
2029 let token = if self.hold_token_data {
2030 Some(self.convert_token(token_ref)?)
2031 } else {
2032 None
2033 };
2034 let new_type = match symbol {
2035 Symbol::True => Type::True(token),
2036 Symbol::False => Type::False(token),
2037 _ => {
2038 return Err(ConvertError::TypeInfo {
2039 type_info: type_info.to_string(),
2040 })
2041 }
2042 };
2043 self.work_stack.push(ConvertWork::PushType(new_type));
2044 } else {
2045 return Err(ConvertError::TypeInfo {
2046 type_info: type_info.to_string(),
2047 });
2048 }
2049 }
2050 TypeInfo::Callback {
2051 generics,
2052 parentheses,
2053 arguments,
2054 arrow,
2055 return_type,
2056 } => {
2057 self.work_stack.push(ConvertWork::MakeFunctionType {
2058 generics,
2059 parentheses,
2060 arguments,
2061 arrow,
2062 });
2063
2064 self.push_function_return_type(return_type);
2065
2066 let mut has_variadic_type = false;
2067
2068 for argument in arguments {
2069 let argument_type = argument.type_info();
2070 if is_argument_variadic(argument_type) {
2071 if has_variadic_type {
2072 return Err(ConvertError::TypeInfo {
2073 type_info: type_info.to_string(),
2074 });
2075 }
2076 has_variadic_type = true;
2077 }
2078 self.push_maybe_variadic_type(argument_type);
2079 }
2080 }
2081 TypeInfo::Generic {
2082 base,
2083 arrows,
2084 generics,
2085 } => {
2086 self.push_generic_type_work(base, arrows, generics, None);
2087 }
2088 TypeInfo::GenericPack { name, ellipsis } => {
2089 let mut generic_pack =
2090 GenericTypePack::new(self.convert_token_to_identifier(name)?);
2091
2092 if self.hold_token_data {
2093 generic_pack.set_token(self.convert_token(ellipsis)?);
2094 }
2095
2096 self.generic_type_packs.push(generic_pack);
2097 }
2098 TypeInfo::Intersection(intersection) => {
2099 self.work_stack.push(ConvertWork::MakeIntersectionType {
2100 leading_token: intersection.leading(),
2101 separators: intersection.types(),
2102 length: intersection.types().len(),
2103 });
2104
2105 for type_info in intersection.types() {
2106 self.push_work(type_info);
2107 }
2108 }
2109 TypeInfo::Union(union) => {
2110 self.work_stack.push(ConvertWork::MakeUnionType {
2111 leading_token: union.leading(),
2112 separators: union.types(),
2113 length: union.types().len(),
2114 });
2115
2116 for type_info in union.types() {
2117 self.push_work(type_info);
2118 }
2119 }
2120 TypeInfo::Module {
2121 module,
2122 punctuation,
2123 type_info,
2124 } => match type_info.as_ref() {
2125 ast::luau::IndexedTypeInfo::Basic(name) => {
2126 let mut type_field = TypeField::new(
2127 self.convert_token_to_identifier(module)?,
2128 TypeName::new(self.convert_token_to_identifier(name)?),
2129 );
2130
2131 if self.hold_token_data {
2132 type_field.set_token(self.convert_token(punctuation)?);
2133 }
2134
2135 self.work_stack
2136 .push(ConvertWork::PushType(type_field.into()));
2137 }
2138 ast::luau::IndexedTypeInfo::Generic {
2139 base,
2140 arrows,
2141 generics,
2142 } => {
2143 self.push_generic_type_work(
2144 base,
2145 arrows,
2146 generics,
2147 Some((module, punctuation)),
2148 );
2149 }
2150 _ => {
2151 return Err(ConvertError::TypeInfo {
2152 type_info: type_info.to_string(),
2153 });
2154 }
2155 },
2156 TypeInfo::Optional {
2157 base,
2158 question_mark,
2159 } => {
2160 self.work_stack
2161 .push(ConvertWork::MakeOptionalType { question_mark });
2162
2163 self.push_work(base.as_ref());
2164 }
2165 TypeInfo::Table { braces, fields } => {
2166 self.work_stack
2167 .push(ConvertWork::MakeTableType { braces, fields });
2168
2169 for field in fields {
2170 use ast::luau::TypeFieldKey;
2171
2172 match field.key() {
2173 TypeFieldKey::Name(_) => {}
2174 TypeFieldKey::IndexSignature { inner, .. } => {
2175 self.push_work(inner);
2176 }
2177 key => {
2178 return Err(ConvertError::TableTypeProperty {
2179 property: key.to_string(),
2180 });
2181 }
2182 }
2183
2184 self.push_work(field.value());
2185 }
2186 }
2187 TypeInfo::Typeof {
2188 typeof_token,
2189 parentheses,
2190 inner,
2191 } => {
2192 self.work_stack.push(ConvertWork::MakeExpressionType {
2193 typeof_token,
2194 parentheses,
2195 });
2196
2197 self.push_work(inner.as_ref());
2198 }
2199 TypeInfo::Tuple { types, parentheses } => {
2200 if types.len() == 1 {
2201 self.work_stack
2202 .push(ConvertWork::MakeParentheseType { parentheses });
2203 self.push_work(
2204 types
2205 .iter()
2206 .next()
2207 .expect("types should contain exactly one type at this point"),
2208 );
2209 } else {
2210 return Err(ConvertError::TypeInfo {
2211 type_info: type_info.to_string(),
2212 });
2213 }
2214 }
2215 TypeInfo::Variadic { type_info, .. } => {
2216 self.push_work(type_info.as_ref());
2217 }
2218 TypeInfo::VariadicPack { name, .. } => {
2219 self.types
2220 .push(TypeName::new(self.convert_token_to_identifier(name)?).into());
2221 }
2222 _ => {
2223 return Err(ConvertError::TypeInfo {
2224 type_info: type_info.to_string(),
2225 });
2226 }
2227 }
2228
2229 Ok(())
2230 }
2231
2232 fn push_maybe_variadic_type(&mut self, type_info: &'a ast::luau::TypeInfo) {
2233 if let Some(ellipsis) = is_variadic_type(type_info) {
2234 self.work_stack
2235 .push(ConvertWork::MakeVariadicTypePack { ellipsis });
2236 }
2237 self.push_work(type_info);
2238 }
2239
2240 fn push_generic_type_work(
2241 &mut self,
2242 base: &'a tokenizer::TokenReference,
2243 arrows: &'a ast::span::ContainedSpan,
2244 generics: &'a ast::punctuated::Punctuated<ast::luau::TypeInfo>,
2245 module: Option<(&'a tokenizer::TokenReference, &'a tokenizer::TokenReference)>,
2246 ) {
2247 self.work_stack
2248 .push(ConvertWork::MakeGenericType { base, module });
2249
2250 self.work_stack
2251 .push(ConvertWork::MakeTypeParameters { arrows, generics });
2252
2253 for parameter_type in generics {
2254 match parameter_type {
2255 ast::luau::TypeInfo::Tuple { parentheses, types } => {
2256 self.push_type_pack_work(types, parentheses);
2257 }
2258 _ => {
2259 self.push_maybe_variadic_type(parameter_type);
2260 }
2261 }
2262 }
2263 }
2264
2265 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2266 fn convert_function_call(&mut self, call: &'a ast::FunctionCall) -> Result<(), ConvertError> {
2267 self.push_work(call.prefix());
2268 self.convert_suffixes(call.suffixes())?;
2269 Ok(())
2270 }
2271
2272 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2273 fn convert_suffixes(
2274 &mut self,
2275 suffixes: impl Iterator<Item = &'a ast::Suffix>,
2276 ) -> Result<(), ConvertError> {
2277 for suffix in suffixes {
2278 match suffix {
2279 ast::Suffix::Call(call_suffix) => match call_suffix {
2280 ast::Call::AnonymousCall(arguments) => {
2281 self.push_work(arguments);
2282 }
2283 ast::Call::MethodCall(method_call) => {
2284 self.push_work(method_call.args());
2285 }
2286 _ => {
2287 return Err(ConvertError::Call {
2288 call: call_suffix.to_string(),
2289 });
2290 }
2291 },
2292 ast::Suffix::Index(index) => match index {
2293 ast::Index::Brackets {
2294 brackets: _,
2295 expression,
2296 } => {
2297 self.push_work(expression);
2298 }
2299 ast::Index::Dot { name: _, dot: _ } => {}
2300 _ => {
2301 return Err(ConvertError::Index {
2302 index: index.to_string(),
2303 });
2304 }
2305 },
2306 _ => {
2307 return Err(ConvertError::Suffix {
2308 suffix: suffix.to_string(),
2309 });
2310 }
2311 }
2312 }
2313 Ok(())
2314 }
2315
2316 fn convert_token_position(
2317 &self,
2318 token: &tokenizer::TokenReference,
2319 ) -> Result<(usize, usize, usize), ConvertError> {
2320 let start = token
2321 .start_position()
2322 .ok_or_else(|| ConvertError::TokenPositionNotFound {
2323 token: token.to_string(),
2324 })?;
2325 Ok((
2326 start.bytes(),
2327 token
2328 .end_position()
2329 .ok_or_else(|| ConvertError::TokenPositionNotFound {
2330 token: token.to_string(),
2331 })?
2332 .bytes(),
2333 start.line(),
2334 ))
2335 }
2336
2337 fn convert_token_end_position(
2338 &self,
2339 token: &tokenizer::TokenReference,
2340 ) -> Result<(usize, usize), ConvertError> {
2341 let end_position =
2342 token
2343 .end_position()
2344 .ok_or_else(|| ConvertError::TokenPositionNotFound {
2345 token: token.to_string(),
2346 })?;
2347 Ok((end_position.bytes(), end_position.line()))
2348 }
2349
2350 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2351 fn convert_token(&self, token: &tokenizer::TokenReference) -> Result<Token, ConvertError> {
2352 let position = self.convert_token_position(token)?;
2353 let mut new_token = Token::new_with_line(position.0, position.1, position.2);
2354
2355 for trivia_token in token.leading_trivia() {
2356 new_token.push_leading_trivia(self.convert_trivia(trivia_token)?);
2357 }
2358
2359 for trivia_token in token.trailing_trivia() {
2360 new_token.push_trailing_trivia(self.convert_trivia(trivia_token)?);
2361 }
2362
2363 Ok(new_token)
2364 }
2365
2366 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2367 fn convert_trivia(&self, token: &tokenizer::Token) -> Result<Trivia, ConvertError> {
2368 use tokenizer::TokenKind;
2369
2370 let trivia = match token.token_kind() {
2371 TokenKind::MultiLineComment => TriviaKind::Comment,
2372 TokenKind::SingleLineComment => TriviaKind::Comment,
2373 TokenKind::Whitespace => TriviaKind::Whitespace,
2374 _ => return Err(ConvertError::UnexpectedTrivia(token.token_kind())),
2375 }
2376 .at(
2377 token.start_position().bytes(),
2378 token.end_position().bytes(),
2379 token.start_position().line(),
2380 );
2381 Ok(trivia)
2382 }
2383
2384 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2385 fn convert_token_to_identifier(
2386 &self,
2387 token: &tokenizer::TokenReference,
2388 ) -> Result<Identifier, ConvertError> {
2389 let mut identifier = Identifier::new(token.token().to_string());
2390 if self.hold_token_data {
2391 identifier.set_token(self.convert_token(token)?);
2392 }
2393 Ok(identifier)
2394 }
2395
2396 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2397 fn convert_typed_identifier(
2398 &mut self,
2399 identifier: &tokenizer::TokenReference,
2400 type_specifier: Option<&ast::luau::TypeSpecifier>,
2401 ) -> Result<TypedIdentifier, ConvertError> {
2402 let identifier = self.convert_token_to_identifier(identifier)?;
2403
2404 Ok(if let Some(type_specifier) = type_specifier {
2405 let mut typed_identifier = identifier.with_type(self.pop_type()?);
2406 if self.hold_token_data {
2407 typed_identifier.set_colon_token(self.convert_token(type_specifier.punctuation())?);
2408 }
2409 typed_identifier
2410 } else {
2411 identifier.into()
2412 })
2413 }
2414
2415 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2416 fn extract_tokens_from_punctuation<T>(
2417 &self,
2418 punctuated: &ast::punctuated::Punctuated<T>,
2419 ) -> Result<Vec<Token>, ConvertError> {
2420 punctuated
2421 .pairs()
2422 .filter_map(|pair| match pair {
2423 ast::punctuated::Pair::End(_) => None,
2424 ast::punctuated::Pair::Punctuated(_, token) => Some(self.convert_token(token)),
2425 })
2426 .collect()
2427 }
2428
2429 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2430 fn extract_contained_span_tokens(
2431 &self,
2432 contained_span: &ast::span::ContainedSpan,
2433 ) -> Result<(Token, Token), ConvertError> {
2434 let (left, right) = contained_span.tokens();
2435 Ok((self.convert_token(left)?, self.convert_token(right)?))
2436 }
2437
2438 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2439 fn convert_function_body_attributes(
2440 &mut self,
2441 body: &ast::FunctionBody,
2442 function_token: Token,
2443 ) -> Result<FunctionBuilder, ConvertError> {
2444 let mut builder = FunctionBuilder::from_block(self.pop_block()?);
2445
2446 if let Some(return_type) = body.return_type() {
2447 if self.hold_token_data {
2448 builder.set_return_type_colon(self.convert_token(return_type.punctuation())?);
2449 }
2450 builder.set_return_type(self.pop_function_return_type()?);
2451 };
2452
2453 for (param, type_specifier) in body.parameters().iter().zip(body.type_specifiers()) {
2454 match param {
2455 ast::Parameter::Ellipsis(token) => {
2456 if builder.is_variadic() {
2457 return Err(ConvertError::FunctionParameters {
2458 parameters: body.parameters().to_string(),
2459 });
2460 } else {
2461 if let Some(type_specifier) = type_specifier {
2462 builder.set_variadic_type(
2463 if let ast::luau::TypeInfo::GenericPack { .. } =
2464 type_specifier.type_info()
2465 {
2466 self.pop_generic_type_pack()?.into()
2467 } else {
2468 self.pop_type()?.into()
2469 },
2470 );
2471
2472 if self.hold_token_data {
2473 builder.set_variable_arguments_colon(
2474 self.convert_token(type_specifier.punctuation())?,
2475 );
2476 }
2477 } else {
2478 builder.set_variadic();
2479 }
2480 if self.hold_token_data {
2481 builder.set_variable_arguments_token(self.convert_token(token)?);
2482 }
2483 }
2484 }
2485 ast::Parameter::Name(name) => {
2486 if builder.is_variadic() {
2487 return Err(ConvertError::FunctionParameters {
2488 parameters: body.parameters().to_string(),
2489 });
2490 }
2491 let mut identifier = Identifier::new(name.token().to_string());
2492 if self.hold_token_data {
2493 identifier.set_token(self.convert_token(name)?);
2494 }
2495
2496 if let Some(type_specifier) = type_specifier {
2497 let type_value = self.pop_type()?;
2498 let mut typed_identifier =
2499 TypedIdentifier::from(identifier).with_type(type_value);
2500 if self.hold_token_data {
2501 typed_identifier
2502 .set_colon_token(self.convert_token(type_specifier.punctuation())?);
2503 }
2504 builder.push_parameter(typed_identifier);
2505 } else {
2506 builder.push_parameter(identifier.into());
2507 }
2508 }
2509 _ => {
2510 return Err(ConvertError::FunctionParameter {
2511 parameter: param.to_string(),
2512 })
2513 }
2514 }
2515 }
2516
2517 if let Some(generics) = body.generics() {
2518 let generic_parameters = self.convert_generic_type_parameters(generics)?;
2519 builder.set_generic_parameters(generic_parameters);
2520 }
2521
2522 if self.hold_token_data {
2523 let (open, close) =
2524 self.extract_contained_span_tokens(body.parameters_parentheses())?;
2525
2526 builder.set_parentheses_tokens(open, close);
2527 builder.set_parameter_commas(self.extract_tokens_from_punctuation(body.parameters())?);
2528 builder.set_function_token(function_token);
2529 builder.set_end_token(self.convert_token(body.end_token())?);
2530 }
2531
2532 Ok(builder)
2533 }
2534
2535 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2536 fn convert_string_expression(
2537 &self,
2538 string: &tokenizer::TokenReference,
2539 ) -> Result<StringExpression, ConvertError> {
2540 let mut expression =
2541 StringExpression::new(&string.token().to_string()).map_err(|_err| {
2542 ConvertError::String {
2543 string: string.to_string(),
2544 }
2545 })?;
2546
2547 if self.hold_token_data {
2548 expression.set_token(self.convert_token(string)?);
2549 }
2550 Ok(expression)
2551 }
2552
2553 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2554 fn convert_string_type(
2555 &self,
2556 string: &tokenizer::TokenReference,
2557 ) -> Result<StringType, ConvertError> {
2558 let mut expression =
2559 StringType::new(&string.token().to_string()).map_err(|_err| ConvertError::String {
2560 string: string.to_string(),
2561 })?;
2562 if self.hold_token_data {
2563 expression.set_token(self.convert_token(string)?);
2564 }
2565 Ok(expression)
2566 }
2567
2568 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2569 fn convert_binop(&self, operator: &ast::BinOp) -> Result<BinaryOperator, ConvertError> {
2570 Ok(match operator {
2571 ast::BinOp::And(_) => BinaryOperator::And,
2572 ast::BinOp::Caret(_) => BinaryOperator::Caret,
2573 ast::BinOp::GreaterThan(_) => BinaryOperator::GreaterThan,
2574 ast::BinOp::GreaterThanEqual(_) => BinaryOperator::GreaterOrEqualThan,
2575 ast::BinOp::LessThan(_) => BinaryOperator::LowerThan,
2576 ast::BinOp::LessThanEqual(_) => BinaryOperator::LowerOrEqualThan,
2577 ast::BinOp::Minus(_) => BinaryOperator::Minus,
2578 ast::BinOp::Or(_) => BinaryOperator::Or,
2579 ast::BinOp::Percent(_) => BinaryOperator::Percent,
2580 ast::BinOp::Plus(_) => BinaryOperator::Plus,
2581 ast::BinOp::Slash(_) => BinaryOperator::Slash,
2582 ast::BinOp::DoubleSlash(_) => BinaryOperator::DoubleSlash,
2583 ast::BinOp::Star(_) => BinaryOperator::Asterisk,
2584 ast::BinOp::TildeEqual(_) => BinaryOperator::NotEqual,
2585 ast::BinOp::TwoDots(_) => BinaryOperator::Concat,
2586 ast::BinOp::TwoEqual(_) => BinaryOperator::Equal,
2587 _ => {
2588 return Err(ConvertError::BinaryOperator {
2589 operator: operator.to_string(),
2590 })
2591 }
2592 })
2593 }
2594
2595 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2596 fn convert_unop(&self, operator: &ast::UnOp) -> Result<UnaryOperator, ConvertError> {
2597 Ok(match operator {
2598 ast::UnOp::Minus(_) => UnaryOperator::Minus,
2599 ast::UnOp::Not(_) => UnaryOperator::Not,
2600 ast::UnOp::Hash(_) => UnaryOperator::Length,
2601 _ => {
2602 return Err(ConvertError::UnaryOperator {
2603 operator: operator.to_string(),
2604 })
2605 }
2606 })
2607 }
2608
2609 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2610 fn convert_compound_op(
2611 &self,
2612 operator: &ast::luau::CompoundOp,
2613 ) -> Result<CompoundOperator, ConvertError> {
2614 Ok(match operator {
2615 ast::luau::CompoundOp::PlusEqual(_) => CompoundOperator::Plus,
2616 ast::luau::CompoundOp::MinusEqual(_) => CompoundOperator::Minus,
2617 ast::luau::CompoundOp::StarEqual(_) => CompoundOperator::Asterisk,
2618 ast::luau::CompoundOp::SlashEqual(_) => CompoundOperator::Slash,
2619 ast::luau::CompoundOp::DoubleSlashEqual(_) => CompoundOperator::DoubleSlash,
2620 ast::luau::CompoundOp::PercentEqual(_) => CompoundOperator::Percent,
2621 ast::luau::CompoundOp::CaretEqual(_) => CompoundOperator::Caret,
2622 ast::luau::CompoundOp::TwoDotsEqual(_) => CompoundOperator::Concat,
2623 _ => {
2624 return Err(ConvertError::CompoundOperator {
2625 operator: operator.to_string(),
2626 })
2627 }
2628 })
2629 }
2630
2631 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2632 fn convert_function_name(
2633 &self,
2634 name: &ast::FunctionName,
2635 ) -> Result<FunctionName, ConvertError> {
2636 let mut name_iter = name
2637 .names()
2638 .iter()
2639 .map(|token_ref| self.convert_token_to_identifier(token_ref));
2640
2641 let mut function_name = FunctionName::new(
2642 name_iter
2643 .next()
2644 .transpose()?
2645 .ok_or(ConvertError::ExpectedFunctionName)?,
2646 name_iter.collect::<Result<Vec<_>, _>>()?,
2647 name.method_name()
2648 .map(|token_ref| self.convert_token_to_identifier(token_ref))
2649 .transpose()?,
2650 );
2651
2652 if self.hold_token_data {
2653 function_name.set_tokens(FunctionNameTokens {
2654 periods: self.extract_tokens_from_punctuation(name.names())?,
2655 colon: name
2656 .method_colon()
2657 .map(|colon| self.convert_token(colon))
2658 .transpose()?,
2659 });
2660 }
2661
2662 Ok(function_name)
2663 }
2664
2665 #[cfg_attr(feature = "tracing", tracing::instrument(level = "trace", skip_all))]
2666 fn convert_variable(&mut self, variable: &'a ast::Var) -> Result<(), ConvertError> {
2667 match variable {
2668 ast::Var::Expression(var_expression) => {
2669 self.work_stack.push(ConvertWork::MakeVariable {
2670 variable: var_expression,
2671 });
2672 self.push_work(var_expression.prefix());
2673 self.convert_suffixes(var_expression.suffixes())?;
2674 }
2675 ast::Var::Name(name) => {
2676 self.work_stack.push(ConvertWork::PushVariable(
2677 self.convert_token_to_identifier(name)?.into(),
2678 ));
2679 }
2680 _ => {
2681 return Err(ConvertError::Variable {
2682 variable: variable.to_string(),
2683 })
2684 }
2685 }
2686 Ok(())
2687 }
2688
2689 fn convert_string_interpolation_segment(
2690 &self,
2691 token: &tokenizer::TokenReference,
2692 ) -> Result<Option<StringSegment>, ConvertError> {
2693 match token.token_type() {
2694 TokenType::InterpolatedString { literal, kind: _ } => {
2695 if !literal.is_empty() {
2696 let mut segment = StringSegment::new(literal.as_str())
2697 .expect("unable to convert interpolated string segment");
2698
2699 if self.hold_token_data {
2700 let position = self.convert_token_position(token)?;
2701 let segment_token = Token::new_with_line(
2702 position.0.saturating_add(1),
2703 position.1.saturating_sub(1),
2704 position.2,
2705 );
2706 segment.set_token(segment_token);
2708 }
2709
2710 Ok(Some(segment))
2711 } else {
2712 Ok(None)
2713 }
2714 }
2715 _ => unreachable!(),
2716 }
2717 }
2718}
2719
2720fn is_argument_variadic(mut r#type: &ast::luau::TypeInfo) -> bool {
2721 use ast::luau::TypeInfo;
2722 loop {
2723 match r#type {
2724 TypeInfo::GenericPack { .. }
2725 | TypeInfo::Variadic { .. }
2726 | TypeInfo::VariadicPack { .. } => break true,
2727 TypeInfo::Optional { base, .. } => {
2728 r#type = base;
2729 }
2730 TypeInfo::Intersection(intersection) => {
2731 r#type = intersection
2732 .types()
2733 .first()
2734 .expect("intersection should have at least one type")
2735 .value();
2736 }
2737 TypeInfo::Union(union_type) => {
2738 r#type = union_type
2739 .types()
2740 .first()
2741 .expect("union should have at least one type")
2742 .value();
2743 }
2744 _ => break false,
2745 }
2746 }
2747}
2748
2749fn is_variadic_type(mut r#type: &ast::luau::TypeInfo) -> Option<&tokenizer::TokenReference> {
2750 use ast::luau::TypeInfo;
2751 loop {
2752 match r#type {
2753 TypeInfo::Variadic { ellipsis, .. } | TypeInfo::VariadicPack { ellipsis, .. } => {
2754 break Some(ellipsis)
2755 }
2756 TypeInfo::Optional { base: left, .. } => {
2757 r#type = left;
2758 }
2759 TypeInfo::Intersection(intersection) => {
2760 r#type = intersection
2761 .types()
2762 .first()
2763 .expect("at least one type")
2764 .value();
2765 }
2766 TypeInfo::Union(union_type) => {
2767 r#type = union_type
2768 .types()
2769 .first()
2770 .expect("at least one type")
2771 .value();
2772 }
2773 _ => break None,
2774 }
2775 }
2776}
2777
2778#[derive(Debug)]
2779enum ConvertWork<'a> {
2780 Block(&'a ast::Block),
2781 Statement(&'a ast::Stmt),
2782 LastStatement(&'a ast::LastStmt),
2783 Expression(&'a ast::Expression),
2784 Prefix(&'a ast::Prefix),
2785 Arguments(&'a ast::FunctionArgs),
2786 TypeInfo(&'a ast::luau::TypeInfo),
2787 PushExpression(Expression),
2788 PushVariable(Variable),
2789 PushType(Type),
2790 MakeBlock {
2791 block: &'a ast::Block,
2792 },
2793 MakeDoStatement {
2794 statement: &'a ast::Do,
2795 },
2796 MakeReturn {
2797 statement: &'a ast::Return,
2798 },
2799 MakeBinaryExpression {
2800 operator: &'a ast::BinOp,
2801 },
2802 MakeUnaryExpression {
2803 operator: &'a ast::UnOp,
2804 },
2805 MakeParentheseExpression {
2806 contained_span: &'a ast::span::ContainedSpan,
2807 },
2808 MakeIfExpression {
2809 if_expression: &'a ast::luau::IfExpression,
2810 },
2811 MakeFunctionExpression {
2812 body: &'a ast::FunctionBody,
2813 token: &'a tokenizer::TokenReference,
2814 },
2815 MakeRepeatStatement {
2816 statement: &'a ast::Repeat,
2817 },
2818 MakeWhileStatement {
2819 statement: &'a ast::While,
2820 },
2821 MakeNumericForStatement {
2822 statement: &'a ast::NumericFor,
2823 },
2824 MakeGenericForStatement {
2825 statement: &'a ast::GenericFor,
2826 },
2827 MakeFunctionDeclaration {
2828 statement: &'a ast::FunctionDeclaration,
2829 },
2830 MakeFunctionCallExpression {
2831 call: &'a ast::FunctionCall,
2832 },
2833 MakeFunctionCallStatement {
2834 call: &'a ast::FunctionCall,
2835 },
2836 MakeTypeDeclarationStatement {
2837 type_declaration: &'a ast::luau::TypeDeclaration,
2838 export_token: Option<&'a tokenizer::TokenReference>,
2839 },
2840 MakePrefixFromExpression {
2841 prefix: &'a ast::Prefix,
2842 },
2843 MakeLocalFunctionStatement {
2844 statement: &'a ast::LocalFunction,
2845 },
2846 MakeLocalAssignStatement {
2847 statement: &'a ast::LocalAssignment,
2848 },
2849 MakeAssignStatement {
2850 statement: &'a ast::Assignment,
2851 },
2852 MakeCompoundAssignStatement {
2853 statement: &'a ast::luau::CompoundAssignment,
2854 },
2855 MakeIfStatement {
2856 statement: &'a ast::If,
2857 },
2858 MakeArgumentsFromExpressions {
2859 arguments: &'a ast::punctuated::Punctuated<ast::Expression>,
2860 parentheses: &'a ast::span::ContainedSpan,
2861 },
2862 MakeArgumentsFromTableEntries {
2863 table: &'a ast::TableConstructor,
2864 },
2865 MakeTableExpression {
2866 table: &'a ast::TableConstructor,
2867 },
2868 MakeVariable {
2869 variable: &'a ast::VarExpression,
2870 },
2871 MakePrefixExpression {
2872 variable: &'a ast::VarExpression,
2873 },
2874 MakeInterpolatedString {
2875 interpolated_string: &'a ast::luau::InterpolatedString,
2876 },
2877 MakeFunctionReturnType {
2878 type_info: &'a ast::luau::TypeInfo,
2879 },
2880 MakeVariadicTypePack {
2881 ellipsis: &'a tokenizer::TokenReference,
2882 },
2883 MakeArrayType {
2884 braces: &'a ast::span::ContainedSpan,
2885 },
2886 MakeOptionalType {
2887 question_mark: &'a tokenizer::TokenReference,
2888 },
2889 MakeUnionType {
2890 length: usize,
2891 leading_token: Option<&'a tokenizer::TokenReference>,
2892 separators: &'a ast::punctuated::Punctuated<ast::luau::TypeInfo>,
2893 },
2894 MakeIntersectionType {
2895 length: usize,
2896 leading_token: Option<&'a tokenizer::TokenReference>,
2897 separators: &'a ast::punctuated::Punctuated<ast::luau::TypeInfo>,
2898 },
2899 MakeTableType {
2900 braces: &'a ast::span::ContainedSpan,
2901 fields: &'a ast::punctuated::Punctuated<ast::luau::TypeField>,
2902 },
2903 MakeExpressionType {
2904 typeof_token: &'a tokenizer::TokenReference,
2905 parentheses: &'a ast::span::ContainedSpan,
2906 },
2907 MakeFunctionType {
2908 generics: &'a Option<ast::luau::GenericDeclaration>,
2909 parentheses: &'a ast::span::ContainedSpan,
2910 arguments: &'a ast::punctuated::Punctuated<ast::luau::TypeArgument>,
2911 arrow: &'a tokenizer::TokenReference,
2912 },
2913 MakeGenericType {
2914 base: &'a tokenizer::TokenReference,
2915 module: Option<(&'a tokenizer::TokenReference, &'a tokenizer::TokenReference)>,
2916 },
2917 MakeTypeParameters {
2918 arrows: &'a ast::span::ContainedSpan,
2919 generics: &'a ast::punctuated::Punctuated<ast::luau::TypeInfo>,
2920 },
2921 MakeTypeCast {
2922 type_assertion: &'a ast::luau::TypeAssertion,
2923 },
2924 MakeParentheseType {
2925 parentheses: &'a ast::span::ContainedSpan,
2926 },
2927 MakeTypePack {
2928 parentheses: &'a ast::span::ContainedSpan,
2929 types: &'a ast::punctuated::Punctuated<ast::luau::TypeInfo>,
2930 },
2931}
2932
2933impl<'a> From<&'a ast::Block> for ConvertWork<'a> {
2934 fn from(block: &'a ast::Block) -> Self {
2935 ConvertWork::Block(block)
2936 }
2937}
2938
2939impl<'a> From<&'a ast::Stmt> for ConvertWork<'a> {
2940 fn from(statement: &'a ast::Stmt) -> Self {
2941 ConvertWork::Statement(statement)
2942 }
2943}
2944
2945impl<'a> From<&'a ast::LastStmt> for ConvertWork<'a> {
2946 fn from(statement: &'a ast::LastStmt) -> Self {
2947 ConvertWork::LastStatement(statement)
2948 }
2949}
2950
2951impl<'a> From<&'a ast::Expression> for ConvertWork<'a> {
2952 fn from(expression: &'a ast::Expression) -> Self {
2953 ConvertWork::Expression(expression)
2954 }
2955}
2956
2957impl<'a> From<&'a ast::Prefix> for ConvertWork<'a> {
2958 fn from(prefix: &'a ast::Prefix) -> Self {
2959 ConvertWork::Prefix(prefix)
2960 }
2961}
2962
2963impl<'a> From<&'a ast::FunctionArgs> for ConvertWork<'a> {
2964 fn from(arguments: &'a ast::FunctionArgs) -> Self {
2965 ConvertWork::Arguments(arguments)
2966 }
2967}
2968
2969impl<'a> From<&'a ast::luau::TypeInfo> for ConvertWork<'a> {
2970 fn from(type_info: &'a ast::luau::TypeInfo) -> Self {
2971 ConvertWork::TypeInfo(type_info)
2972 }
2973}
2974
2975#[derive(Clone, Debug)]
2976pub(crate) enum ConvertError {
2977 Statement {
2978 statement: String,
2979 },
2980 LastStatement {
2981 statement: String,
2982 },
2983 Variable {
2984 variable: String,
2985 },
2986 FunctionArguments {
2987 arguments: String,
2988 },
2989 Call {
2990 call: String,
2991 },
2992 Index {
2993 index: String,
2994 },
2995 Suffix {
2996 suffix: String,
2997 },
2998 Prefix {
2999 prefix: String,
3000 },
3001 Number {
3002 number: String,
3003 parsing_error: String,
3004 },
3005 Expression {
3006 expression: String,
3007 },
3008 FunctionParameter {
3009 parameter: String,
3010 },
3011 FunctionParameters {
3012 parameters: String,
3013 },
3014 TableEntry {
3015 entry: String,
3016 },
3017 BinaryOperator {
3018 operator: String,
3019 },
3020 CompoundOperator {
3021 operator: String,
3022 },
3023 UnaryOperator {
3024 operator: String,
3025 },
3026 InterpolatedString {
3027 string: String,
3028 },
3029 String {
3030 string: String,
3031 },
3032 TypeInfo {
3033 type_info: String,
3034 },
3035 TableTypeProperty {
3036 property: String,
3037 },
3038 GenericDeclaration {
3039 generics: String,
3040 },
3041 UnexpectedTrivia(tokenizer::TokenKind),
3042 ExpectedFunctionName,
3043 TokenPositionNotFound {
3044 token: String,
3045 },
3046 InternalStack {
3047 kind: &'static str,
3048 },
3049}
3050
3051impl fmt::Display for ConvertError {
3052 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3053 let (kind, code) = match self {
3054 ConvertError::Statement { statement } => ("statement", statement),
3055 ConvertError::LastStatement { statement } => ("last statement", statement),
3056 ConvertError::Variable { variable } => ("variable", variable),
3057 ConvertError::FunctionArguments { arguments } => ("function arguments", arguments),
3058 ConvertError::Call { call } => ("function call", call),
3059 ConvertError::Index { index } => ("index expression", index),
3060 ConvertError::Suffix { suffix } => ("suffix", suffix),
3061 ConvertError::Prefix { prefix } => ("prefix", prefix),
3062 ConvertError::Number {
3063 number,
3064 parsing_error,
3065 } => {
3066 return write!(
3067 f,
3068 "unable to convert number from `{}` ({})",
3069 number, parsing_error
3070 )
3071 }
3072 ConvertError::InterpolatedString { string } => ("interpolated string", string),
3073 ConvertError::Expression { expression } => ("expression", expression),
3074 ConvertError::FunctionParameter { parameter } => ("parameter", parameter),
3075 ConvertError::FunctionParameters { parameters } => ("parameters", parameters),
3076 ConvertError::TableEntry { entry } => ("table entry", entry),
3077 ConvertError::BinaryOperator { operator } => ("binary operator", operator),
3078 ConvertError::CompoundOperator { operator } => ("compound operator", operator),
3079 ConvertError::UnaryOperator { operator } => ("unary operator", operator),
3080 ConvertError::String { string } => ("string", string),
3081 ConvertError::TypeInfo { type_info } => ("type", type_info),
3082 ConvertError::TableTypeProperty { property } => ("table type property", property),
3083 ConvertError::GenericDeclaration { generics } => ("generics", generics),
3084 ConvertError::UnexpectedTrivia(token_kind) => {
3085 return write!(
3086 f,
3087 "unable to convert trivia from token kind `{:?}`",
3088 token_kind
3089 );
3090 }
3091 ConvertError::ExpectedFunctionName => {
3092 return write!(f, "unable to convert empty function name");
3093 }
3094 ConvertError::TokenPositionNotFound { token } => {
3095 return write!(
3096 f,
3097 "unable to convert token '{}' because its position is missing",
3098 token
3099 );
3100 }
3101 ConvertError::InternalStack { kind } => {
3102 return write!(
3103 f,
3104 "internal conversion stack expected to find an item of `{}`",
3105 kind
3106 )
3107 }
3108 };
3109 write!(f, "unable to convert {} from `{}`", kind, code)
3110 }
3111}
3112
3113fn get_binary_operator_token(
3114 operator: &ast::BinOp,
3115) -> Result<&tokenizer::TokenReference, ConvertError> {
3116 use ast::BinOp;
3117
3118 match operator {
3119 BinOp::And(token)
3120 | BinOp::Caret(token)
3121 | BinOp::GreaterThan(token)
3122 | BinOp::GreaterThanEqual(token)
3123 | BinOp::LessThan(token)
3124 | BinOp::LessThanEqual(token)
3125 | BinOp::Minus(token)
3126 | BinOp::Or(token)
3127 | BinOp::Percent(token)
3128 | BinOp::Plus(token)
3129 | BinOp::Slash(token)
3130 | BinOp::DoubleSlash(token)
3131 | BinOp::Star(token)
3132 | BinOp::TildeEqual(token)
3133 | BinOp::TwoDots(token)
3134 | BinOp::TwoEqual(token) => Ok(token),
3135 _ => Err(ConvertError::BinaryOperator {
3136 operator: operator.to_string(),
3137 }),
3138 }
3139}
3140
3141fn get_unary_operator_token(
3142 operator: &ast::UnOp,
3143) -> Result<&tokenizer::TokenReference, ConvertError> {
3144 use ast::UnOp;
3145
3146 match operator {
3147 UnOp::Minus(token) | UnOp::Not(token) | UnOp::Hash(token) => Ok(token),
3148 _ => Err(ConvertError::UnaryOperator {
3149 operator: operator.to_string(),
3150 }),
3151 }
3152}
3153
3154fn get_compound_operator_token(
3155 operator: &ast::luau::CompoundOp,
3156) -> Result<&tokenizer::TokenReference, ConvertError> {
3157 use ast::luau::CompoundOp;
3158
3159 match operator {
3160 CompoundOp::PlusEqual(token)
3161 | CompoundOp::MinusEqual(token)
3162 | CompoundOp::StarEqual(token)
3163 | CompoundOp::SlashEqual(token)
3164 | CompoundOp::DoubleSlashEqual(token)
3165 | CompoundOp::PercentEqual(token)
3166 | CompoundOp::CaretEqual(token)
3167 | CompoundOp::TwoDotsEqual(token) => Ok(token),
3168 _ => Err(ConvertError::CompoundOperator {
3169 operator: operator.to_string(),
3170 }),
3171 }
3172}
3173
3174#[cfg(test)]
3175mod test {
3176 use super::*;
3177
3178 mod convert_error {
3179 use super::*;
3180
3181 #[test]
3182 fn display_unexpected_trivia_symbol() {
3183 assert_eq!(
3184 ConvertError::UnexpectedTrivia(tokenizer::TokenKind::Symbol).to_string(),
3185 "unable to convert trivia from token kind `Symbol`"
3186 )
3187 }
3188
3189 #[test]
3190 fn display_unexpected_trivia_eof() {
3191 assert_eq!(
3192 ConvertError::UnexpectedTrivia(tokenizer::TokenKind::Eof).to_string(),
3193 "unable to convert trivia from token kind `Eof`"
3194 )
3195 }
3196 }
3197}