1/* 2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS of ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16package std.core; 17 18export type TypeDesc = string 19 20/* 21 Type intrinsics 22*/ 23native function TypeAPIGetTypeDescriptor(o: NullishType): string 24 25native function TypeAPIGetTypeKind(td: TypeDesc): byte 26 27native function TypeAPIIsValueType(td: TypeDesc): boolean 28 29native function TypeAPIGetTypeName(td: TypeDesc): string 30 31native function TypeAPIGetTypeId(td: TypeDesc): long 32 33/* 34 Class type intrinsics 35*/ 36native function TypeAPIGetClassAttributes(td: TypeDesc): int 37 38native function TypeAPIGetFieldsNum(td: TypeDesc): long 39 40native function TypeAPIGetOwnFieldsNum(td: TypeDesc): long 41 42native function TypeAPIGetField(td: TypeDesc, i: long): Field 43 44native function TypeAPIGetOwnField(td: TypeDesc, i: long): Field 45 46native function TypeAPIGetFieldByName(td: TypeDesc, name: string): Field 47 48native function TypeAPIGetStaticFieldValue(ownerTD: TypeDesc, name: string): NullishType 49 50native function TypeAPIGetMethodsNum(td: TypeDesc): long 51 52native function TypeAPIGetMethod(td: TypeDesc, i: long): Method 53 54native function TypeAPIGetConstructorsNum(td: TypeDesc): long 55 56native function TypeAPIGetConstructor(td: TypeDesc, i: long): Method 57 58native function TypeAPIGetBaseType(td: TypeDesc): TypeDesc 59 60native function TypeAPIGetInterfacesNum(td: TypeDesc): long 61 62native function TypeAPIGetInterface(td: TypeDesc, i: long): TypeDesc 63 64native function TypeAPISetStaticFieldValue(ownerTD: TypeDesc, name: string, val: NullishType): void 65 66native function TypeAPIIsInheritedFrom(ltd: TypeDesc, rtd:TypeDesc): boolean 67 68/* 69 Function (Lambda or Method) type intrinsics 70*/ 71native function TypeAPIGetFunctionAttributes(td: TypeDesc): int 72 73native function TypeAPIGetReceiverType(td: TypeDesc): TypeDesc 74 75native function TypeAPIGetParametersNum(td: TypeDesc): long 76 77native function TypeAPIGetParameter(td: TypeDesc, i: long): Parameter 78 79native function TypeAPIGetResultType(td: TypeDesc): TypeDesc 80 81/* 82 Array type intrinsics 83*/ 84native function TypeAPIGetArrayElementType(td: TypeDesc): TypeDesc 85 86native function TypeAPIMakeArrayInstance(td: TypeDesc, len: long): Object 87 88// NOTE(shumilov-petr): replace to enum, enum not available now 89export class TypeKind { 90 public static readonly NONE: byte = 0x0 91 public static readonly VOID: byte = 0x1 92 93 public static readonly CHAR: byte = 0x2 94 public static readonly BOOLEAN: byte = 0x3 95 public static readonly BYTE: byte = 0x4 96 public static readonly SHORT: byte = 0x5 97 public static readonly INT: byte = 0x6 98 public static readonly LONG: byte = 0x7 99 public static readonly FLOAT: byte = 0x8 100 public static readonly DOUBLE: byte = 0x9 101 102 public static readonly CLASS: byte = 0xA 103 public static readonly STRING: byte = 0xB 104 public static readonly INTERFACE: byte = 0xC 105 public static readonly ARRAY: byte = 0xD 106 public static readonly TUPLE: byte = 0xE 107 public static readonly LAMBDA: byte = 0xF 108 public static readonly METHOD: byte = 0x10 109 110 public static readonly UNION: byte = 0x11 111 public static readonly UNDEFINED: byte = 0x12 112 public static readonly NULL: byte = 0x13 113 114 public static readonly ENUM: byte = 0x14 115 116 private constructor() {} 117} 118 119// 5 lower bits stores kind's id 120const TypeKindMask: byte = (1 << 6) - 1 121 122// NOTE(shumilov-petr): replace to enum, enum not available now 123export class ValueTypeDesc { 124 public static readonly BOOLEAN: TypeDesc = "Z" 125 public static readonly BYTE: TypeDesc = "B" 126 public static readonly SHORT: TypeDesc = "S" 127 public static readonly CHAR: TypeDesc = "C" 128 public static readonly INT: TypeDesc = "I" 129 public static readonly LONG: TypeDesc = "J" 130 public static readonly FLOAT: TypeDesc = "F" 131 public static readonly DOUBLE: TypeDesc = "D" 132} 133 134const ObjectTD = "Lstd/core/Object;" // NOTE(shumilov-petr): get td from runtime 135 136export const ObjectType: ClassType = new ClassType(ObjectTD) 137 138export class Attributes { 139 public static readonly STATIC: int = 1 << 0 // Field, Method 140 public static readonly INHERITED: int = 1 << 1 // Field, Method 141 public static readonly READONLY: int = 1 << 2 // Field 142 public static readonly FINAL: int = 1 << 3 // Method, Class 143 public static readonly ABSTRACT: int = 1 << 4 // Method 144 public static readonly CONSTRUCTOR: int = 1 << 5 // Method 145 public static readonly REST: int = 1 << 6 // Parameter 146 public static readonly OPTIONAL: int = 1 << 7 // Parameter 147 public static readonly THROWING: int = 1 << 8 // Method, Lambda 148 public static readonly NATIVE: int = 1 << 9 // Method, Lambda 149 public static readonly ASYNC: int = 1 << 10 // Method, Lambda 150 public static readonly NEVERRESULT: int = 1 << 11 // Method, Lambda 151 public static readonly GETTER: int = 1 << 12 // Method 152 public static readonly SETTER: int = 1 << 13 // Method 153 154 private constructor() {} 155} 156 157export class AccessModifier { 158 public static readonly PUBLIC: byte = 0 159 public static readonly PRIVATE: byte = 1 160 public static readonly PROTECTED: byte = 2 161 162 private constructor() {} 163} 164 165/** 166 * Runtime ArkTS type representation 167 */ 168export abstract class Type { 169 internal td: TypeDesc 170 171 172 /** 173 * Resolves type by descriptor 174 * 175 * @param td type descriptor 176 * 177 * @returns instance of appropriate type or null if resolving is failed 178 */ 179 public static resolve(td: TypeDesc): Type | null { 180 let kind = (TypeAPIGetTypeKind(td) & TypeKindMask) as byte 181 switch (kind) { 182 case TypeKind.NONE: 183 return null 184 case TypeKind.VOID: 185 return VoidType.REF 186 case TypeKind.CHAR: 187 return TypeAPIIsValueType(td) ? CharType.VAL : CharType.REF 188 case TypeKind.BOOLEAN: 189 return TypeAPIIsValueType(td) ? BooleanType.VAL : BooleanType.REF 190 case TypeKind.BYTE: 191 return TypeAPIIsValueType(td) ? ByteType.VAL : ByteType.REF 192 case TypeKind.SHORT: 193 return TypeAPIIsValueType(td) ? ShortType.VAL : ShortType.REF 194 case TypeKind.INT: 195 return TypeAPIIsValueType(td) ? IntType.VAL : IntType.REF 196 case TypeKind.LONG: 197 return TypeAPIIsValueType(td) ? LongType.VAL : LongType.REF 198 case TypeKind.FLOAT: 199 return TypeAPIIsValueType(td) ? FloatType.VAL : FloatType.REF 200 case TypeKind.DOUBLE: 201 return TypeAPIIsValueType(td) ? DoubleType.VAL : DoubleType.REF 202 203 case TypeKind.CLASS: 204 return new ClassType(td) 205 case TypeKind.STRING: 206 return StringType.REF 207 case TypeKind.INTERFACE: 208 return new InterfaceType(td) 209 case TypeKind.ARRAY: 210 return ArrayType.getInstance(td) 211 case TypeKind.TUPLE: 212 return new TupleType(td) 213 case TypeKind.LAMBDA: 214 return new LambdaType(td) 215 case TypeKind.METHOD: 216 return new MethodType(td) 217 case TypeKind.UNION: 218 return new UnionType(td) 219 case TypeKind.UNDEFINED: 220 return UndefinedType.REF 221 case TypeKind.NULL: 222 return NullType.REF 223 224 case TypeKind.ENUM: 225 return new EnumType(td) 226 default: 227 // NOTE(shumilov-petr): unknown type, need error 228 assert(false) 229 } 230 231 return null; 232 } 233 234 /** 235 * Returns Type of value 236 * 237 * @param v value 238 * 239 * @returns Type instance of this value 240 */ 241 public static of(v: boolean): Type { 242 return BooleanType.VAL 243 } 244 245 /** 246 * Returns Type of value 247 * 248 * @param v value 249 * 250 * @returns Type instance of this value 251 */ 252 public static of(v: char): Type { 253 return CharType.VAL 254 } 255 256 /** 257 * Returns Type of value 258 * 259 * @param v value 260 * 261 * @returns Type instance of this value 262 */ 263 public static of(v: byte): Type { 264 return ByteType.VAL 265 } 266 267 /** 268 * Returns Type of value 269 * 270 * @param v value 271 * 272 * @returns Type instance of this value 273 */ 274 public static of(v: short): Type { 275 return ShortType.VAL 276 } 277 278 /** 279 * Returns Type of value 280 * 281 * @param v value 282 * 283 * @returns Type instance of this value 284 */ 285 public static of(v: int): Type { 286 return IntType.VAL 287 } 288 289 /** 290 * Returns Type of value 291 * 292 * @param v value 293 * 294 * @returns Type instance of this value 295 */ 296 public static of(v: long): Type { 297 return LongType.VAL 298 } 299 300 /** 301 * Returns Type of value 302 * 303 * @param v value 304 * 305 * @returns Type instance of this value 306 */ 307 public static of(v: float): Type { 308 return FloatType.VAL 309 } 310 311 /** 312 * Returns Type of value 313 * 314 * @param v value 315 * 316 * @returns Type instance of this value 317 */ 318 public static of(v: double): Type { 319 return DoubleType.VAL 320 } 321 322 // ----- 323 324 public static of(o: NullishType): Type { 325 let td = TypeAPIGetTypeDescriptor(o) 326 return Type.resolve(td)! 327 } 328 329 // ----- 330 331 public static of(v: Boolean): Type { 332 return BooleanType.REF 333 } 334 335 /** 336 * Returns Type of value 337 * 338 * @param v value 339 * 340 * @returns Type instance of this value 341 */ 342 public static of(v: Char): Type { 343 return CharType.REF 344 } 345 346 /** 347 * Returns Type of value 348 * 349 * @param v value 350 * 351 * @returns Type instance of this value 352 */ 353 public static of(v: Byte): Type { 354 return ByteType.REF 355 } 356 357 /** 358 * Returns Type of value 359 * 360 * @param v value 361 * 362 * @returns Type instance of this value 363 */ 364 public static of(v: Short): Type { 365 return ShortType.REF 366 } 367 368 /** 369 * Returns Type of value 370 * 371 * @param v value 372 * 373 * @returns Type instance of this value 374 */ 375 public static of(v: Int): Type { 376 return IntType.REF 377 } 378 379 /** 380 * Returns Type of value 381 * 382 * @param v value 383 * 384 * @returns Type instance of this value 385 */ 386 public static of(v: Long): Type { 387 return LongType.REF 388 } 389 390 /** 391 * Returns Type of value 392 * 393 * @param v value 394 * 395 * @returns Type instance of this value 396 */ 397 public static of(v: Float): Type { 398 return FloatType.REF 399 } 400 401 /** 402 * Returns Type of value 403 * 404 * @param v value 405 * 406 * @returns Type instance of this value 407 */ 408 public static of(v: Double): Type { 409 return DoubleType.REF 410 } 411 412 // ----- 413 414 /** 415 * Returns Type of value 416 * 417 * @param v value 418 * 419 * @returns Type instance of this value 420 */ 421 public static of(v: string): Type { 422 return StringType.REF 423 } 424 425 // ----- 426 427 /** 428 * Returns Type of value 429 * 430 * @param v value 431 * 432 * @returns Type instance of this value 433 */ 434 public static of(v: boolean[]): Type { 435 return ArrayType.getInstance(TypeAPIGetTypeDescriptor(v), ValueTypeDesc.BOOLEAN) 436 } 437 438 /** 439 * Returns Type of value 440 * 441 * @param v value 442 * 443 * @returns Type instance of this value 444 */ 445 public static of(v: char[]): Type { 446 return ArrayType.getInstance(TypeAPIGetTypeDescriptor(v), ValueTypeDesc.CHAR) 447 } 448 449 /** 450 * Returns Type of value 451 * 452 * @param v value 453 * 454 * @returns Type instance of this value 455 */ 456 public static of(v: byte[]): Type { 457 return ArrayType.getInstance(TypeAPIGetTypeDescriptor(v), ValueTypeDesc.BYTE) 458 } 459 460 /** 461 * Returns Type of value 462 * 463 * @param v value 464 * 465 * @returns Type instance of this value 466 */ 467 public static of(v: short[]): Type { 468 return ArrayType.getInstance(TypeAPIGetTypeDescriptor(v), ValueTypeDesc.SHORT) 469 } 470 471 /** 472 * Returns Type of value 473 * 474 * @param v value 475 * 476 * @returns Type instance of this value 477 */ 478 public static of(v: int[]): Type { 479 return ArrayType.getInstance(TypeAPIGetTypeDescriptor(v), ValueTypeDesc.INT) 480 } 481 482 /** 483 * Returns Type of value 484 * 485 * @param v value 486 * 487 * @returns Type instance of this value 488 */ 489 public static of(v: long[]): Type { 490 return ArrayType.getInstance(TypeAPIGetTypeDescriptor(v), ValueTypeDesc.LONG) 491 } 492 493 /** 494 * Returns Type of value 495 * 496 * @param v value 497 * 498 * @returns Type instance of this value 499 */ 500 public static of(v: float[]): Type { 501 return ArrayType.getInstance(TypeAPIGetTypeDescriptor(v), ValueTypeDesc.FLOAT) 502 } 503 504 /** 505 * Returns Type of value 506 * 507 * @param v value 508 * 509 * @returns Type instance of this value 510 */ 511 public static of(v: double[]): Type { 512 return ArrayType.getInstance(TypeAPIGetTypeDescriptor(v), ValueTypeDesc.DOUBLE) 513 } 514 515 // ----- 516 517 /** 518 * Returns Type of value 519 * 520 * @param v value 521 * 522 * @returns Type instance of this value 523 */ 524 public static of(v: Object[]): Type { 525 return ArrayType.getInstance(TypeAPIGetTypeDescriptor(v)) 526 } 527 528 public abstract isPrimitive(): boolean // Or Composite 529 530 public abstract isReference(): boolean // Or Value 531 532 public abstract hasName(): boolean 533 534 // T.subTypeOf(U) means that `T extends U` 535 protected subTypeOf(other: Type): boolean { 536 if (this.equals(other)) { 537 return true 538 } else if (other.equals(ObjectType)) { 539 let isNullish = (this) instanceof UndefinedType || (this) instanceof NullType 540 return this.isReference() && !isNullish 541 } 542 return false 543 } 544 545 // T.assignableFrom(U) means that `T <- U` 546 public assignableFrom(other: Type): boolean { 547 if (other.subTypeOf(this)) { 548 return true 549 } 550 if (this.isNumericType() && other.isNumericType()) { 551 return true 552 } 553 return false 554 } 555 556 internal abstract convertObject(obj: NullishType): NullishType; 557 558 private isNumericType(): boolean { 559 return (this) instanceof ByteType 560 || (this) instanceof ShortType 561 || (this) instanceof IntType 562 || (this) instanceof LongType 563 || (this) instanceof FloatType 564 || (this) instanceof DoubleType 565 } 566 567 public getId(): long { 568 return TypeAPIGetTypeId(this.td); 569 } 570 571 public abstract getName(): string 572 573 /** 574 * Returns literal of type if exists 575 * 576 * @returns type literal 577 */ 578 public abstract getLiteral(): string 579 580 public override toString(): string { 581 if (this.hasName()) { 582 return this.getName() 583 } 584 return this.getLiteral() 585 } 586 587 abstract equals(other: Type): boolean 588} 589 590/** 591 * Represents null type 592 */ 593export final class NullType extends Type { 594 public static readonly REF: NullType = new NullType() 595 596 private constructor() { 597 this.td = TypeAPIGetTypeDescriptor(null) 598 } 599 600 /** 601 * Checks whether type is primitive or composite 602 * 603 * @returns true if type is primitive and false otherwise 604 */ 605 public override isPrimitive(): boolean { 606 return true 607 } 608 609 /** 610 * Checks whether type is reference or composite 611 * 612 * @returns true if type is reference and false otherwise 613 */ 614 public override isReference(): boolean { 615 return true 616 } 617 618 /** 619 * Checks whether type has name 620 * 621 * @returns true if type has name 622 */ 623 public override hasName(): boolean { 624 return true 625 } 626 627 /** 628 * Returns name of type 629 * 630 * @throws error in case of absence of name 631 * 632 * @returns type name 633 */ 634 public override getName(): string { 635 return "null" 636 } 637 638 /** 639 * Returns literal of type if exists 640 * 641 * @returns type literal 642 */ 643 public override getLiteral(): string { 644 return "null" 645 } 646 647 /** 648 * Checks for equality this instance with provided object, treated as a DoubleType 649 * 650 * @param other type to be checked against 651 * 652 * @returns true if object also has NullType 653 */ 654 public override equals(other: Type): boolean { 655 return other instanceof NullType 656 } 657 658 internal override convertObject(obj: NullishType): NullishType { 659 if (obj != null) { 660 throw new Error("invalid conversion") 661 } 662 return null 663 } 664} 665 666export final class UndefinedType extends Type { 667 public static readonly REF: UndefinedType = new UndefinedType() 668 669 private constructor() { 670 this.td = TypeAPIGetTypeDescriptor(undefined) 671 } 672 673 /** 674 * Checks whether type is primitive or composite 675 * 676 * @returns true if type is primitive and false otherwise 677 */ 678 public override isPrimitive(): boolean { 679 return true 680 } 681 682 /** 683 * Checks whether type is reference or composite 684 * 685 * @returns true if type is reference and false otherwise 686 */ 687 public override isReference(): boolean { 688 return true 689 } 690 691 /** 692 * Checks whether type has name 693 * 694 * @returns true if type has name 695 */ 696 public override hasName(): boolean { 697 return true 698 } 699 700 /** 701 * Returns name of type if exists and empty string otherwise 702 * 703 * @returns type name 704 */ 705 public override getName(): string { 706 return "undefined" 707 } 708 709 /** 710 * Returns literal of type if exists 711 * 712 * @returns type literal 713 */ 714 public override getLiteral(): string { 715 return "undefined" 716 } 717 718 /** 719 * Checks for equality this instance with provided object, treated as a UndefinedType 720 * 721 * @param other type to be checked against 722 * 723 * @returns true if object also has UndefinedType 724 */ 725 public override equals(other: Type): boolean { 726 return other instanceof UndefinedType 727 } 728 729 internal override convertObject(obj: NullishType): NullishType { 730 throw new Error("todo(kprokopenko): add when undefined becomes available") 731 } 732} 733 734/** 735 * Represents void type 736 */ 737export final class VoidType extends Type { 738 public static readonly REF: VoidType = new VoidType() 739 740 private constructor() { 741 this.td = TypeAPIGetTypeDescriptor(Void.void_instance) 742 } 743 744 /** 745 * Checks whether type is primitive or composite 746 * 747 * @returns true if type is primitive and false otherwise 748 */ 749 public override isPrimitive(): boolean { 750 return true 751 } 752 753 /** 754 * Checks whether type is reference or composite 755 * 756 * @returns true if type is reference and false otherwise 757 */ 758 public override isReference(): boolean { 759 return true 760 } 761 762 /** 763 * Checks whether type has name 764 * 765 * @returns true if type has name 766 */ 767 public override hasName(): boolean { 768 return true 769 } 770 771 /** 772 * Returns name of type if exists and empty string otherwise 773 * 774 * @returns type name 775 */ 776 public override getName(): string { 777 return "void" 778 } 779 780 /** 781 * Returns literal of type if exists 782 * 783 * @returns type literal 784 */ 785 public override getLiteral(): string { 786 return "void" 787 } 788 789 /** 790 * Checks for equality this instance with provided object, treated as a VoidType 791 * 792 * @param other type to be checked against 793 * 794 * @returns true if object also has VoidType 795 */ 796 public override equals(other: Type): boolean { 797 return other instanceof VoidType 798 } 799 800 internal override convertObject(obj: NullishType): NullishType { 801 if (!this.assignableFrom(Type.of(obj))) { 802 throw new Error("invalid conversion") 803 } 804 return Void.void_instance 805 } 806} 807 808/** 809 * Represents char type 810 * 811 * @note Boxed Char and primitive char both have CharType 812 */ 813 814export final class CharType extends Type { 815 public static readonly VAL: CharType = new CharType(ValueTypeDesc.CHAR, true) 816 public static readonly REF: CharType = new CharType(TypeAPIGetTypeDescriptor(new Char()), false) 817 818 private isValue: boolean 819 820 private constructor(td: TypeDesc, isValue: boolean) { 821 this.td = td 822 this.isValue = isValue 823 } 824 825 /** 826 * Checks whether type is primitive or composite 827 * 828 * @returns true if type is primitive and false otherwise 829 */ 830 public override isPrimitive(): boolean { 831 return true 832 } 833 834 /** 835 * Checks whether type is reference or composite 836 * 837 * @returns true if type is reference and false otherwise 838 */ 839 public override isReference(): boolean { 840 return !this.isValue 841 } 842 843 /** 844 * Checks whether type has name 845 * 846 * @returns true if type has name 847 */ 848 public override hasName(): boolean { 849 return !this.isValue 850 } 851 852 /** 853 * Returns name of type 854 * 855 * @throws error in case of absence of name 856 * 857 * @returns name of type 858 */ 859 //NOTE(kirill-mitkin): add error 860 public override getName(): string { 861 if (this.isValue) { 862 return "" 863 } 864 return TypeAPIGetTypeName(this.td) 865 } 866 867 /** 868 * Returns literal of type if exists 869 * 870 * @returns type literal 871 */ 872 public override getLiteral(): string { 873 if (this.isValue) { 874 return "char" 875 } 876 return "Char" 877 } 878 879 public override equals(other: Type): boolean { 880 return other instanceof CharType && this.isValue != (other as CharType).isReference() 881 } 882 883 internal override convertObject(obj: NullishType): NullishType { 884 const objType = Type.of(obj) 885 if (!this.equals(objType)) { 886 throw new Error("invalid type for conversion") 887 } 888 return obj 889 } 890} 891 892/** 893 * Represents boolean type 894 * 895 * @note Boxed Boolean and primitive boolean both have BooleanType 896 */ 897export final class BooleanType extends Type { 898 public static readonly VAL: BooleanType = new BooleanType(ValueTypeDesc.BOOLEAN, true) 899 public static readonly REF: BooleanType = new BooleanType(TypeAPIGetTypeDescriptor(new Boolean()), false) 900 901 private isValue: boolean 902 903 private constructor(td: TypeDesc, isValue: boolean) { 904 this.td = td 905 this.isValue = isValue 906 } 907 908 /** 909 * Checks whether type is primitive or composite 910 * 911 * @returns true if type is primitive and false otherwise 912 */ 913 public override isPrimitive(): boolean { 914 return true 915 } 916 917 /** 918 * Checks whether type is reference or composite 919 * 920 * @returns true if type is reference and false otherwise 921 */ 922 public override isReference(): boolean { 923 return !this.isValue 924 } 925 926 /** 927 * Checks whether type has name 928 * 929 * @returns true if type has name 930 */ 931 public override hasName(): boolean { 932 return !this.isValue 933 } 934 935 /** 936 * Returns name of type 937 * 938 * @throws error in case of absence of name 939 * 940 * @returns name of type 941 */ 942 //NOTE(kirill-mitkin): add error 943 public override getName(): string { 944 if (this.isValue) { 945 return "" 946 } 947 return TypeAPIGetTypeName(this.td) 948 } 949 950 /** 951 * Returns literal of type if exists 952 * 953 * @returns type literal 954 */ 955 public override getLiteral(): string { 956 if (this.isValue) { 957 return "boolean" 958 } 959 return "Boolean" 960 } 961 962 override equals(other: Type): boolean { 963 return other instanceof BooleanType && this.isValue != (other as BooleanType).isReference() 964 } 965 966 internal override convertObject(obj: NullishType): NullishType { 967 const objType = Type.of(obj) 968 if (!this.equals(objType)) { 969 throw new Error("invalid type for conversion") 970 } 971 return obj 972 } 973} 974 975/** 976 * Represents byte type 977 * 978 * @note Boxed Byte and primitive byte both have ByteType 979 */ 980export final class ByteType extends Type { 981 public static readonly VAL: ByteType = new ByteType(ValueTypeDesc.BYTE, true) 982 public static readonly REF: ByteType = new ByteType(TypeAPIGetTypeDescriptor(new Byte()), false) 983 984 private isValue: boolean 985 986 private constructor(td: TypeDesc, isValue: boolean) { 987 this.td = td 988 this.isValue = isValue 989 } 990 991 /** 992 * Checks whether type is primitive or composite 993 * 994 * @returns true if type is primitive and false otherwise 995 */ 996 public override isPrimitive(): boolean { 997 return true 998 } 999 1000 /** 1001 * Checks whether type is reference or composite 1002 * 1003 * @returns true if type is reference and false otherwise 1004 */ 1005 public override isReference(): boolean { 1006 return !this.isValue 1007 } 1008 1009 /** 1010 * Checks whether type has name 1011 * 1012 * @returns true if type has name 1013 */ 1014 public override hasName(): boolean { 1015 return !this.isValue 1016 } 1017 1018 /** 1019 * Returns name of type 1020 * 1021 * @throws error in case of absence of name 1022 * 1023 * @returns name of type 1024 */ 1025 //NOTE(kirill-mitkin): add error 1026 public override getName(): string { 1027 if (this.isValue) { 1028 return "" 1029 } 1030 return TypeAPIGetTypeName(this.td) 1031 } 1032 1033 /** 1034 * Returns literal of type if exists 1035 * 1036 * @returns type literal 1037 */ 1038 public override getLiteral(): string { 1039 if (this.isValue) { 1040 return "byte" 1041 } 1042 return "Byte" 1043 } 1044 1045 public override equals(other: Type): boolean { 1046 return other instanceof ByteType && this.isValue != (other as ByteType).isReference() 1047 } 1048 1049 internal override convertObject(obj: NullishType): NullishType { 1050 const objType = Type.of(obj) 1051 if (this.equals(objType)) { 1052 return obj 1053 } 1054 if (!this.assignableFrom(objType)) { 1055 throw new Error("invalid conversion") 1056 } 1057 return (obj as Numeric).byteValue() 1058 } 1059} 1060 1061/** 1062 * Represents short type 1063 * 1064 * @note Boxed Short and primitive short both have ShortType 1065 */ 1066export final class ShortType extends Type { 1067 public static readonly VAL: ShortType = new ShortType(ValueTypeDesc.SHORT, true) 1068 public static readonly REF: ShortType = new ShortType(TypeAPIGetTypeDescriptor(new Short()), false) 1069 1070 private isValue: boolean 1071 1072 private constructor(td: TypeDesc, isValue: boolean) { 1073 this.td = td 1074 this.isValue = isValue 1075 } 1076 1077 /** 1078 * Checks whether type is primitive or composite 1079 * 1080 * @returns true if type is primitive and false otherwise 1081 */ 1082 public override isPrimitive(): boolean { 1083 return true 1084 } 1085 1086 /** 1087 * Checks whether type is reference or composite 1088 * 1089 * @returns true if type is reference and false otherwise 1090 */ 1091 public override isReference(): boolean { 1092 return !this.isValue 1093 } 1094 1095 /** 1096 * Checks whether type has name 1097 * 1098 * @returns true if type has name 1099 */ 1100 public override hasName(): boolean { 1101 return !this.isValue 1102 } 1103 1104 /** 1105 * Returns name of type 1106 * 1107 * @throws error in case of absence of name 1108 * 1109 * @returns name of type 1110 */ 1111 //NOTE(kirill-mitkin): add error 1112 public override getName(): string { 1113 if (this.isValue) { 1114 return "" 1115 } 1116 return TypeAPIGetTypeName(this.td) 1117 } 1118 1119 /** 1120 * Returns literal of type 1121 * 1122 * @returns type literal 1123 */ 1124 public override getLiteral(): string { 1125 if (this.isValue) { 1126 return "short" 1127 } 1128 return "Short" 1129 } 1130 1131 /** 1132 * Checks for equality this instance with provided object, treated as a ShortType 1133 * 1134 * @param other type to be checked against 1135 * 1136 * @returns true if object also has ShortType and 1137 * this type and other type both are reference or value 1138 */ 1139 public override equals(other: Type): boolean { 1140 return other instanceof ShortType && this.isValue != (other as ShortType).isReference() 1141 } 1142 1143 internal override convertObject(obj: NullishType): NullishType { 1144 const objType = Type.of(obj) 1145 if (this.equals(objType)) { 1146 return obj 1147 } 1148 if (!this.assignableFrom(objType)) { 1149 throw new Error("invalid conversion") 1150 } 1151 return (obj as Numeric).shortValue() 1152 } 1153} 1154 1155/** 1156 * Represents int type 1157 * 1158 * @note Boxed Int and primitive int both have IntType 1159 */ 1160export final class IntType extends Type { 1161 public static readonly VAL: IntType = new IntType(ValueTypeDesc.INT, true) 1162 public static readonly REF: IntType = new IntType(TypeAPIGetTypeDescriptor(new Int()), false) 1163 1164 private isValue: boolean 1165 1166 private constructor(td: TypeDesc, isValue: boolean) { 1167 this.td = td 1168 this.isValue = isValue 1169 } 1170 1171 /** 1172 * Checks whether type is primitive or composite 1173 * 1174 * @returns true if type is primitive and false otherwise 1175 */ 1176 public override isPrimitive(): boolean { 1177 return true 1178 } 1179 1180 /** 1181 * Checks whether type is reference or composite 1182 * 1183 * @returns true if type is reference and false otherwise 1184 */ 1185 public override isReference(): boolean { 1186 return !this.isValue 1187 } 1188 1189 /** 1190 * Checks whether type has name 1191 * 1192 * @returns true if type has name 1193 */ 1194 public override hasName(): boolean { 1195 return !this.isValue 1196 } 1197 1198 /** 1199 * Returns name of type if exists and empty string otherwise 1200 * 1201 * @throws error in case of absence of name 1202 * 1203 * @returns type name 1204 */ 1205 //NOTE(kirill-mitkin): add error 1206 public override getName(): string { 1207 if (this.isValue) { 1208 return "" 1209 } 1210 return TypeAPIGetTypeName(this.td) 1211 } 1212 1213 /** 1214 * Returns literal of type if exists 1215 * 1216 * @returns type literal 1217 */ 1218 public override getLiteral(): string { 1219 if (this.isValue) { 1220 return "int" 1221 } 1222 return "Int" 1223 } 1224 1225 /** 1226 * Checks for equality this instance with provided object, treated as a IntType 1227 * 1228 * @param other type to be checked against 1229 * 1230 * @returns true if object also has IntType and 1231 * this type and other type both are reference or value 1232 */ 1233 public override equals(other: Type): boolean { 1234 return other instanceof IntType && this.isValue != (other as IntType).isReference() 1235 } 1236 1237 internal override convertObject(obj: NullishType): NullishType { 1238 const objType = Type.of(obj) 1239 if (this.equals(objType)) { 1240 return obj 1241 } 1242 if (!this.assignableFrom(objType)) { 1243 throw new Error("invalid conversion") 1244 } 1245 return (obj as Numeric).intValue() 1246 } 1247} 1248 1249/** 1250 * Represents long type 1251 * 1252 * @note Boxed Long and primitive long both have LongType 1253 */ 1254export final class LongType extends Type { 1255 public static readonly VAL = new LongType(ValueTypeDesc.LONG, true) 1256 public static readonly REF = new LongType(TypeAPIGetTypeDescriptor(new Long()), false) 1257 1258 private isValue: boolean 1259 1260 private constructor(td: TypeDesc, isValue: boolean) { 1261 this.td = td 1262 this.isValue = isValue 1263 } 1264 1265 /** 1266 * Checks whether type is primitive or composite 1267 * 1268 * @returns true if type is primitive and false otherwise 1269 */ 1270 public override isPrimitive(): boolean { 1271 return true 1272 } 1273 1274 /** 1275 * Checks whether type is reference or composite 1276 * 1277 * @returns true if type is reference and false otherwise 1278 */ 1279 public override isReference(): boolean { 1280 return !this.isValue 1281 } 1282 1283 /** 1284 * Checks whether type has name 1285 * 1286 * @returns true if type has name 1287 */ 1288 public override hasName(): boolean { 1289 return !this.isValue 1290 } 1291 1292 /** 1293 * Returns name of type if exists and empty string otherwise 1294 * 1295 * @throws error in case of absence of name 1296 * 1297 * @returns type name 1298 */ 1299 //NOTE(kirill-mitkin): add error 1300 public override getName(): string { 1301 if (this.isValue) { 1302 return "" 1303 } 1304 return TypeAPIGetTypeName(this.td) 1305 } 1306 1307 /** 1308 * Returns literal of type if exists 1309 * 1310 * @returns type literal 1311 */ 1312 public override getLiteral(): string { 1313 if (this.isValue) { 1314 return "long" 1315 } 1316 return "Long" 1317 } 1318 1319 /** 1320 * Checks for equality this instance with provided object, treated as a LongType 1321 * 1322 * @param other type to be checked against 1323 * 1324 * @returns true if object also has LongType and 1325 * this type and other type both are reference or value 1326 */ 1327 public override equals(other: Type): boolean { 1328 return other instanceof LongType && this.isValue != (other as LongType).isReference() 1329 } 1330 1331 internal override convertObject(obj: NullishType): NullishType { 1332 const objType = Type.of(obj) 1333 if (this.equals(objType)) { 1334 return obj 1335 } 1336 if (!this.assignableFrom(objType)) { 1337 throw new Error("invalid conversion") 1338 } 1339 return (obj as Numeric).longValue() 1340 } 1341} 1342 1343/** 1344 * Represents float type 1345 * 1346 * @note Boxed Float and primitive float both have FloatType 1347 */ 1348export final class FloatType extends Type { 1349 public static readonly VAL: FloatType = new FloatType(ValueTypeDesc.FLOAT, true) 1350 public static readonly REF: FloatType = new FloatType(TypeAPIGetTypeDescriptor(new Float()), false) 1351 1352 private isValue: boolean 1353 1354 private constructor(td: TypeDesc, isValue: boolean) { 1355 this.td = td 1356 this.isValue = isValue 1357 } 1358 1359 /** 1360 * Checks whether type is primitive or composite 1361 * 1362 * @returns true if type is primitive and false otherwise 1363 */ 1364 public override isPrimitive(): boolean { 1365 return true 1366 } 1367 1368 /** 1369 * Checks whether type is reference or composite 1370 * 1371 * @returns true if type is reference and false otherwise 1372 */ 1373 public override isReference(): boolean { 1374 return !this.isValue 1375 } 1376 1377 /** 1378 * Checks whether type has name 1379 * 1380 * @returns true if type has name 1381 */ 1382 public override hasName(): boolean { 1383 return !this.isValue 1384 } 1385 1386 /** 1387 * Returns name of type 1388 * 1389 * @throws error in case of absence of name 1390 * 1391 * @returns name of type 1392 */ 1393 //NOTE(kirill-mitkin): add error 1394 public override getName(): string { 1395 if (this.isValue) { 1396 return "" 1397 } 1398 return TypeAPIGetTypeName(this.td) 1399 } 1400 1401 /** 1402 * Returns literal of type if exists 1403 * 1404 * @returns type literal 1405 */ 1406 public override getLiteral(): string { 1407 if (this.isValue) { 1408 return "float" 1409 } 1410 return "Float" 1411 } 1412 1413 /** 1414 * Checks for equality this instance with provided object, treated as a FloatType 1415 * 1416 * @param other type to be checked against 1417 * 1418 * @returns true if object also has FloatType and 1419 * this type and other type both are reference or value 1420 */ 1421 public override equals(other: Type): boolean { 1422 return other instanceof FloatType && this.isValue != (other as FloatType).isReference() 1423 } 1424 1425 internal override convertObject(obj: NullishType): NullishType { 1426 const objType = Type.of(obj) 1427 if (this.equals(objType)) { 1428 return obj 1429 } 1430 if (!this.assignableFrom(objType)) { 1431 throw new Error("invalid conversion") 1432 } 1433 return (obj as Numeric).floatValue() 1434 } 1435} 1436 1437/** 1438 * Represents double type 1439 * 1440 * @note Boxed Double and primitive double both have DoubleType 1441 */ 1442export final class DoubleType extends Type { 1443 public static readonly VAL: DoubleType = new DoubleType(ValueTypeDesc.DOUBLE, true) 1444 public static readonly REF: DoubleType = new DoubleType(TypeAPIGetTypeDescriptor(new Double()), false) 1445 1446 private isValue: boolean 1447 1448 private constructor(td: TypeDesc, isValue: boolean) { 1449 this.td = td 1450 this.isValue = isValue 1451 } 1452 1453 /** 1454 * Checks whether type is primitive or composite 1455 * 1456 * @returns true if type is primitive and false otherwise 1457 */ 1458 public override isPrimitive(): boolean { 1459 return true 1460 } 1461 1462 /** 1463 * Checks whether type is reference or composite 1464 * 1465 * @returns true if type is reference and false otherwise 1466 */ 1467 public override isReference(): boolean { 1468 return !this.isValue 1469 } 1470 1471 /** 1472 * Checks whether type has name 1473 * 1474 * @returns true if type has name 1475 */ 1476 public override hasName(): boolean { 1477 return !this.isValue 1478 } 1479 1480 /** 1481 * Returns name of type 1482 * 1483 * @throws error in case of absence of name 1484 * 1485 * @returns name of type 1486 */ 1487 //NOTE(kirill-mitkin): add error 1488 public override getName(): string { 1489 if (this.isValue) { 1490 return "" 1491 } 1492 return TypeAPIGetTypeName(this.td) 1493 } 1494 1495 /** 1496 * Returns literal of type if exists 1497 * 1498 * @returns type literal 1499 */ 1500 public override getLiteral(): string { 1501 if (this.isValue) { 1502 return "double" 1503 } 1504 return "Double" 1505 } 1506 1507 /** 1508 * Checks for equality this instance with provided object, treated as a DoubleType 1509 * 1510 * @param other type to be checked against 1511 * 1512 * @returns true if object also has DoubleType and 1513 * this type and other type both are reference or value 1514 */ 1515 public override equals(other: Type): boolean { 1516 return other instanceof DoubleType && this.isValue != (other as DoubleType).isReference() 1517 } 1518 1519 internal override convertObject(obj: NullishType): NullishType { 1520 const objType = Type.of(obj) 1521 if (this.equals(objType)) { 1522 return obj 1523 } 1524 if (!this.assignableFrom(objType)) { 1525 throw new Error("invalid conversion") 1526 } 1527 return (obj as Numeric).doubleValue() 1528 } 1529} 1530 1531/** 1532 * Represents type of classes 1533 */ 1534export final class ClassType extends Type { 1535 private readonly attrs: int 1536 1537 internal constructor(td: TypeDesc) { 1538 this.td = td 1539 this.attrs = TypeAPIGetClassAttributes(td) 1540 } 1541 1542 /** 1543 * Checks whether type is primitive or composite 1544 * 1545 * @returns true if type is primitive and false otherwise 1546 */ 1547 public override isPrimitive(): boolean { 1548 return false 1549 } 1550 1551 /** 1552 * Checks whether type is reference or composite 1553 * 1554 * @returns true if type is reference and false otherwise 1555 */ 1556 public override isReference(): boolean { 1557 return true 1558 } 1559 1560 /** 1561 * Checks whether type has name 1562 * 1563 * @returns true if type has name 1564 */ 1565 public override hasName(): boolean { 1566 return true 1567 } 1568 1569 /** 1570 * Returns name of type 1571 * 1572 * @returns type name 1573 */ 1574 public override getName(): string { 1575 return TypeAPIGetTypeName(this.td) 1576 } 1577 1578 /** 1579 * Returns literal of type if exists 1580 * 1581 * @returns type literal 1582 */ 1583 public override getLiteral(): string { 1584 // NOTE(shumilov-petr): not implemented 1585 return "class{...}" 1586 } 1587 1588 /** 1589 * Checks for equality this instance with provided object, treated as a ClassType 1590 * 1591 * @param other type to be checked against 1592 * 1593 * @returns true if object also has ClassType and their names are the same 1594 */ 1595 public override equals(other: Type): boolean { 1596 return (other instanceof ClassType) && (other as ClassType).td == this.td 1597 } 1598 1599 /** 1600 * Returns base type of this class 1601 * If this type is the type of Object class then returns this 1602 * 1603 * @returns base type of class 1604 */ 1605 public getBaseType(): ClassType { 1606 return Type.resolve(TypeAPIGetBaseType(this.td))! as ClassType 1607 } 1608 1609 /** 1610 * Returns number of direct superinterfaces of this class 1611 * 1612 * @returns number of interfaces that was implemented by this class directly 1613 */ 1614 public getInterfacesNum(): long { 1615 return TypeAPIGetInterfacesNum(this.td) 1616 } 1617 1618 /** 1619 * Returns ith direct superinterface of this class 1620 * 1621 * @param i index 1622 * 1623 * @throws error when i greater then num of interfaces 1624 * 1625 * @returns type of ith superinterface 1626 */ 1627 public getInterface(i: long): InterfaceType { 1628 return Type.resolve(TypeAPIGetInterface(this.td, i))! as InterfaceType 1629 } 1630 1631 /** 1632 * Returns number of all fields 1633 * including static, instance and also fields of all its superclasses 1634 * 1635 * @returns number of fields 1636 * 1637 * @example 1638 * 1639 * ``` 1640 * class A { 1641 * a : int 1642 * } 1643 * 1644 * class B extends A { 1645 * b : int 1646 * } 1647 * ``` 1648 * let bType class type of B, then `bType.getFieldsNum()` returns 2 1649 * Note that Object class also is super class of B 1650 */ 1651 public getFieldsNum(): long { 1652 return TypeAPIGetFieldsNum(this.td) 1653 } 1654 1655 public getOwnFieldsNum(): long { 1656 return TypeAPIGetOwnFieldsNum(this.td) 1657 } 1658 1659 /** 1660 * Returns ith Field of this class 1661 * 1662 * @param i index (using flat semantic) 1663 * 1664 * @throws error when i greater then number of fields 1665 * 1666 * @returns ith Field 1667 */ 1668 //NOTE(kirill-mitkin): add error 1669 public getField(i: long): Field { 1670 return TypeAPIGetField(this.td, i) 1671 } 1672 1673 public getOwnField(i: long): Field { 1674 return TypeAPIGetOwnField(this.td, i) 1675 } 1676 1677 /** 1678 * Find Field by name 1679 * 1680 * @param name name of field 1681 * 1682 * @throws error when class doesn't have field with this name 1683 * 1684 * @returns Field instance with this name 1685 */ 1686 //NOTE(kirill-mitkin): add error 1687 public getFieldByName(name: string): Field { 1688 return TypeAPIGetFieldByName(this.td, name) 1689 } 1690 1691 /** 1692 * Returns number of methods of this class 1693 * including static methods and methods of super classes 1694 * @example 1695 * 1696 * ``` 1697 * class A { 1698 * a(): void {} 1699 * } 1700 * 1701 * class B extends A { 1702 * b(): void {} 1703 * } 1704 * ``` 1705 * let bType class type of B, then `bType.getMethodsNum()` returns at least 2 1706 * Note that Object class also super class of B 1707 * @returns number of methods 1708 */ 1709 public getMethodsNum(): long { 1710 return TypeAPIGetMethodsNum(this.td) 1711 } 1712 1713 /** 1714 * Returns ith Method of this class 1715 * 1716 * @param i index (using flat semantic) 1717 * 1718 * @throws error when i greater then number of methods 1719 * 1720 * @returns ith method 1721 */ 1722 //NOTE(kirill-mitkin): add error 1723 public getMethod(i: long): Method { 1724 return TypeAPIGetMethod(this.td, i) 1725 } 1726 1727 /** 1728 * Returns number of constructors of this class 1729 * Note that constructors of super class isn't considered as constructors of this class 1730 * 1731 * @returns number of constructors 1732 */ 1733 public getConstructorsNum(): long { 1734 return TypeAPIGetConstructorsNum(this.td) 1735 } 1736 1737 /** 1738 * Returns ith constructor of this class 1739 * 1740 * @param i index 1741 * 1742 * @throws error then i greater then number of constructors 1743 * 1744 * @returns {@link Method} instance representing ith constructor 1745 */ 1746 //NOTE(kirill-mitkin): add error 1747 public getConstructor(i: long): Method { 1748 return TypeAPIGetConstructor(this.td, i) 1749 } 1750 1751 /** 1752 * Checks for existence of empty constructor of this class 1753 * 1754 * @returns true if there is empty constructor of this class 1755 */ 1756 public hasEmptyConstructor(): boolean { 1757 let num = this.getConstructorsNum() 1758 for (let i = 0; i < num; i++) { 1759 if (this.getConstructor(i).getType().getParametersNum() == 0) { 1760 return true 1761 } 1762 } 1763 return false 1764 } 1765 1766 public isFinal(): boolean { 1767 return (this.attrs & Attributes.FINAL) != 0 1768 } 1769 1770 public hasField(name: string): boolean { 1771 // NOTE(shumilov-petr): may be faster if implement via intrinsic 1772 let fnum = this.getFieldsNum() 1773 for (let i = 0; i < fnum; i++) { 1774 if (this.getField(i).getName() == name) { 1775 return true 1776 } 1777 } 1778 return false 1779 } 1780 1781 /** 1782 * Returns number of type parameters of this class 1783 * 1784 * @returns number of type parameters 1785 */ 1786 public getTypeParametersNum(): long { 1787 // NOTE(shumilov-petr): not implemented 1788 throw new Error("Not implemented") 1789 } 1790 1791 /** 1792 * Returns ith type parameter of this class 1793 * 1794 * @param i index 1795 * 1796 * @throws error then i greater then number of type parameters 1797 * 1798 * @returns NOTE(kirill-mitkin): we cannot return concrete type in this method 1799 */ 1800 public getTypeParameter(i: long): Type { 1801 // NOTE(shumilov-petr): not implemented 1802 throw new Error("Not implemented") 1803 } 1804 1805 /** 1806 * Makes instance of this type by invoking 1807 * empty constructor of this class 1808 * 1809 * @throws error when class doesn't have an empty constructor 1810 */ 1811 public make(): Object { 1812 const emptyArgs = new NullishType[0] 1813 return this.make(emptyArgs) 1814 } 1815 1816 // todo(kprokopenko): make varargs 1817 public make(args: NullishType[]): Object { 1818 const argTypes = new Array<Type>(args.length) 1819 for (let i = 0; i < args.length; i++) { 1820 argTypes[i] = Type.of(args[i]) 1821 } 1822 // collect all applicable constructors 1823 const ctors = new Array<Method>() 1824 const ctorNum = this.getConstructorsNum() 1825 for (let i = 0; i < ctorNum; i++) { 1826 const c = this.getConstructor(i) 1827 const ct = c.getType() 1828 if (ct.getParametersNum() == args.length) { 1829 let ok = true 1830 for (let arg = 0; arg < args.length; arg++) { 1831 if (!ct.getParameter(arg).getType().assignableFrom(argTypes[arg])) { 1832 ok = false 1833 break 1834 } 1835 } 1836 if (ok) { 1837 ctors.push(c) 1838 } 1839 } 1840 } 1841 // inspect if constructor has a more specific one (O(n^2)) 1842 for (let inspect = 0; inspect < ctors.length; inspect++) { 1843 const toRem = ctors.at(inspect)!.getType() 1844 let rem = false 1845 for (let c = 0; c < ctors.length; c++) { 1846 if (c == inspect) { 1847 continue 1848 } 1849 rem = true 1850 const cur = ctors.at(c)!.getType() 1851 for (let a = 0; a < args.length; a++) { 1852 if (!toRem.getParameter(a).getType().assignableFrom(cur.getParameter(a).getType())) { 1853 rem = false; 1854 break; 1855 } 1856 } 1857 if (rem) { 1858 break 1859 } 1860 } 1861 if (rem) { 1862 ctors.splice(inspect, 1) 1863 inspect-- 1864 } 1865 } 1866 if (ctors.length != 1) { 1867 throw new Error("can't select consturctor: " + ctors.length + " left") 1868 } 1869 return ctors.at(0)!.invoke(null, args)! 1870 } 1871 1872 // class.subTypeOf(U) means that `class extends U` or `class implements U` 1873 protected override subTypeOf(other: Type): boolean { 1874 if (super.subTypeOf(other)) { 1875 return true 1876 } 1877 // `this` is derived of `other` class? 1878 if (other instanceof ClassType) { 1879 let bt = this; 1880 while (!bt.equals(bt.getBaseType())) { 1881 if (bt.equals(other)) { 1882 return true 1883 } 1884 bt = bt.getBaseType() 1885 } 1886 return false 1887 } 1888 // `this` implements `other` interface? 1889 if (other instanceof InterfaceType) { 1890 let iface = other as InterfaceType 1891 let ifaceNum = this.getInterfacesNum() 1892 for (let i = 0; i < ifaceNum; i++) { 1893 if (this.getInterface(i).hasSuperInterface(iface)) { 1894 return true 1895 } 1896 } 1897 } 1898 return false 1899 } 1900 1901 internal override convertObject(obj: NullishType): NullishType { 1902 const objType = Type.of(obj) 1903 if (!this.assignableFrom(objType)) { 1904 throw new Error("invalid conversion") 1905 } 1906 return obj 1907 } 1908} 1909 1910/** 1911 * Represents interface type 1912 */ 1913export final class InterfaceType extends Type { 1914 public constructor() {} 1915 1916 public constructor(td: TypeDesc) { 1917 this.td = td 1918 } 1919 1920 /** 1921 * Checks whether type is primitive or composite 1922 * 1923 * @returns true if type is primitive and false otherwise 1924 */ 1925 public override isPrimitive(): boolean { 1926 return false 1927 } 1928 1929 /** 1930 * Checks whether type is reference or composite 1931 * 1932 * @returns true if type is reference and false otherwise 1933 */ 1934 public override isReference(): boolean { 1935 return true 1936 } 1937 1938 /** 1939 * Checks whether type has name 1940 * 1941 * @returns true if type has name 1942 */ 1943 public override hasName(): boolean { 1944 return true 1945 } 1946 1947 /** 1948 * Returns name of type 1949 * 1950 * @returns name of type 1951 */ 1952 public override getName(): string { 1953 return TypeAPIGetTypeName(this.td) 1954 } 1955 1956 /** 1957 * Returns literal of type if exists 1958 * 1959 * @returns type literal 1960 */ 1961 public override getLiteral(): string { 1962 // NOTE(shumilov-petr): not implemented 1963 return "interface{...}" 1964 } 1965 1966 /** 1967 * Checks for equality this instance with provided object, treated as a InterfaceType 1968 * 1969 * @param other type to be checked against 1970 * 1971 * @returns true if object also has InterfaceType and 1972 * their names are the same 1973 */ 1974 public override equals(other: Type): boolean { 1975 return other instanceof InterfaceType && this.td == (other as InterfaceType).td 1976 } 1977 1978 // `this` extends of `other` interface? 1979 protected override subTypeOf(other: Type): boolean { 1980 if (super.subTypeOf(other)) { 1981 return true 1982 } 1983 if (other instanceof InterfaceType) { 1984 return this.hasSuperInterface(other as InterfaceType) 1985 } 1986 return false 1987 } 1988 1989 public getInterfacesNum(): long { 1990 return TypeAPIGetInterfacesNum(this.td) 1991 } 1992 1993 public getInterface(i: long): InterfaceType { 1994 return Type.resolve(TypeAPIGetInterface(this.td, i))! as InterfaceType 1995 } 1996 1997 /** 1998 * Returns number of methods of this interface 1999 * including static methods and methods of super interfaces 2000 * @example 2001 * 2002 * ``` 2003 * class A { 2004 * a(): void {} 2005 * } 2006 * 2007 * class B extends A { 2008 * b(): void {} 2009 * } 2010 * ``` 2011 * let bType interface type of B, then `bType.getMethodsNum()` returns at least 2 2012 * Note that Object class also super class of B 2013 * @returns number of methods 2014 */ 2015 public getMethodsNum(): long { 2016 return TypeAPIGetMethodsNum(this.td) 2017 } 2018 2019 /** 2020 * Returns ith Method of this interface 2021 * 2022 * @param i index (using flat semantic) 2023 * 2024 * @throws error when i greater then number of methods 2025 * 2026 * @returns ith method 2027 */ 2028 public getMethod(i: long): Method { 2029 return TypeAPIGetMethod(this.td, i) 2030 } 2031 2032 /** 2033 * Returns number of type parameters of this class 2034 * 2035 * @returns number of type parameters 2036 */ 2037 public getTypeParametersNum(): long { 2038 // NOTE(shumilov-petr): not implemented 2039 throw new Error("Not implemented") 2040 } 2041 2042 /** 2043 * Returns ith type parameter of this class 2044 * 2045 * @param i index 2046 * 2047 * @throws error then i greater then number of type parameters 2048 * 2049 * @returns NOTE(kirill-mitkin): we cannot return concrete type in this method 2050 */ 2051 public getTypeParameter(i: long): Type { 2052 // NOTE(shumilov-petr): not implemented 2053 throw new Error("Not implemented") 2054 } 2055 2056 internal hasSuperInterface(expected: InterfaceType): boolean { 2057 if (this.equals(expected)) { 2058 return true 2059 } 2060 return TypeAPIIsInheritedFrom(this.td, expected.td) 2061 } 2062 2063 internal override convertObject(obj: NullishType): NullishType { 2064 const objType = Type.of(obj) 2065 if (!this.assignableFrom(objType)) { 2066 throw new Error("invalid conversion") 2067 } 2068 return obj 2069 } 2070} 2071 2072/** 2073 * Represents array type 2074 */ 2075export final class ArrayType extends Type { 2076 private elemTD: TypeDesc 2077 2078 public static readonly BOOLEAN_VAL: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new boolean[0]), ValueTypeDesc.BOOLEAN) 2079 public static readonly BOOLEAN_REF: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new Boolean[0]), TypeAPIGetTypeDescriptor(new Boolean())) 2080 public static readonly CHAR_VAL: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new char[0]), ValueTypeDesc.CHAR) 2081 public static readonly CHAR_REF: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new Char[0]), TypeAPIGetTypeDescriptor(new Char())) 2082 public static readonly BYTE_VAL: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new byte[0]), ValueTypeDesc.BYTE) 2083 public static readonly BYTE_REF: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new Byte[0]), TypeAPIGetTypeDescriptor(new Byte())) 2084 public static readonly SHORT_VAL: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new short[0]), ValueTypeDesc.SHORT) 2085 public static readonly SHORT_REF: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new Short[0]), TypeAPIGetTypeDescriptor(new Short())) 2086 public static readonly INT_VAL: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new int[0]), ValueTypeDesc.INT) 2087 public static readonly INT_REF: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new Int[0]), TypeAPIGetTypeDescriptor(new Int())) 2088 public static readonly LONG_VAL: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new long[0]), ValueTypeDesc.LONG) 2089 public static readonly LONG_REF: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new Long[0]), TypeAPIGetTypeDescriptor(new Long())) 2090 public static readonly FLOAT_VAL: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new float[0]), ValueTypeDesc.FLOAT) 2091 public static readonly FLOAT_REF: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new Float[0]), TypeAPIGetTypeDescriptor(new Float())) 2092 public static readonly DOUBLE_VAL: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new double[0]), ValueTypeDesc.DOUBLE) 2093 public static readonly DOUBLE_REF: ArrayType = new ArrayType(TypeAPIGetTypeDescriptor(new Double[0]), TypeAPIGetTypeDescriptor(new Double())) 2094 2095 private constructor(td: TypeDesc, elemTD: TypeDesc) { 2096 this.td = td 2097 this.elemTD = elemTD 2098 } 2099 2100 public override assignableFrom(other: Type): boolean { 2101 if (super.assignableFrom(other)) { 2102 return true 2103 } 2104 return other instanceof ArrayType && (other as ArrayType).getElementType().subTypeOf(this.getElementType()) 2105 } 2106 2107 internal static getInstance(td: TypeDesc, elemTD: TypeDesc): ArrayType { 2108 let ek = (TypeAPIGetTypeKind(elemTD) & TypeKindMask) as byte 2109 switch (ek) { 2110 case TypeKind.BOOLEAN: 2111 return (TypeAPIIsValueType(elemTD)) ? ArrayType.BOOLEAN_VAL : ArrayType.BOOLEAN_REF 2112 case TypeKind.CHAR: 2113 return (TypeAPIIsValueType(elemTD)) ? ArrayType.CHAR_VAL : ArrayType.CHAR_REF 2114 case TypeKind.BYTE: 2115 return (TypeAPIIsValueType(elemTD)) ? ArrayType.BYTE_VAL : ArrayType.BYTE_REF 2116 case TypeKind.SHORT: 2117 return (TypeAPIIsValueType(elemTD)) ? ArrayType.SHORT_VAL : ArrayType.SHORT_REF 2118 case TypeKind.INT: 2119 return (TypeAPIIsValueType(elemTD)) ? ArrayType.INT_VAL : ArrayType.INT_REF 2120 case TypeKind.LONG: 2121 return (TypeAPIIsValueType(elemTD)) ? ArrayType.LONG_VAL : ArrayType.LONG_REF 2122 case TypeKind.FLOAT: 2123 return (TypeAPIIsValueType(elemTD)) ? ArrayType.FLOAT_VAL : ArrayType.FLOAT_REF 2124 case TypeKind.DOUBLE: 2125 return (TypeAPIIsValueType(elemTD)) ? ArrayType.DOUBLE_VAL : ArrayType.DOUBLE_REF 2126 case TypeKind.CLASS: 2127 case TypeKind.STRING: 2128 case TypeKind.INTERFACE: 2129 case TypeKind.ARRAY: 2130 case TypeKind.TUPLE: 2131 case TypeKind.LAMBDA: 2132 case TypeKind.METHOD: 2133 case TypeKind.UNION: 2134 return new ArrayType(td, elemTD) 2135 default: 2136 // NOTE(shumilov-petr): need throw exception 2137 assert(false) 2138 } 2139 2140 throw new Error("Invalid object") 2141 } 2142 2143 internal static getInstance(td: TypeDesc): ArrayType { 2144 return ArrayType.getInstance(td, TypeAPIGetArrayElementType(td)) 2145 } 2146 2147 /** 2148 * Checks whether type is primitive or composite 2149 * 2150 * @returns true if type is primitive and false otherwise 2151 */ 2152 public override isPrimitive(): boolean { 2153 return false 2154 } 2155 2156 /** 2157 * Checks whether type is reference or composite 2158 * 2159 * @returns true if type is reference and false otherwise 2160 */ 2161 public override isReference(): boolean { 2162 return true 2163 } 2164 2165 /** 2166 * Checks whether type has name 2167 * 2168 * @returns true if type has name 2169 */ 2170 public override hasName(): boolean { 2171 return false 2172 } 2173 2174 /** 2175 * Returns name of type 2176 * 2177 * @throws error in case of absence of name 2178 * 2179 * @returns name of type 2180 */ 2181 public override getName(): string { 2182 return "" 2183 } 2184 2185 /** 2186 * Returns literal of type if exists 2187 * 2188 * @returns type literal 2189 */ 2190 public override getLiteral(): string { 2191 return this.getElementType().toString() + "[]" 2192 } 2193 2194 /** 2195 * Checks for equality this instance with provided object, treated as a ArrayType 2196 * 2197 * @param other type to be checked against 2198 * 2199 * @returns true if object also has ArrayType and 2200 * their element types are the same 2201 */ 2202 public override equals(other: Type): boolean { 2203 return other instanceof ArrayType && (other as ArrayType).getElementType().equals(this.getElementType()) 2204 } 2205 2206 /** 2207 * Returns element type of this array 2208 * 2209 * @returns element type 2210 */ 2211 public getElementType(): Type { 2212 return Type.resolve(this.elemTD)! 2213 } 2214 2215 /** 2216 * Makes instance of this array with provided length 2217 * Each element are instantiated using default value 2218 * If element type is class value then empty constructor are called 2219 * 2220 * @param length of array 2221 * 2222 * @throws error if element type doesn't have default value 2223 * 2224 * @returns new instance of array 2225 */ 2226 public make(length: long): Object { 2227 return TypeAPIMakeArrayInstance(this.elemTD, length) 2228 } 2229 2230 internal override convertObject(obj: NullishType): NullishType { 2231 const objType = Type.of(obj) 2232 if (this.equals(objType)) { 2233 return obj 2234 } 2235 if (!this.assignableFrom(objType)) { 2236 throw new Error("invalid conversion") 2237 } 2238 return obj 2239 } 2240} 2241 2242export final class TupleType extends Type { 2243 public constructor(td: TypeDesc) { 2244 this.td = td 2245 } 2246 2247 public override isPrimitive(): boolean { 2248 throw new Error("Not implemented") 2249 } 2250 2251 public override isReference(): boolean { 2252 throw new Error("Not implemented") 2253 } 2254 2255 public override hasName(): boolean { 2256 throw new Error("Not implemented") 2257 } 2258 2259 public override getName(): string { 2260 throw new Error("Not implemented") 2261 } 2262 2263 public override getLiteral(): string { 2264 throw new Error("Not implemented") 2265 } 2266 2267 public override equals(other: Type): boolean { 2268 throw new Error("Not implemented") 2269 } 2270 2271 internal override convertObject(obj: NullishType): NullishType { 2272 throw new Error("todo(kprokopenko): add when tuple becomes available") 2273 } 2274} 2275 2276/** 2277 * Represents function type 2278 * 2279 * @note lambdas, functions and methods have function type 2280 */ 2281export abstract class FunctionType extends Type { 2282 private readonly attrs: int 2283 2284 protected constructor(td: TypeDesc) { 2285 this.td = td 2286 this.attrs = TypeAPIGetFunctionAttributes(td) 2287 } 2288 2289 /** 2290 * Checks whether type is primitive or composite 2291 * 2292 * @returns true if type is primitive and false otherwise 2293 */ 2294 public override isPrimitive(): boolean { 2295 return false 2296 } 2297 2298 /** 2299 * Checks whether type is reference or composite 2300 * 2301 * @returns true if type is reference and false otherwise 2302 */ 2303 public override isReference(): boolean { 2304 return true 2305 } 2306 2307 /** 2308 * Checks whether type has name 2309 * 2310 * @returns true if type has name 2311 */ 2312 public override hasName(): boolean { 2313 return false 2314 } 2315 2316 /** 2317 * Returns name of type 2318 * 2319 * @returns name of type 2320 */ 2321 public override getName(): string { 2322 return "" 2323 } 2324 2325 /** 2326 * Returns return type of function type 2327 * 2328 * @returns result type 2329 */ 2330 public getResultType(): Type { 2331 return Type.resolve(TypeAPIGetResultType(this.td))! 2332 } 2333 2334 /** 2335 * Checks whether function type throws some exception 2336 * 2337 * @returns true if function type throws some exception 2338 */ 2339 public isThrowing(): boolean { 2340 return (this.attrs & Attributes.THROWING) != 0 2341 } 2342 2343 /** 2344 * Checks whether function type has native modifier 2345 * 2346 * @returns true if function type has native modifier 2347 */ 2348 public isNative(): boolean { 2349 return (this.attrs & Attributes.NATIVE) != 0 2350 } 2351 2352 /** 2353 * Checks whether function type has async modifier 2354 * 2355 * @returns true if function type has async modifier 2356 */ 2357 public isAsync(): boolean { 2358 return (this.attrs & Attributes.ASYNC) != 0 2359 } 2360 2361 /** 2362 * Checks whether function result type is never 2363 * 2364 * @returns true if function result type is never 2365 */ 2366 public isNeverResult(): boolean { 2367 return (this.attrs & Attributes.NEVERRESULT) != 0 2368 } 2369 2370 /** 2371 * Checks for equality this instance with provided object, treated as a FunctionType 2372 * 2373 * @param other type to be checked against 2374 * 2375 * @returns true if object also has FunctionType and 2376 * they both has same signatures 2377 */ 2378 public override equals(other: Type): boolean { 2379 return (other instanceof FunctionType) && (other as FunctionType).td == this.td 2380 } 2381 2382 /** 2383 * Returns number of parameters 2384 * For static methods reciever type counted as parameter 2385 * For instance methods reciever type isn't counted as parameter 2386 * 2387 * @returns number of parameters 2388 */ 2389 public getParametersNum(): long { 2390 return TypeAPIGetParametersNum(this.td) 2391 } 2392 2393 /** 2394 * Returns ith parameter of function type 2395 * 2396 * @return Parameter, corresponding ith parameter in signature 2397 */ 2398 public getParameter(i: long): Parameter { 2399 return TypeAPIGetParameter(this.td, i) 2400 } 2401 2402 /** 2403 * Returns number of type parameters of this class 2404 * 2405 * @returns number of type parameters 2406 */ 2407 public getTypeParametersNum(): long { 2408 // NOTE(shumilov-petr): not implemented 2409 return 0 2410 } 2411 2412 /** 2413 * Returns ith type parameter of this class 2414 * 2415 * @param i index 2416 * 2417 * @throws error then i greater then number of type parameters 2418 * 2419 * @returns NOTE(kirill-mitkin): we cannot return concrete type in this method 2420 */ 2421 public getTypeParameter(i: long): Type { 2422 // NOTE(shumilov-petr): not implemented 2423 throw new Error("not implemented") 2424 } 2425} 2426 2427 2428export final class LambdaType extends FunctionType { 2429 public constructor(td: TypeDesc) { 2430 super(td) 2431 } 2432 2433 public override getLiteral(): string { 2434 let sb = new StringBuilder("(") 2435 const paramsNum = this.getParametersNum() 2436 for (let i = 0; i < paramsNum; ++i) { 2437 sb.append(this.getParameter(i).toString()) 2438 if (i != paramsNum - 1) { 2439 sb.append(", ") 2440 } 2441 } 2442 sb.append("): ") 2443 sb.append(this.getResultType().toString()) 2444 return sb.toString() 2445 } 2446 2447 /** 2448 * Make an instance of LambdaType 2449 * 2450 * @returns LambdaType instance 2451 */ 2452 public make(): Object { 2453 // NOTE(kprokopenko): not implemented 2454 throw new Error("Not implemented") 2455 } 2456 2457 public override assignableFrom(other: Type): boolean { 2458 if (super.assignableFrom(other)) { 2459 return true 2460 } 2461 if (!(other instanceof LambdaType)) { 2462 return false 2463 } 2464 let l = (this) 2465 let r = other as LambdaType 2466 if (l.getParametersNum() != r.getParametersNum()) { 2467 return false 2468 } 2469 // Parameter types are using contravariance 2470 for (let i = 0; i < l.getParametersNum(); i++) { 2471 let lt = l.getParameter(i).getType() 2472 let rt = r.getParameter(i).getType() 2473 if (!lt.subTypeOf(rt)) { 2474 return false 2475 } 2476 } 2477 // Return types are using covariance 2478 return r.getResultType().subTypeOf(l.getResultType()) 2479 } 2480 2481 internal override convertObject(obj: NullishType): NullishType { 2482 const objType = Type.of(obj) 2483 if (this.equals(objType)) { 2484 return obj 2485 } 2486 if (!this.assignableFrom(objType)) { 2487 throw new Error("invalid conversion") 2488 } 2489 // NOTE(shumilov-petr): Need to use Create API 2490 throw new Error("todo(kprokopenko): unequal labmda type conversion") 2491 } 2492} 2493 2494 2495export final class MethodType extends FunctionType { 2496 public constructor(td: TypeDesc) { 2497 super(td) 2498 } 2499 2500 public override getLiteral(): string { 2501 let sb = new StringBuilder("(this: ") 2502 sb.append(this.getReceiverType().toString()) 2503 const paramsNum = this.getParametersNum() 2504 if (paramsNum > 0) { 2505 sb.append(", ") 2506 } 2507 for (let i = 0; i < paramsNum; ++i) { 2508 sb.append(this.getParameter(i).toString()) 2509 if (i != paramsNum - 1) { 2510 sb.append(", ") 2511 } 2512 } 2513 sb.append("): ") 2514 sb.append(this.getResultType().toString()) 2515 return sb.toString() 2516 } 2517 2518 public getReceiverType(): Type { 2519 return Type.resolve(TypeAPIGetReceiverType(this.td))! 2520 } 2521 2522 public override assignableFrom(other: Type): boolean { 2523 return false 2524 } 2525 2526 internal override convertObject(obj: NullishType): NullishType { 2527 throw new Error("Only LambdaType can be converted") 2528 } 2529} 2530 2531/** 2532 * Represents string type 2533 */ 2534export final class StringType extends Type { 2535 public static readonly REF: StringType = new StringType() 2536 2537 internal constructor() { 2538 this.td = TypeAPIGetTypeDescriptor("") 2539 } 2540 2541 /** 2542 * Checks whether type is primitive or composite 2543 * 2544 * @returns true if type is primitive and false otherwise 2545 */ 2546 public override isPrimitive(): boolean { 2547 return true 2548 } 2549 2550 /** 2551 * Checks whether type is reference or composite 2552 * 2553 * @returns true if type is reference and false otherwise 2554 */ 2555 public override isReference(): boolean { 2556 return true 2557 } 2558 2559 /** 2560 * Checks whether type has name 2561 * 2562 * @returns true if type has name 2563 */ 2564 public override hasName(): boolean { 2565 return false 2566 } 2567 2568 /** 2569 * Returns name of type 2570 * 2571 * @returns type name 2572 */ 2573 public override getName(): string { 2574 // NOTE(shumilov-petr): not implemented 2575 return "" 2576 } 2577 2578 /** 2579 * Returns literal of type if exists 2580 * 2581 * @returns type literal 2582 */ 2583 public override getLiteral(): string { 2584 // NOTE(shumilov-petr): not implemented 2585 return "string" 2586 } 2587 2588 2589 /** 2590 * Checks for equality this instance with provided object, treated as a StringType 2591 * 2592 * @param other object to be checked against 2593 * 2594 * @returns true if object also has StringType 2595 */ 2596 public override equals(other: Type): boolean { 2597 return other instanceof StringType 2598 } 2599 2600 internal override convertObject(obj: NullishType): NullishType { 2601 const objType = Type.of(obj) 2602 if (!this.equals(objType)) { 2603 throw new Error("invalid conversion") 2604 } 2605 return obj 2606 } 2607} 2608 2609/** 2610 * Represents enum type 2611 */ 2612export final class EnumType extends Type { 2613 internal constructor(td: TypeDesc) { 2614 this.td = td 2615 } 2616 2617 public override assignableFrom(other: Type): boolean { 2618 if (super.assignableFrom(other)) { 2619 return true 2620 } 2621 if (!(other instanceof EnumType)) { 2622 return false 2623 } 2624 let rt = other as EnumType 2625 return this.getName() == rt.getName() 2626 } 2627 2628 /** 2629 * Checks whether type is primitive or composite 2630 * 2631 * @returns true if type is primitive and false otherwise 2632 */ 2633 public override isPrimitive(): boolean { 2634 return false 2635 } 2636 2637 /** 2638 * Checks whether type is reference or composite 2639 * 2640 * @returns true if type is reference and false otherwise 2641 */ 2642 public override isReference(): boolean { 2643 return false 2644 } 2645 2646 /** 2647 * Checks whether type has name 2648 * 2649 * @returns true if type has name 2650 */ 2651 public override hasName(): boolean { 2652 return true 2653 } 2654 2655 /** 2656 * Returns name of type 2657 * 2658 * @returns type name 2659 */ 2660 public override getName(): string { 2661 // NOTE(shumilov-petr): not implemented 2662 return "" 2663 } 2664 2665 /** 2666 * Returns literal of type if exists 2667 * 2668 * @returns type literal 2669 */ 2670 public override getLiteral(): string { 2671 // NOTE(shumilov-petr): not implemented 2672 return "enum {...}" 2673 } 2674 2675 /** 2676 * Checks for equality this instance with provided object, treated as a EnumType 2677 * 2678 * @param other type to be checked against 2679 * 2680 * @returns true if object also has EnumType and their names are the same 2681 */ 2682 public override equals(other: Type): boolean { 2683 // NOTE(shumilov-petr): not implemented 2684 return false 2685 } 2686 2687 public getConstantsNum(): long { 2688 // NOTE(shumilov-petr): not implemented 2689 return 0 2690 } 2691 2692 public getConstant(i: long): EnumConstant { 2693 // NOTE(shumilov-petr): not implemented 2694 throw new Error("not implemented") 2695 } 2696 2697 public getConstantByName(name: string): EnumConstant { 2698 // NOTE(shumilov-petr): not implemented 2699 throw new Error("not implemented") 2700 } 2701 2702 public create(consts: EnumConstant[]): EnumType { 2703 // NOTE(shumilov-petr): not implemented 2704 throw new Error("not implemented") 2705 } 2706 2707 public make(constantName: string): Object { 2708 // NOTE(shumilov-petr): not implemented 2709 throw new Error("not implemented") 2710 } 2711 2712 internal override convertObject(obj: NullishType): NullishType { 2713 throw new Error("todo(kprokopenko): enum conversion") 2714 } 2715} 2716 2717/** 2718 * Represents union type 2719 */ 2720export final class UnionType extends Type { 2721 internal constructor(td: TypeDesc) { 2722 this.td = td 2723 } 2724 2725 public override assignableFrom(other: Type): boolean { 2726 if (other instanceof UnionType) { 2727 const otherUnion = other as UnionType 2728 // all cases of other are assignable into this 2729 const otherCasesN = this.getCasesNum() 2730 for (let i = 0; i < otherCasesN; i++) { 2731 let cas = otherUnion.getCase(i) 2732 if (!this.assignableFrom(cas.getType())) { 2733 return false 2734 } 2735 } 2736 return true 2737 } 2738 // assignable to any case 2739 const selfCasesN = this.getCasesNum() 2740 for (let i = 0; i < selfCasesN; i++) { 2741 let cas = this.getCase(i) 2742 if (cas.getType().assignableFrom(other)) { 2743 return true 2744 } 2745 } 2746 return false 2747 } 2748 2749 /** 2750 * Checks whether type is primitive or composite 2751 * 2752 * @returns true if type is primitive and false otherwise 2753 */ 2754 public override isPrimitive(): boolean { 2755 return false 2756 } 2757 2758 /** 2759 * Checks whether type is reference or composite 2760 * 2761 * @returns true if type is reference and false otherwise 2762 */ 2763 public override isReference(): boolean { 2764 return true 2765 } 2766 2767 /** 2768 * Checks whether type has name 2769 * 2770 * @returns true if type has name 2771 */ 2772 public override hasName(): boolean { 2773 return false 2774 } 2775 2776 /** 2777 * Returns name of type 2778 * 2779 * @returns type name 2780 */ 2781 public override getName(): string { 2782 // NOTE(shumilov-petr): not implemented 2783 return "" 2784 } 2785 2786 /** 2787 * Returns literal of type if exists 2788 * 2789 * @returns type literal 2790 */ 2791 public override getLiteral(): string { 2792 // NOTE(shumilov-petr): not implemented 2793 return "(... | ...)" 2794 } 2795 2796 public getCasesNum(): long { 2797 // NOTE(kirill-mitkin): not implemented 2798 return 0 2799 } 2800 2801 public getCase(i: long): UnionCase { 2802 // NOTE(kirill-mitkin): not implemented 2803 throw new Error("Not implemented") 2804 } 2805 2806 /** 2807 * Checks for equality this instance with provided object, treated as a UnionType 2808 * 2809 * @param other type to be checked against 2810 * 2811 * @returns true if object also has UnionType and their cases are the same 2812 */ 2813 public override equals(other: Type): boolean { 2814 // NOTE(shumilov-petr): not implemented 2815 return false 2816 } 2817 2818 public make(default: Type): Object { 2819 // NOTE(shumilov-petr): not implemented 2820 throw new Error("not implemented") 2821 } 2822 2823 public make(default: Value): Object { 2824 // NOTE(shumilov-petr): not implemented 2825 throw new Error("not implemented") 2826 } 2827 2828 internal override convertObject(obj: NullishType): NullishType { 2829 const objType = Type.of(obj) 2830 if (this.equals(objType)) { 2831 return obj 2832 } 2833 if (!this.assignableFrom(objType)) { 2834 throw new Error("invalid conversion") 2835 } 2836 return obj 2837 } 2838} 2839