1 //! Contains the types necessary to parse [Roblox's typed Lua](https://devforum.roblox.com/t/luau-type-checking-beta/435382).
2 //! Only usable when the "roblox" feature flag is enabled.
3 use super::{punctuated::Punctuated, span::ContainedSpan, *};
4 use crate::{util::display_option, ShortString};
5 use derive_more::Display;
6 
7 /// Any type, such as `string`, `boolean?`, `number | boolean`, etc.
8 #[derive(Clone, Debug, Display, PartialEq, Node)]
9 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
10 #[non_exhaustive]
11 pub enum TypeInfo {
12     /// A shorthand type annotating the structure of an array: { number }
13     #[display(fmt = "{}{}{}", "braces.tokens().0", "type_info", "braces.tokens().1")]
14     Array {
15         /// The braces (`{}`) containing the type info.
16         braces: ContainedSpan,
17         /// The type info for the values in the Array
18         type_info: Box<TypeInfo>,
19     },
20 
21     /// A standalone type, such as `string` or `Foo`.
22     #[display(fmt = "{}", "_0")]
23     Basic(TokenReference),
24 
25     /// A callback type, such as `(string, number) => boolean`.
26     #[display(
27         fmt = "{}{}{}{}{}",
28         "parentheses.tokens().0",
29         "arguments",
30         "parentheses.tokens().1",
31         "arrow",
32         "return_type"
33     )]
34     Callback {
35         /// The parentheses for the arguments.
36         parentheses: ContainedSpan,
37         /// The argument types: `(string, number)`.
38         arguments: Punctuated<TypeArgument>,
39         /// The "thin arrow" (`->`) in between the arguments and the return type.
40         arrow: TokenReference,
41         /// The return type: `boolean`.
42         return_type: Box<TypeInfo>,
43     },
44 
45     /// A type using generics, such as `map<number, string>`.
46     #[display(
47         fmt = "{}{}{}{}",
48         "base",
49         "arrows.tokens().0",
50         "generics",
51         "arrows.tokens().1"
52     )]
53     Generic {
54         /// The type that has generics: `map`.
55         base: TokenReference,
56         /// The arrows (`<>`) containing the type parameters.
57         arrows: ContainedSpan,
58         /// The type parameters: `number, string`.
59         generics: Punctuated<TypeInfo>,
60     },
61 
62     /// An intersection type: `string & number`, denoting both types.
63     #[display(fmt = "{}{}{}", "left", "ampersand", "right")]
64     Intersection {
65         /// The left hand side: `string`.
66         left: Box<TypeInfo>,
67         /// The ampersand (`&`) to separate the types.
68         ampersand: TokenReference,
69         /// The right hand side: `number`.
70         right: Box<TypeInfo>,
71     },
72 
73     /// A type coming from a module, such as `module.Foo`
74     #[display(fmt = "{}{}{}", "module", "punctuation", "type_info")]
75     Module {
76         /// The module the type is coming from: `module`.
77         module: TokenReference,
78         /// The punctuation (`.`) to index the module.
79         punctuation: TokenReference,
80         /// The indexed type info: `Foo`.
81         type_info: Box<IndexedTypeInfo>,
82     },
83 
84     /// An optional type, such as `string?`.
85     #[display(fmt = "{}{}", "base", "question_mark")]
86     Optional {
87         /// The type that is optional: `string`.
88         base: Box<TypeInfo>,
89         /// The question mark: `?`.
90         question_mark: TokenReference,
91     },
92 
93     /// A type annotating the structure of a table: { foo: number, bar: string }
94     #[display(fmt = "{}{}{}", "braces.tokens().0", "fields", "braces.tokens().1")]
95     Table {
96         /// The braces (`{}`) containing the fields.
97         braces: ContainedSpan,
98         /// The fields: `foo: number, bar: string`.
99         fields: Punctuated<TypeField>,
100     },
101 
102     /// A type in the form of `typeof(foo)`.
103     #[display(
104         fmt = "{}{}{}{}",
105         "typeof_token",
106         "parentheses.tokens().0",
107         "inner",
108         "parentheses.tokens().1"
109     )]
110     Typeof {
111         /// The token `typeof`.
112         typeof_token: TokenReference,
113         /// The parentheses used to contain the expression.
114         parentheses: ContainedSpan,
115         /// The inner expression: `foo`.
116         inner: Box<Expression>,
117     },
118 
119     /// A tuple expression: `(string, number)`.
120     #[display(
121         fmt = "{}{}{}",
122         "parentheses.tokens().0",
123         "types",
124         "parentheses.tokens().1"
125     )]
126     Tuple {
127         /// The parentheses used to contain the types
128         parentheses: ContainedSpan,
129         /// The types: `(string, number)`.
130         types: Punctuated<TypeInfo>,
131     },
132 
133     /// A union type: `string | number`, denoting one or the other.
134     #[display(fmt = "{}{}{}", "left", "pipe", "right")]
135     Union {
136         /// The left hand side: `string`.
137         left: Box<TypeInfo>,
138         /// The pipe (`|`) to separate the types.
139         pipe: TokenReference,
140         /// The right hand side: `number`.
141         right: Box<TypeInfo>,
142     },
143 
144     /// A variadic type: `...number`.
145     #[display(fmt = "{}{}", "ellipse", "type_info")]
146     Variadic {
147         /// The ellipse: `...`.
148         ellipse: TokenReference,
149         /// The type that is variadic: `number`.
150         type_info: Box<TypeInfo>,
151     },
152 }
153 
154 /// A subset of TypeInfo that consists of items which can only be used as an index, such as `Foo` and `Foo<Bar>`,
155 #[derive(Clone, Debug, Display, PartialEq, Node)]
156 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
157 #[non_exhaustive]
158 pub enum IndexedTypeInfo {
159     /// A standalone type, such as `string` or `Foo`.
160     #[display(fmt = "{}", "_0")]
161     Basic(TokenReference),
162 
163     /// A type using generics, such as `map<number, string>`.
164     #[display(
165         fmt = "{}{}{}{}",
166         "base",
167         "arrows.tokens().0",
168         "generics",
169         "arrows.tokens().1"
170     )]
171     Generic {
172         /// The type that has generics: `map`.
173         base: TokenReference,
174         /// The arrows (`<>`) containing the type parameters.
175         arrows: ContainedSpan,
176         /// The type parameters: `number, string`.
177         generics: Punctuated<TypeInfo>,
178     },
179 }
180 
181 /// A type field used within table types.
182 /// The `foo: number` in `{ foo: number }`.
183 #[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
184 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
185 #[display(fmt = "{}{}{}", "key", "colon", "value")]
186 pub struct TypeField {
187     pub(crate) key: TypeFieldKey,
188     pub(crate) colon: TokenReference,
189     pub(crate) value: TypeInfo,
190 }
191 
192 impl TypeField {
193     /// Creates a new TypeField from the given key and value
new(key: TypeFieldKey, value: TypeInfo) -> Self194     pub fn new(key: TypeFieldKey, value: TypeInfo) -> Self {
195         Self {
196             key,
197             colon: TokenReference::symbol(": ").unwrap(),
198             value,
199         }
200     }
201 
202     /// The key of the field, `foo` in `foo: number`.
key(&self) -> &TypeFieldKey203     pub fn key(&self) -> &TypeFieldKey {
204         &self.key
205     }
206 
207     /// The colon in between the key name and the value type.
colon_token(&self) -> &TokenReference208     pub fn colon_token(&self) -> &TokenReference {
209         &self.colon
210     }
211 
212     /// The type for the field, `number` in `foo: number`.
value(&self) -> &TypeInfo213     pub fn value(&self) -> &TypeInfo {
214         &self.value
215     }
216 
217     /// Returns a new TypeField with the given key
with_key(self, key: TypeFieldKey) -> Self218     pub fn with_key(self, key: TypeFieldKey) -> Self {
219         Self { key, ..self }
220     }
221 
222     /// Returns a new TypeField with the `:` token
with_colon_token(self, colon_token: TokenReference) -> Self223     pub fn with_colon_token(self, colon_token: TokenReference) -> Self {
224         Self {
225             colon: colon_token,
226             ..self
227         }
228     }
229 
230     /// Returns a new TypeField with the `:` token
with_value(self, value: TypeInfo) -> Self231     pub fn with_value(self, value: TypeInfo) -> Self {
232         Self { value, ..self }
233     }
234 }
235 
236 /// A key in a [`TypeField`]. Can either be a name or an index signature.
237 #[derive(Clone, Debug, Display, PartialEq, Node)]
238 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
239 #[non_exhaustive]
240 pub enum TypeFieldKey {
241     /// A name, such as `foo`.
242     #[display(fmt = "{}", "_0")]
243     Name(TokenReference),
244 
245     /// An index signature, such as `[number]`.
246     #[display(fmt = "{}{}{}", "brackets.tokens().0", "inner", "brackets.tokens().1")]
247     IndexSignature {
248         /// The brackets (`[]`) used to contain the type.
249         brackets: ContainedSpan,
250 
251         /// The type for the index signature, `number` in `[number]`.
252         inner: TypeInfo,
253     },
254 }
255 
256 /// A type assertion using `::`, such as `:: number`.
257 #[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
258 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
259 #[display(fmt = "{}{}", "assertion_op", "cast_to")]
260 pub struct TypeAssertion {
261     pub(crate) assertion_op: TokenReference,
262     pub(crate) cast_to: TypeInfo,
263 }
264 
265 impl TypeAssertion {
266     /// Creates a new TypeAssertion from the given cast to TypeInfo
new(cast_to: TypeInfo) -> Self267     pub fn new(cast_to: TypeInfo) -> Self {
268         Self {
269             assertion_op: TokenReference::symbol("::").unwrap(),
270             cast_to,
271         }
272     }
273 
274     /// The token `::`.
assertion_op(&self) -> &TokenReference275     pub fn assertion_op(&self) -> &TokenReference {
276         &self.assertion_op
277     }
278 
279     /// The type to cast the expression into, `number` in `:: number`.
cast_to(&self) -> &TypeInfo280     pub fn cast_to(&self) -> &TypeInfo {
281         &self.cast_to
282     }
283 
284     /// Returns a new TypeAssertion with the given `::` token
with_assertion_op(self, assertion_op: TokenReference) -> Self285     pub fn with_assertion_op(self, assertion_op: TokenReference) -> Self {
286         Self {
287             assertion_op,
288             ..self
289         }
290     }
291 
292     /// Returns a new TypeAssertion with the given TypeInfo to cast to
with_cast_to(self, cast_to: TypeInfo) -> Self293     pub fn with_cast_to(self, cast_to: TypeInfo) -> Self {
294         Self { cast_to, ..self }
295     }
296 }
297 
298 /// A type declaration, such as `type Meters = number`
299 #[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
300 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
301 #[display(
302     fmt = "{}{}{}{}{}",
303     "type_token",
304     "base",
305     "display_option(generics)",
306     "equal_token",
307     "declare_as"
308 )]
309 pub struct TypeDeclaration {
310     pub(crate) type_token: TokenReference,
311     pub(crate) base: TokenReference,
312     pub(crate) generics: Option<GenericDeclaration>,
313     pub(crate) equal_token: TokenReference,
314     pub(crate) declare_as: TypeInfo,
315 }
316 
317 impl TypeDeclaration {
318     /// Creates a new TypeDeclaration from the given type name and type declaration
new(type_name: TokenReference, type_definition: TypeInfo) -> Self319     pub fn new(type_name: TokenReference, type_definition: TypeInfo) -> Self {
320         Self {
321             type_token: TokenReference::symbol("type ").unwrap(),
322             base: type_name,
323             generics: None,
324             equal_token: TokenReference::symbol(" = ").unwrap(),
325             declare_as: type_definition,
326         }
327     }
328 
329     /// The token `type`.
type_token(&self) -> &TokenReference330     pub fn type_token(&self) -> &TokenReference {
331         &self.type_token
332     }
333 
334     /// The name of the type, `Meters` in `type Meters = number`.
type_name(&self) -> &TokenReference335     pub fn type_name(&self) -> &TokenReference {
336         &self.base
337     }
338 
339     /// The generics of the type, if there are any. `<T>` in `type Foo<T> = T`.
generics(&self) -> Option<&GenericDeclaration>340     pub fn generics(&self) -> Option<&GenericDeclaration> {
341         self.generics.as_ref()
342     }
343 
344     /// The `=` token in between the type name and the definition.
equal_token(&self) -> &TokenReference345     pub fn equal_token(&self) -> &TokenReference {
346         &self.equal_token
347     }
348 
349     /// The definition of the type, `number` in `type Meters = number`.
type_definition(&self) -> &TypeInfo350     pub fn type_definition(&self) -> &TypeInfo {
351         &self.declare_as
352     }
353 
354     /// Returns a new TypeDeclaration with the given `type` token
with_type_token(self, type_token: TokenReference) -> Self355     pub fn with_type_token(self, type_token: TokenReference) -> Self {
356         Self { type_token, ..self }
357     }
358 
359     /// Returns a new TypeDeclaration with the given type name
with_type_name(self, type_name: TokenReference) -> Self360     pub fn with_type_name(self, type_name: TokenReference) -> Self {
361         Self {
362             base: type_name,
363             ..self
364         }
365     }
366 
367     /// Returns a new TypeDeclaration with the given generics of the type
with_generics(self, generics: Option<GenericDeclaration>) -> Self368     pub fn with_generics(self, generics: Option<GenericDeclaration>) -> Self {
369         Self { generics, ..self }
370     }
371 
372     /// Returns a new TypeDeclaration with the given generics of the type
with_equal_token(self, equal_token: TokenReference) -> Self373     pub fn with_equal_token(self, equal_token: TokenReference) -> Self {
374         Self {
375             equal_token,
376             ..self
377         }
378     }
379 
380     /// Returns a new TypeDeclaration with the given generics of the type
with_type_definition(self, type_definition: TypeInfo) -> Self381     pub fn with_type_definition(self, type_definition: TypeInfo) -> Self {
382         Self {
383             declare_as: type_definition,
384             ..self
385         }
386     }
387 }
388 
389 /// The generics used in a [`TypeDeclaration`].
390 #[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
391 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
392 #[display(fmt = "{}{}{}", "arrows.tokens().0", "generics", "arrows.tokens().1")]
393 pub struct GenericDeclaration {
394     #[visit(contains = "generics")]
395     pub(crate) arrows: ContainedSpan,
396     pub(crate) generics: Punctuated<TokenReference>,
397 }
398 
399 impl GenericDeclaration {
400     /// Creates a new GenericDeclaration
new() -> Self401     pub fn new() -> Self {
402         Self {
403             arrows: ContainedSpan::new(
404                 TokenReference::symbol("<").unwrap(),
405                 TokenReference::symbol(">").unwrap(),
406             ),
407             generics: Punctuated::new(),
408         }
409     }
410 
411     /// The arrows (`<>`) containing the types.
arrows(&self) -> &ContainedSpan412     pub fn arrows(&self) -> &ContainedSpan {
413         &self.arrows
414     }
415 
416     /// The names of the generics: `T, U` in `<T, U>`.
generics(&self) -> &Punctuated<TokenReference>417     pub fn generics(&self) -> &Punctuated<TokenReference> {
418         &self.generics
419     }
420 
421     /// Returns a new GenericDeclaration with the given arrows containing the types
with_arrows(self, arrows: ContainedSpan) -> Self422     pub fn with_arrows(self, arrows: ContainedSpan) -> Self {
423         Self { arrows, ..self }
424     }
425 
426     /// Returns a new TypeDeclaration with the given names of the generics
with_generics(self, generics: Punctuated<TokenReference>) -> Self427     pub fn with_generics(self, generics: Punctuated<TokenReference>) -> Self {
428         Self { generics, ..self }
429     }
430 }
431 
432 impl Default for GenericDeclaration {
default() -> Self433     fn default() -> Self {
434         Self::new()
435     }
436 }
437 
438 /// A type specifier, the `: number` in `local foo: number`
439 #[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
440 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
441 #[display(fmt = "{}{}", "punctuation", "type_info")]
442 pub struct TypeSpecifier {
443     pub(crate) punctuation: TokenReference,
444     pub(crate) type_info: TypeInfo,
445 }
446 
447 impl TypeSpecifier {
448     /// Creates a new TypeSpecifier with the given type info
new(type_info: TypeInfo) -> Self449     pub fn new(type_info: TypeInfo) -> Self {
450         Self {
451             punctuation: TokenReference::symbol(": ").unwrap(),
452             type_info,
453         }
454     }
455 
456     /// The punctuation being used.
457     /// `:` for `local foo: number`.
punctuation(&self) -> &TokenReference458     pub fn punctuation(&self) -> &TokenReference {
459         &self.punctuation
460     }
461 
462     /// The type being specified: `number` in `local foo: number`.
type_info(&self) -> &TypeInfo463     pub fn type_info(&self) -> &TypeInfo {
464         &self.type_info
465     }
466 
467     /// Returns a new TypeSpecifier with the given punctuation
with_punctuation(self, punctuation: TokenReference) -> Self468     pub fn with_punctuation(self, punctuation: TokenReference) -> Self {
469         Self {
470             punctuation,
471             ..self
472         }
473     }
474 
475     /// Returns a new TypeSpecifier with the given type being specified
with_type_info(self, type_info: TypeInfo) -> Self476     pub fn with_type_info(self, type_info: TypeInfo) -> Self {
477         Self { type_info, ..self }
478     }
479 }
480 
481 /// A type argument specified in a callback type, the `count: number` in `(count: number) -> ()`
482 #[derive(Clone, Debug, PartialEq, Node, Visit)]
483 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
484 pub struct TypeArgument {
485     pub(crate) name: Option<(TokenReference, TokenReference)>,
486     pub(crate) type_info: TypeInfo,
487 }
488 
489 impl TypeArgument {
490     /// Creates a new TypeArgument with the given type info
new(type_info: TypeInfo) -> Self491     pub fn new(type_info: TypeInfo) -> Self {
492         Self {
493             name: None,
494             type_info,
495         }
496     }
497 
498     /// The name of the argument split into identifier and punctuation: `count:` in `count: number`.
name(&self) -> Option<&(TokenReference, TokenReference)>499     pub fn name(&self) -> Option<&(TokenReference, TokenReference)> {
500         self.name.as_ref()
501     }
502 
503     /// The type info for the argument: `number` in `count: number`.
type_info(&self) -> &TypeInfo504     pub fn type_info(&self) -> &TypeInfo {
505         &self.type_info
506     }
507 
508     /// Returns a new TypeArgument with the given punctuation
with_name(self, name: Option<(TokenReference, TokenReference)>) -> Self509     pub fn with_name(self, name: Option<(TokenReference, TokenReference)>) -> Self {
510         Self { name, ..self }
511     }
512 
513     /// Returns a new TypeArgument with the given type info
with_type_info(self, type_info: TypeInfo) -> Self514     pub fn with_type_info(self, type_info: TypeInfo) -> Self {
515         Self { type_info, ..self }
516     }
517 }
518 
519 impl fmt::Display for TypeArgument {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result520     fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
521         if let Some((identifier, punctuation)) = self.name() {
522             write!(formatter, "{}{}{}", identifier, punctuation, self.type_info)
523         } else {
524             write!(formatter, "{}", self.type_info)
525         }
526     }
527 }
528 
529 /// An exported type declaration, such as `export type Meters = number`
530 #[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
531 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
532 #[display(fmt = "{}{}", "export_token", "type_declaration")]
533 pub struct ExportedTypeDeclaration {
534     pub(crate) export_token: TokenReference,
535     pub(crate) type_declaration: TypeDeclaration,
536 }
537 
538 impl ExportedTypeDeclaration {
539     /// Creates a new ExportedTypeDeclaration with the given type declaration
new(type_declaration: TypeDeclaration) -> Self540     pub fn new(type_declaration: TypeDeclaration) -> Self {
541         Self {
542             export_token: TokenReference::new(
543                 vec![],
544                 Token::new(TokenType::Identifier {
545                     identifier: ShortString::new("export"),
546                 }),
547                 vec![Token::new(TokenType::spaces(1))],
548             ),
549             type_declaration,
550         }
551     }
552 
553     /// The token `export`.
export_token(&self) -> &TokenReference554     pub fn export_token(&self) -> &TokenReference {
555         &self.export_token
556     }
557 
558     /// The type declaration, `type Meters = number`.
type_declaration(&self) -> &TypeDeclaration559     pub fn type_declaration(&self) -> &TypeDeclaration {
560         &self.type_declaration
561     }
562 
563     /// Returns a new ExportedTypeDeclaration with the `export` token
with_export_token(self, export_token: TokenReference) -> Self564     pub fn with_export_token(self, export_token: TokenReference) -> Self {
565         Self {
566             export_token,
567             ..self
568         }
569     }
570 
571     /// Returns a new TypeDeclaration with the given type declaration
with_type_declaration(self, type_declaration: TypeDeclaration) -> Self572     pub fn with_type_declaration(self, type_declaration: TypeDeclaration) -> Self {
573         Self {
574             type_declaration,
575             ..self
576         }
577     }
578 }
579 
580 make_op!(CompoundOp,
581     #[doc = "Compound operators, such as X += Y or X -= Y"]
582     {
583         PlusEqual,
584         MinusEqual,
585         StarEqual,
586         SlashEqual,
587         PercentEqual,
588         CaretEqual,
589         TwoDotsEqual,
590     }
591 );
592 
593 /// A Compound Assignment statement, such as `x += 1` or `x -= 1`
594 #[derive(Clone, Debug, Display, PartialEq, Node, Visit)]
595 #[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
596 #[display(fmt = "{}{}{}", "lhs", "compound_operator", "rhs")]
597 pub struct CompoundAssignment {
598     pub(crate) lhs: Var,
599     pub(crate) compound_operator: CompoundOp,
600     pub(crate) rhs: Expression,
601 }
602 
603 impl CompoundAssignment {
604     /// Creates a new CompoundAssignment from the left and right hand side
new(lhs: Var, compound_operator: CompoundOp, rhs: Expression) -> Self605     pub fn new(lhs: Var, compound_operator: CompoundOp, rhs: Expression) -> Self {
606         Self {
607             lhs,
608             compound_operator,
609             rhs,
610         }
611     }
612 
613     /// The variable assigned to, the `x` part of `x += 1`
lhs(&self) -> &Var614     pub fn lhs(&self) -> &Var {
615         &self.lhs
616     }
617 
618     /// The operator used, the `+=` part of `x += 1`
compound_operator(&self) -> &CompoundOp619     pub fn compound_operator(&self) -> &CompoundOp {
620         &self.compound_operator
621     }
622 
623     /// The value being assigned, the `1` part of `x += 1`
rhs(&self) -> &Expression624     pub fn rhs(&self) -> &Expression {
625         &self.rhs
626     }
627 
628     /// Returns a new CompoundAssignment with the given variable being assigned to
with_lhs(self, lhs: Var) -> Self629     pub fn with_lhs(self, lhs: Var) -> Self {
630         Self { lhs, ..self }
631     }
632 
633     /// Returns a new CompoundAssignment with the given operator used
with_compound_operator(self, compound_operator: CompoundOp) -> Self634     pub fn with_compound_operator(self, compound_operator: CompoundOp) -> Self {
635         Self {
636             compound_operator,
637             ..self
638         }
639     }
640 
641     /// Returns a new CompoundAssignment with the given value being assigned
with_rhs(self, rhs: Expression) -> Self642     pub fn with_rhs(self, rhs: Expression) -> Self {
643         Self { rhs, ..self }
644     }
645 }
646