1/* 2 * Copyright (c) 2022 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 16import * as ts from "typescript"; 17import * as jshelpers from "../jshelpers"; 18import { PandaGen } from "../pandagen"; 19import { TypeChecker } from "../typeChecker"; 20import { TypeRecorder } from "../typeRecorder"; 21import { isGlobalDeclare } from "../strictMode"; 22import { 23 Literal, 24 LiteralBuffer, 25 LiteralTag 26} from "./literal"; 27import { hasAbstractModifier } from "./util"; 28import { CmdOptions } from "../cmdOptions"; 29import { getLiteralKey } from "./util"; 30import { CompilerDriver } from "../compilerDriver"; 31 32export enum PrimitiveType { 33 ANY, 34 NUMBER, 35 BOOLEAN, 36 VOID, 37 STRING, 38 SYMBOL, 39 NULL, 40 UNDEFINED, 41 INT, 42} 43 44export enum BuiltinType { 45 _HEAD = 20, 46 Function, 47 RangeError, 48 Error, 49 Object, 50 SyntaxError, 51 TypeError, 52 ReferenceError, 53 URIError, 54 Symbol, 55 EvalError, 56 Number, 57 parseFloat, 58 Date, 59 Boolean, 60 BigInt, 61 parseInt, 62 WeakMap, 63 RegExp, 64 Set, 65 Map, 66 WeakRef, 67 WeakSet, 68 FinalizationRegistry, 69 Array, 70 Uint8ClampedArray, 71 Uint8Array, 72 TypedArray, 73 Int8Array, 74 Uint16Array, 75 Uint32Array, 76 Int16Array, 77 Int32Array, 78 Float32Array, 79 Float64Array, 80 BigInt64Array, 81 BigUint64Array, 82 SharedArrayBuffer, 83 DataView, 84 String, 85 ArrayBuffer, 86 eval, 87 isFinite, 88 ArkPrivate, 89 print, 90 decodeURI, 91 decodeURIComponent, 92 isNaN, 93 encodeURI, 94 NaN, 95 globalThis, 96 encodeURIComponent, 97 Infinity, 98 Math, 99 JSON, 100 Atomics, 101 undefined, 102 Reflect, 103 Promise, 104 Proxy, 105 GeneratorFunction, 106 Intl, 107} 108 109export const userDefinedTypeStartIndex = 100; 110let literalBufferIndexShift = userDefinedTypeStartIndex; 111 112export enum L2Type { 113 _COUNTER, 114 CLASS, 115 CLASSINST, 116 FUNCTION, 117 UNION, 118 ARRAY, 119 OBJECT, 120 EXTERNAL, 121 INTERFACE, 122 BUILTINCONTAINER 123} 124 125 126export enum ClassModifierAbstract { 127 NONABSTRACT, 128 ABSTRACT 129} 130 131export enum MethodModifier { 132 STATIC = 1 << 2, 133 ASYNC = 1 << 3, 134 ASTERISK = 1 << 4, 135 ABSTRACT = 1 << 6, // The fifth bit is held by GetOrSetAccessorFlag 136 DECLARE = 1 << 7 137} 138 139export enum ModifierReadonly { 140 NONREADONLY, 141 READONLY 142} 143 144export enum AccessFlag { 145 PUBLIC, 146 PRIVATE, 147 PROTECTED 148} 149 150export enum GetOrSetAccessorFlag { 151 FALSE = 0, // Not GetAccessor and SetAccessor 152 TRUE = 1 << 5 // GetAccessor or SetAccessor 153} 154 155type ClassMemberFunction = ts.MethodDeclaration | ts.ConstructorDeclaration | 156 ts.GetAccessorDeclaration | ts.SetAccessorDeclaration; 157 158export abstract class BaseType { 159 160 abstract transfer2LiteralBuffer(): LiteralBuffer; 161 protected typeChecker = TypeChecker.getInstance(); 162 protected typeRecorder = TypeRecorder.getInstance(); 163 164 protected transferType2Literal(type: number, literals: Array<Literal>) { 165 if (type >= literalBufferIndexShift) { 166 let litId = getLiteralKey(CompilerDriver.srcNode, type - literalBufferIndexShift); 167 literals.push(new Literal(LiteralTag.LITERALARRAY, litId)); 168 } else { 169 literals.push(new Literal(LiteralTag.BUILTINTYPEINDEX, type)); 170 } 171 } 172 173 protected addCurrentType(node: ts.Node, index: number): void { 174 this.typeRecorder.addType2Index(node, index); 175 } 176 177 protected setVariable2Type(variableNode: ts.Node, index: number): void { 178 this.typeRecorder.setVariable2Type(variableNode, index); 179 } 180 181 protected tryGetTypeIndex(typeNode: ts.Node): number { 182 return this.typeRecorder.tryGetTypeIndex(typeNode); 183 } 184 185 protected getOrCreateRecordForDeclNode(typeNode: ts.Node, variableNode?: ts.Node): PrimitiveType { 186 return this.typeChecker.getOrCreateRecordForDeclNode(typeNode, variableNode); 187 } 188 189 protected getOrCreateRecordForTypeNode(typeNode: ts.TypeNode | undefined, variableNode?: ts.Node): PrimitiveType { 190 return this.typeChecker.getOrCreateRecordForTypeNode(typeNode, variableNode); 191 } 192 193 protected getIndexFromTypeArrayBuffer(type: BaseType): number { 194 return PandaGen.appendTypeArrayBuffer(type); 195 } 196 197 protected setTypeArrayBuffer(type: BaseType, index: number): void { 198 PandaGen.setTypeArrayBuffer(type, index); 199 } 200 201 protected calculateIndex(builtinTypeIdx): { typeIndex: number; shiftedTypeIndex: number; } { 202 let typeIndex: number; 203 let shiftedTypeIndex: number; 204 let recordBuiltin = builtinTypeIdx && CmdOptions.needRecordBuiltinDtsType(); 205 if (recordBuiltin) { 206 typeIndex = undefined; 207 shiftedTypeIndex = builtinTypeIdx; 208 if (isGlobalDeclare()) { 209 typeIndex = builtinTypeIdx - BuiltinType._HEAD; 210 } 211 } else { 212 typeIndex = this.getIndexFromTypeArrayBuffer(new PlaceHolderType()); 213 shiftedTypeIndex = typeIndex + literalBufferIndexShift; 214 } 215 return {typeIndex: typeIndex, shiftedTypeIndex: shiftedTypeIndex}; 216 } 217 218} 219 220export class PlaceHolderType extends BaseType { 221 transfer2LiteralBuffer(): LiteralBuffer { 222 return new LiteralBuffer(); 223 } 224} 225 226export class TypeSummary extends BaseType { 227 preservedIndex: number = 0; 228 userDefinedClassNum: number = 0; 229 anonymousRedirect: Array<string> = new Array<string>(); 230 constructor() { 231 super(); 232 this.preservedIndex = this.getIndexFromTypeArrayBuffer(new PlaceHolderType()); 233 if (isGlobalDeclare()) { 234 let builtinTypeSlotNum = userDefinedTypeStartIndex - BuiltinType._HEAD; 235 for (let i = 0; i < builtinTypeSlotNum; i++) { 236 this.getIndexFromTypeArrayBuffer(new PlaceHolderType()); 237 } 238 literalBufferIndexShift = BuiltinType._HEAD; 239 } 240 } 241 242 public setInfo(userDefinedClassNum: number, anonymousRedirect: Array<string>): void { 243 this.userDefinedClassNum = userDefinedClassNum; 244 this.anonymousRedirect = anonymousRedirect; 245 this.setTypeArrayBuffer(this, this.preservedIndex); 246 } 247 248 public getPreservedIndex() { 249 return this.preservedIndex; 250 } 251 252 transfer2LiteralBuffer(): LiteralBuffer { 253 let countBuf = new LiteralBuffer(); 254 let summaryLiterals: Array<Literal> = new Array<Literal>(); 255 let definedTypeNum = this.userDefinedClassNum; 256 if (isGlobalDeclare()) { 257 definedTypeNum += userDefinedTypeStartIndex - BuiltinType._HEAD; 258 } 259 summaryLiterals.push(new Literal(LiteralTag.INTEGER, definedTypeNum)); 260 let literalIdx = PandaGen.getLiteralArrayBuffer.length; 261 for (let i = 1; i <= definedTypeNum; i++) { 262 summaryLiterals.push(new Literal(LiteralTag.LITERALARRAY, 263 getLiteralKey(CompilerDriver.srcNode, literalIdx + i))); 264 } 265 summaryLiterals.push(new Literal(LiteralTag.INTEGER, this.anonymousRedirect.length)); 266 for (let element of this.anonymousRedirect) { 267 summaryLiterals.push(new Literal(LiteralTag.STRING, element)); 268 } 269 countBuf.addLiterals(...summaryLiterals); 270 return countBuf; 271 } 272} 273 274export class ClassType extends BaseType { 275 modifier: number = ClassModifierAbstract.NONABSTRACT; // 0 -> unabstract, 1 -> abstract; 276 extendsHeritage: number = PrimitiveType.ANY; 277 implementsHeritages: Array<number> = new Array<number>(); 278 // fileds Array: [typeIndex] [public -> 0, private -> 1, protected -> 2] [readonly -> 1] 279 staticFields: Map<string, Array<number>> = new Map<string, Array<number>>(); 280 staticMethods: Map<string, {typeIndex: number, isDeclare: boolean}> = new Map<string, {typeIndex: number, isDeclare: boolean}>(); 281 fields: Map<string, Array<number>> = new Map<string, Array<number>>(); 282 methods: Map<string, {typeIndex: number, isDeclare: boolean}> = new Map<string, {typeIndex: number, isDeclare: boolean}>(); 283 typeIndex: number; 284 shiftedTypeIndex: number; 285 field_with_init_num: number = 0; 286 method_with_body_num: number = 0; 287 288 constructor(classNode: ts.ClassDeclaration | ts.ClassExpression, builtinTypeIdx: number = undefined) { 289 super(); 290 let res = this.calculateIndex(builtinTypeIdx); 291 this.typeIndex = res.typeIndex; 292 this.shiftedTypeIndex = res.shiftedTypeIndex; 293 294 // record type before its initialization, so its index can be recorded 295 // in case there's recursive reference of this type 296 this.addCurrentType(classNode, this.shiftedTypeIndex); 297 this.fillInModifiers(classNode); 298 this.fillInHeritages(classNode); 299 this.fillInFieldsAndMethods(classNode); 300 301 if (!builtinTypeIdx || isGlobalDeclare()) { 302 this.setTypeArrayBuffer(this, this.typeIndex); 303 } 304 305 // create class instance type used by recording 'this' later 306 if ((this.method_with_body_num > 0 || this.field_with_init_num > 0) && !hasAbstractModifier(classNode)) { 307 let instTypeIdx = this.typeChecker.getOrCreateInstanceType(this.shiftedTypeIndex); 308 this.typeRecorder.addUserDefinedTypeSet(instTypeIdx); 309 } 310 } 311 312 private fillInModifiers(node: ts.ClassDeclaration | ts.ClassExpression): void { 313 if (node.modifiers) { 314 for (let modifier of node.modifiers) { 315 switch (modifier.kind) { 316 case ts.SyntaxKind.AbstractKeyword: { 317 this.modifier = ClassModifierAbstract.ABSTRACT; 318 break; 319 } 320 default: { 321 break; 322 } 323 } 324 } 325 } 326 } 327 328 private fillInHeritages(node: ts.ClassDeclaration | ts.ClassExpression): void { 329 if (node.heritageClauses) { 330 for (let heritage of node.heritageClauses) { 331 let heritageFullName = heritage.getText(); 332 for (let heritageType of heritage.types) { 333 let heritageIdentifier = <ts.Identifier>heritageType.expression; 334 let heritageTypeIndex = this.getOrCreateRecordForDeclNode(heritageIdentifier, heritageIdentifier); 335 if (heritageFullName.startsWith("extends ")) { 336 this.extendsHeritage = heritageTypeIndex; 337 } else if (heritageFullName.startsWith("implements ")) { 338 this.implementsHeritages.push(heritageTypeIndex); 339 } 340 } 341 } 342 } 343 } 344 345 private fillInFields(member: ts.PropertyDeclaration): void { 346 let fieldName = jshelpers.getTextOfIdentifierOrLiteral(member.name); 347 let fieldInfo = Array<number>(PrimitiveType.ANY, AccessFlag.PUBLIC, ModifierReadonly.NONREADONLY); 348 let isStatic: boolean = false; 349 if (member.modifiers) { 350 for (let modifier of member.modifiers) { 351 switch (modifier.kind) { 352 case ts.SyntaxKind.StaticKeyword: { 353 isStatic = true; 354 break; 355 } 356 case ts.SyntaxKind.PrivateKeyword: { 357 fieldInfo[1] = AccessFlag.PRIVATE; 358 break; 359 } 360 case ts.SyntaxKind.ProtectedKeyword: { 361 fieldInfo[1] = AccessFlag.PROTECTED; 362 break; 363 } 364 case ts.SyntaxKind.ReadonlyKeyword: { 365 fieldInfo[2] = ModifierReadonly.READONLY; 366 break; 367 } 368 default: { 369 break; 370 } 371 } 372 } 373 } 374 375 let typeNode = member.type; 376 let memberName = member.name; 377 fieldInfo[0] = this.getOrCreateRecordForTypeNode(typeNode, memberName); 378 379 if (isStatic) { 380 this.staticFields.set(fieldName, fieldInfo); 381 } else { 382 this.fields.set(fieldName, fieldInfo); 383 if (member.initializer != undefined) { 384 this.field_with_init_num++; 385 } 386 } 387 } 388 389 private fillInMethods(member: ClassMemberFunction): void { 390 /** 391 * a method like declaration in a new class must be a new type, 392 * create this type and add it into typeRecorder if it's not from tsc's library 393 */ 394 if (this.typeChecker.isFromDefaultLib(member)) { 395 return; 396 } 397 // Keep the rule to get the name as the same as to get function's name in FunctionType 398 let funcName = member.name ? jshelpers.getTextOfIdentifierOrLiteral(member.name) : "constructor"; 399 let isStatic = false; 400 if (member.modifiers) { 401 for (let modifier of member.modifiers) { 402 if (modifier.kind == ts.SyntaxKind.StaticKeyword) { 403 isStatic = true; 404 } 405 } 406 } 407 let foundSameNameFuncRet = isStatic ? this.staticMethods.get(funcName) : this.methods.get(funcName); 408 if (foundSameNameFuncRet && !foundSameNameFuncRet.isDeclare) { 409 // A same named method with implementation has already been recorded 410 return; 411 } 412 let variableNode = member.name ? member.name : undefined; 413 let funcType = new FunctionType(<ts.FunctionLikeDeclaration>member); 414 if (variableNode) { 415 this.setVariable2Type(variableNode, funcType.shiftedTypeIndex); 416 } 417 418 // Then, get the typeIndex and fill in the methods array 419 let type = this.tryGetTypeIndex(member); 420 if (isStatic) { 421 this.staticMethods.set(funcType.getFunctionName(), {typeIndex: type!, isDeclare: member.body == undefined}); 422 } else { 423 this.methods.set(funcType.getFunctionName(), {typeIndex: type!, isDeclare: member.body == undefined}); 424 if (member.body != undefined) { 425 this.method_with_body_num++; 426 } 427 } 428 } 429 430 private fillInFieldsAndMethods(node: ts.ClassDeclaration | ts.ClassExpression): void { 431 if (node.members) { 432 for (let member of node.members) { 433 switch (member.kind) { 434 case ts.SyntaxKind.MethodDeclaration: 435 case ts.SyntaxKind.Constructor: 436 case ts.SyntaxKind.GetAccessor: 437 case ts.SyntaxKind.SetAccessor: { 438 this.fillInMethods(<ClassMemberFunction>member); 439 break; 440 } 441 case ts.SyntaxKind.PropertyDeclaration: { 442 this.fillInFields(<ts.PropertyDeclaration>member); 443 break; 444 } 445 default: 446 break; 447 } 448 } 449 } 450 } 451 452 transfer2LiteralBuffer(): LiteralBuffer { 453 if (!this.typeIndex) { 454 return; 455 } 456 let classTypeBuf = new LiteralBuffer(); 457 let classTypeLiterals: Array<Literal> = new Array<Literal>(); 458 // the first element is to determine the L2 type 459 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.CLASS)); 460 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.modifier)); 461 462 this.transferType2Literal(this.extendsHeritage, classTypeLiterals); 463 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.implementsHeritages.length)); 464 this.implementsHeritages.forEach(heritage => { // heritage types 465 this.transferType2Literal(heritage, classTypeLiterals); 466 }); 467 468 // record unstatic fields and methods 469 this.transferFields2Literal(classTypeLiterals, false); 470 this.transferMethods2Literal(classTypeLiterals, false); 471 472 // record static methods and fields; 473 this.transferFields2Literal(classTypeLiterals, true); 474 this.transferMethods2Literal(classTypeLiterals, true); 475 476 classTypeBuf.addLiterals(...classTypeLiterals); 477 return classTypeBuf; 478 } 479 480 private transferFields2Literal(classTypeLiterals: Array<Literal>, isStatic: boolean): void { 481 let transferredTarget: Map<string, Array<number>> = isStatic ? this.staticFields : this.fields; 482 483 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, transferredTarget.size)); 484 transferredTarget.forEach((typeInfo, name) => { 485 classTypeLiterals.push(new Literal(LiteralTag.STRING, name)); 486 this.transferType2Literal(typeInfo[0], classTypeLiterals); 487 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, typeInfo[1])); // accessFlag 488 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, typeInfo[2])); // readonly 489 }); 490 } 491 492 private transferMethods2Literal(classTypeLiterals: Array<Literal>, isStatic: boolean): void { 493 let transferredTarget: Map<string, {typeIndex: number, isDeclare: boolean}> = isStatic ? this.staticMethods : this.methods; 494 495 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, transferredTarget.size)); 496 transferredTarget.forEach((typeInfo, name) => { 497 let typeIndex: number = <number>typeInfo.typeIndex; 498 classTypeLiterals.push(new Literal(LiteralTag.STRING, name)); 499 this.transferType2Literal(typeIndex, classTypeLiterals); 500 }); 501 } 502} 503 504export class ClassInstType extends BaseType { 505 shiftedReferredClassIndex: number; // the referred class in the type system; 506 typeIndex: number; 507 shiftedTypeIndex: number; 508 constructor(referredClassIndex: number) { 509 super(); 510 this.shiftedReferredClassIndex = referredClassIndex; 511 this.typeIndex = this.getIndexFromTypeArrayBuffer(this); 512 this.shiftedTypeIndex = this.typeIndex + literalBufferIndexShift; 513 this.typeRecorder.setClass2InstanceMap(this.shiftedReferredClassIndex, this.shiftedTypeIndex); 514 if (this.shiftedReferredClassIndex > BuiltinType._HEAD) { 515 this.typeRecorder.addUserDefinedTypeSet(this.shiftedTypeIndex); 516 } 517 } 518 519 transfer2LiteralBuffer(): LiteralBuffer { 520 let classInstBuf = new LiteralBuffer(); 521 let classInstLiterals: Array<Literal> = new Array<Literal>(); 522 523 classInstLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.CLASSINST)); 524 this.transferType2Literal(this.shiftedReferredClassIndex, classInstLiterals); 525 classInstBuf.addLiterals(...classInstLiterals); 526 527 return classInstBuf; 528 } 529} 530 531export class FunctionType extends BaseType { 532 name: string = ''; 533 accessFlag: number = AccessFlag.PUBLIC; // 0 -> public, 1 -> private, 2 -> protected 534 modifiers: number = 0; // 0 -> non-static, 4 -> static, 8 -> async, 16-> asterisk 535 containThisParam: boolean = false; 536 parameters: Array<number> = new Array<number>(); 537 returnType: number = PrimitiveType.ANY; 538 typeIndex: number; 539 shiftedTypeIndex: number; 540 getOrSetAccessorFlag: GetOrSetAccessorFlag = GetOrSetAccessorFlag.FALSE; 541 542 constructor(funcNode: ts.FunctionLikeDeclaration | ts.MethodSignature, builtinTypeIdx: number = undefined) { 543 super(); 544 let res = this.calculateIndex(builtinTypeIdx); 545 this.typeIndex = res.typeIndex; 546 this.shiftedTypeIndex = res.shiftedTypeIndex; 547 if (funcNode.kind === ts.SyntaxKind.GetAccessor || funcNode.kind === ts.SyntaxKind.SetAccessor) { 548 this.getOrSetAccessorFlag = GetOrSetAccessorFlag.TRUE; 549 } 550 551 // record type before its initialization, so its index can be recorded 552 // in case there's recursive reference of this type 553 this.addCurrentType(funcNode, this.shiftedTypeIndex); 554 555 if (funcNode.name) { 556 this.name = jshelpers.getTextOfIdentifierOrLiteral(funcNode.name); 557 } else { 558 this.name = "constructor"; 559 } 560 this.fillInModifiers(funcNode); 561 this.fillInParameters(funcNode); 562 this.fillInReturn(funcNode); 563 this.setTypeArrayBuffer(this, this.typeIndex); 564 } 565 566 public getFunctionName(): string { 567 return this.name; 568 } 569 570 private fillInModifiers(node: ts.FunctionLikeDeclaration | ts.MethodSignature): void { 571 if (node.modifiers) { 572 for (let modifier of node.modifiers) { 573 switch (modifier.kind) { 574 case ts.SyntaxKind.PrivateKeyword: { 575 this.accessFlag = AccessFlag.PRIVATE; 576 break; 577 } 578 case ts.SyntaxKind.ProtectedKeyword: { 579 this.accessFlag = AccessFlag.PROTECTED; 580 break; 581 } 582 case ts.SyntaxKind.StaticKeyword: { 583 this.modifiers = MethodModifier.STATIC; 584 break; 585 } 586 case ts.SyntaxKind.AsyncKeyword: { 587 this.modifiers += MethodModifier.ASYNC; 588 break; 589 } 590 case ts.SyntaxKind.AbstractKeyword: { 591 this.modifiers += MethodModifier.ABSTRACT; 592 break; 593 } 594 default: 595 break; 596 } 597 } 598 } 599 600 if (!ts.isMethodSignature(node) && node.asteriskToken) { 601 this.modifiers += MethodModifier.ASTERISK; 602 } 603 if (ts.isMethodSignature(node) || !<ts.FunctionLikeDeclaration>node.body) { 604 this.modifiers += MethodModifier.DECLARE; 605 } 606 } 607 608 private fillInParameters(node: ts.FunctionLikeDeclaration | ts.MethodSignature): void { 609 if (node.parameters) { 610 for (let parameter of node.parameters) { 611 let typeNode = parameter.type; 612 let variableNode = parameter.name; 613 let typeIndex = this.getOrCreateRecordForTypeNode(typeNode, variableNode); 614 this.parameters.push(typeIndex); 615 if (variableNode.getFullText() === 'this') { 616 this.containThisParam = true; 617 } 618 } 619 } 620 } 621 622 private fillInReturn(node: ts.FunctionLikeDeclaration | ts.MethodSignature): void { 623 let typeNode = node.type; 624 let typeIndex = this.getOrCreateRecordForTypeNode(typeNode, typeNode); 625 this.returnType = typeIndex; 626 } 627 628 getModifier(): number { 629 return this.modifiers; 630 } 631 632 hasModifier(modifier: MethodModifier): boolean { 633 return (this.modifiers & modifier) ? true : false; 634 } 635 636 transfer2LiteralBuffer(): LiteralBuffer { 637 let funcTypeBuf = new LiteralBuffer(); 638 let funcTypeLiterals: Array<Literal> = new Array<Literal>(); 639 funcTypeLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.FUNCTION)); 640 funcTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.accessFlag + this.modifiers + this.getOrSetAccessorFlag)); 641 funcTypeLiterals.push(new Literal(LiteralTag.STRING, this.name)); 642 if (this.containThisParam) { 643 funcTypeLiterals.push(new Literal(LiteralTag.INTEGER, 1)); // marker for having 'this' param 644 this.transferType2Literal(this.parameters[0], funcTypeLiterals); 645 funcTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.parameters.length - 1)); 646 for (let i = 1; i < this.parameters.length; i++) { // normal parameter types 647 this.transferType2Literal(this.parameters[i], funcTypeLiterals); 648 } 649 } else { 650 funcTypeLiterals.push(new Literal(LiteralTag.INTEGER, 0)); // marker for not having 'this' param 651 funcTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.parameters.length)); 652 for (let i = 0; i < this.parameters.length; i++) { 653 this.transferType2Literal(this.parameters[i], funcTypeLiterals); 654 } 655 } 656 657 this.transferType2Literal(this.returnType, funcTypeLiterals); 658 funcTypeBuf.addLiterals(...funcTypeLiterals); 659 return funcTypeBuf; 660 } 661} 662 663export class ExternalType extends BaseType { 664 fullRedirectNath: string; 665 typeIndex: number; 666 shiftedTypeIndex: number; 667 668 constructor(importName: string, redirectPath: string) { 669 super(); 670 this.fullRedirectNath = `#${importName}#${redirectPath}`; 671 this.typeIndex = this.getIndexFromTypeArrayBuffer(this); 672 this.shiftedTypeIndex = this.typeIndex + literalBufferIndexShift; 673 } 674 675 transfer2LiteralBuffer(): LiteralBuffer { 676 let impTypeBuf = new LiteralBuffer(); 677 let impTypeLiterals: Array<Literal> = new Array<Literal>(); 678 impTypeLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.EXTERNAL)); 679 impTypeLiterals.push(new Literal(LiteralTag.STRING, this.fullRedirectNath)); 680 impTypeBuf.addLiterals(...impTypeLiterals); 681 return impTypeBuf; 682 } 683} 684 685export class UnionType extends BaseType { 686 unionedTypeArray: Array<number> = []; 687 typeIndex: number = PrimitiveType.ANY; 688 shiftedTypeIndex: number = PrimitiveType.ANY; 689 690 constructor(typeNode: ts.Node) { 691 super(); 692 this.setOrReadFromArrayRecord(typeNode); 693 } 694 695 setOrReadFromArrayRecord(typeNode: ts.Node): void { 696 let unionStr = typeNode.getText(); 697 if (this.hasUnionTypeMapping(unionStr)) { 698 this.shiftedTypeIndex = this.getFromUnionTypeMap(unionStr)!; 699 return; 700 } 701 this.typeIndex = this.getIndexFromTypeArrayBuffer(new PlaceHolderType()); 702 this.shiftedTypeIndex = this.typeIndex + literalBufferIndexShift; 703 this.fillInUnionArray(typeNode, this.unionedTypeArray); 704 this.setUnionTypeMap(unionStr, this.shiftedTypeIndex); 705 this.setTypeArrayBuffer(this, this.typeIndex); 706 } 707 708 hasUnionTypeMapping(unionStr: string): boolean { 709 return this.typeRecorder.hasUnionTypeMapping(unionStr); 710 } 711 712 getFromUnionTypeMap(unionStr: string): number { 713 return this.typeRecorder.getFromUnionTypeMap(unionStr); 714 } 715 716 setUnionTypeMap(unionStr: string, shiftedTypeIndex: number): void { 717 return this.typeRecorder.setUnionTypeMap(unionStr, shiftedTypeIndex); 718 } 719 720 fillInUnionArray(typeNode: ts.Node, unionedTypeArray: Array<number>): void { 721 for (let element of (<ts.UnionType><any>typeNode).types) { 722 let elementNode = <ts.TypeNode><any>element; 723 let typeIndex = this.getOrCreateRecordForTypeNode(elementNode, elementNode); 724 unionedTypeArray.push(typeIndex!); 725 } 726 } 727 728 transfer2LiteralBuffer(): LiteralBuffer { 729 let unionTypeBuf = new LiteralBuffer(); 730 let unionTypeLiterals: Array<Literal> = new Array<Literal>(); 731 unionTypeLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.UNION)); 732 unionTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.unionedTypeArray.length)); 733 for (let type of this.unionedTypeArray) { 734 this.transferType2Literal(type, unionTypeLiterals); 735 } 736 unionTypeBuf.addLiterals(...unionTypeLiterals); 737 return unionTypeBuf; 738 } 739} 740 741export class ArrayType extends BaseType { 742 referedTypeIndex: number = PrimitiveType.ANY; 743 typeIndex: number = PrimitiveType.ANY; 744 shiftedTypeIndex: number = PrimitiveType.ANY; 745 constructor(typeNode: ts.Node) { 746 super(); 747 let elementNode = (<ts.ArrayTypeNode><any>typeNode).elementType; 748 this.referedTypeIndex = this.getOrCreateRecordForTypeNode(elementNode, elementNode); 749 this.setOrReadFromArrayRecord(); 750 } 751 752 setOrReadFromArrayRecord(): void { 753 if (this.hasArrayTypeMapping(this.referedTypeIndex)) { 754 this.shiftedTypeIndex = this.getFromArrayTypeMap(this.referedTypeIndex)!; 755 } else { 756 this.typeIndex = this.getIndexFromTypeArrayBuffer(this); 757 this.shiftedTypeIndex = this.typeIndex + literalBufferIndexShift; 758 this.setTypeArrayBuffer(this, this.typeIndex); 759 this.setArrayTypeMap(this.referedTypeIndex, this.shiftedTypeIndex); 760 } 761 } 762 763 hasArrayTypeMapping(referedTypeIndex: number): boolean { 764 return this.typeRecorder.hasArrayTypeMapping(referedTypeIndex); 765 } 766 767 getFromArrayTypeMap(referedTypeIndex: number): number { 768 return this.typeRecorder.getFromArrayTypeMap(referedTypeIndex); 769 } 770 771 setArrayTypeMap(referedTypeIndex: number, shiftedTypeIndex: number): void { 772 return this.typeRecorder.setArrayTypeMap(referedTypeIndex, shiftedTypeIndex); 773 } 774 775 transfer2LiteralBuffer(): LiteralBuffer { 776 let arrayBuf = new LiteralBuffer(); 777 let arrayLiterals: Array<Literal> = new Array<Literal>(); 778 arrayLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.ARRAY)); 779 this.transferType2Literal(this.referedTypeIndex, arrayLiterals); 780 arrayBuf.addLiterals(...arrayLiterals); 781 return arrayBuf; 782 } 783} 784 785export class ObjectType extends BaseType { 786 private properties: Map<string, number> = new Map<string, number>(); 787 typeIndex: number = PrimitiveType.ANY; 788 shiftedTypeIndex: number = PrimitiveType.ANY; 789 790 constructor(objNode: ts.TypeLiteralNode) { 791 super(); 792 this.typeIndex = this.getIndexFromTypeArrayBuffer(new PlaceHolderType()); 793 this.shiftedTypeIndex = this.typeIndex + literalBufferIndexShift; 794 this.fillInMembers(objNode); 795 this.setTypeArrayBuffer(this, this.typeIndex); 796 } 797 798 fillInMembers(objNode: ts.TypeLiteralNode): void { 799 for (let member of objNode.members) { 800 let propertySig = <ts.PropertySignature>member; 801 let name = member.name ? member.name.getText() : "#undefined"; 802 let typeIndex = this.getOrCreateRecordForTypeNode(propertySig.type, member.name); 803 this.properties.set(name, typeIndex); 804 } 805 } 806 807 transfer2LiteralBuffer(): LiteralBuffer { 808 let objTypeBuf = new LiteralBuffer(); 809 let objLiterals: Array<Literal> = new Array<Literal>(); 810 objLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.OBJECT)); 811 objLiterals.push(new Literal(LiteralTag.INTEGER, this.properties.size)); 812 this.properties.forEach((typeIndex, name) => { 813 objLiterals.push(new Literal(LiteralTag.STRING, name)); 814 this.transferType2Literal(typeIndex, objLiterals); 815 }); 816 objTypeBuf.addLiterals(...objLiterals); 817 return objTypeBuf; 818 } 819} 820 821export class InterfaceType extends BaseType { 822 heritages: Array<number> = new Array<number>(); 823 // fileds Array: [typeIndex] [public -> 0, private -> 1, protected -> 2] [readonly -> 1] 824 fields: Map<string, Array<number>> = new Map<string, Array<number>>(); 825 methods: Array<number> = new Array<number>(); 826 typeIndex: number; 827 shiftedTypeIndex: number; 828 829 constructor(interfaceNode: ts.InterfaceDeclaration) { 830 super(); 831 this.typeIndex = this.getIndexFromTypeArrayBuffer(new PlaceHolderType()); 832 this.shiftedTypeIndex = this.typeIndex + literalBufferIndexShift; 833 // record type before its initialization, so its index can be recorded 834 // in case there's recursive reference of this type 835 this.addCurrentType(interfaceNode, this.shiftedTypeIndex); 836 this.fillInHeritages(interfaceNode); 837 this.fillInFieldsAndMethods(interfaceNode); 838 this.setTypeArrayBuffer(this, this.typeIndex); 839 } 840 841 private fillInHeritages(node: ts.InterfaceDeclaration): void { 842 if (node.heritageClauses) { 843 for (let heritage of node.heritageClauses) { 844 for (let heritageType of heritage.types) { 845 let heritageIdentifier = <ts.Identifier>heritageType.expression; 846 let heritageTypeIndex = this.getOrCreateRecordForDeclNode(heritageIdentifier, heritageIdentifier); 847 this.heritages.push(heritageTypeIndex); 848 } 849 } 850 } 851 } 852 853 private fillInFields(member: ts.PropertySignature): void { 854 let fieldName = jshelpers.getTextOfIdentifierOrLiteral(member.name); 855 let fieldInfo = Array<number>(PrimitiveType.ANY, AccessFlag.PUBLIC, ModifierReadonly.NONREADONLY); 856 if (member.modifiers) { 857 for (let modifier of member.modifiers) { 858 switch (modifier.kind) { 859 case ts.SyntaxKind.PrivateKeyword: { 860 fieldInfo[1] = AccessFlag.PRIVATE; 861 break; 862 } 863 case ts.SyntaxKind.ProtectedKeyword: { 864 fieldInfo[1] = AccessFlag.PROTECTED; 865 break; 866 } 867 case ts.SyntaxKind.ReadonlyKeyword: { 868 fieldInfo[2] = ModifierReadonly.READONLY; 869 break; 870 } 871 default: 872 break; 873 } 874 } 875 } 876 let typeNode = member.type; 877 let memberName = member.name; 878 fieldInfo[0] = this.getOrCreateRecordForTypeNode(typeNode, memberName); 879 this.fields.set(fieldName, fieldInfo); 880 } 881 882 private fillInMethods(member: ts.MethodSignature): void { 883 /** 884 * a method like declaration in a new class must be a new type, 885 * create this type and add it into typeRecorder if it's not from tsc's library 886 */ 887 if (this.typeChecker.isFromDefaultLib(member)) { 888 return; 889 } 890 let variableNode = member.name ? member.name : undefined; 891 let funcType = new FunctionType(<ts.MethodSignature>member); 892 if (variableNode) { 893 this.setVariable2Type(variableNode, funcType.shiftedTypeIndex); 894 } 895 // Then, get the typeIndex and fill in the methods array 896 let typeIndex = this.tryGetTypeIndex(member); 897 this.methods.push(typeIndex!); 898 } 899 900 private fillInFieldsAndMethods(node: ts.InterfaceDeclaration): void { 901 if (node.members) { 902 for (let member of node.members) { 903 switch (member.kind) { 904 case ts.SyntaxKind.MethodSignature: { 905 this.fillInMethods(<ts.MethodSignature>member); 906 break; 907 } 908 case ts.SyntaxKind.PropertySignature: { 909 this.fillInFields(<ts.PropertySignature>member); 910 break; 911 } 912 default: 913 break; 914 } 915 } 916 } 917 } 918 919 transfer2LiteralBuffer(): LiteralBuffer { 920 let interfaceTypeBuf = new LiteralBuffer(); 921 let interfaceTypeLiterals: Array<Literal> = new Array<Literal>(); 922 // the first element is to determine the L2 type 923 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.INTERFACE)); 924 925 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.heritages.length)); 926 this.heritages.forEach(heritage => { 927 this.transferType2Literal(heritage, interfaceTypeLiterals) 928 }); 929 930 // record fields and methods 931 this.transferFields2Literal(interfaceTypeLiterals); 932 this.transferMethods2Literal(interfaceTypeLiterals); 933 934 interfaceTypeBuf.addLiterals(...interfaceTypeLiterals); 935 return interfaceTypeBuf; 936 } 937 938 private transferFields2Literal(interfaceTypeLiterals: Array<Literal>): void { 939 let transferredTarget: Map<string, Array<number>> = this.fields; 940 941 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, transferredTarget.size)); 942 transferredTarget.forEach((typeInfo, name) => { 943 interfaceTypeLiterals.push(new Literal(LiteralTag.STRING, name)); 944 this.transferType2Literal(typeInfo[0], interfaceTypeLiterals); 945 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, typeInfo[1])); // accessFlag 946 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, typeInfo[2])); // readonly 947 }); 948 } 949 950 private transferMethods2Literal(interfaceTypeLiterals: Array<Literal>): void { 951 let transferredTarget: Array<number> = this.methods; 952 953 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, transferredTarget.length)); 954 transferredTarget.forEach(method => { 955 this.transferType2Literal(method, interfaceTypeLiterals); 956 }); 957 } 958} 959 960export class BuiltinContainerType extends BaseType { 961 containerArray: Array<number> = []; 962 builtinTypeIndex: number; 963 typeIndex: number = PrimitiveType.ANY; 964 shiftedTypeIndex: number = PrimitiveType.ANY; 965 966 constructor(builtinContainerSignature: object) { 967 super(); 968 this.builtinTypeIndex = builtinContainerSignature['typeIndex']; 969 this.containerArray = builtinContainerSignature['typeArgIdxs']; 970 this.typeIndex = this.getIndexFromTypeArrayBuffer(this); 971 this.shiftedTypeIndex = this.typeIndex + literalBufferIndexShift; 972 this.setBuiltinContainer2InstanceMap(builtinContainerSignature, this.shiftedTypeIndex); 973 } 974 975 setBuiltinContainer2InstanceMap(builtinContainerSignature: object, index: number): void { 976 return this.typeRecorder.setBuiltinContainer2InstanceMap(builtinContainerSignature, index); 977 } 978 979 transfer2LiteralBuffer(): LiteralBuffer { 980 let BuiltinContainerBuf = new LiteralBuffer(); 981 let BuiltinContainerLiterals: Array<Literal> = new Array<Literal>(); 982 BuiltinContainerLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.BUILTINCONTAINER)); 983 this.transferType2Literal(this.builtinTypeIndex, BuiltinContainerLiterals); 984 BuiltinContainerLiterals.push(new Literal(LiteralTag.INTEGER, this.containerArray.length)); 985 for (let type of this.containerArray) { 986 BuiltinContainerLiterals.push(new Literal(LiteralTag.INTEGER, type)); 987 } 988 BuiltinContainerBuf.addLiterals(...BuiltinContainerLiterals); 989 return BuiltinContainerBuf; 990 } 991} 992