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