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 { 22 Literal, 23 LiteralBuffer, 24 LiteralTag 25} from "./literal"; 26 27export enum PrimitiveType { 28 ANY, 29 NUMBER, 30 BOOLEAN, 31 VOID, 32 STRING, 33 SYMBOL, 34 NULL, 35 UNDEFINED, 36 INT, 37 _LENGTH = 50 38} 39 40export enum L2Type { 41 _COUNTER, 42 CLASS, 43 CLASSINST, 44 FUNCTION, 45 UNION, 46 ARRAY, 47 OBJECT, 48 EXTERNAL, 49 INTERFACE 50} 51 52export enum ModifierAbstract { 53 NONABSTRACT, 54 ABSTRACT 55} 56 57export enum ModifierStatic { 58 NONSTATIC, 59 STATIC 60} 61 62export enum ModifierReadonly { 63 NONREADONLY, 64 READONLY 65} 66 67export enum AccessFlag { 68 PUBLIC, 69 PRIVATE, 70 PROTECTED 71} 72 73type ClassMemberFunction = ts.MethodDeclaration | ts.ConstructorDeclaration | ts.GetAccessorDeclaration | ts.SetAccessorDeclaration; 74 75export abstract class BaseType { 76 77 abstract transfer2LiteralBuffer(): LiteralBuffer; 78 protected typeChecker = TypeChecker.getInstance(); 79 protected typeRecorder = TypeRecorder.getInstance(); 80 81 protected addCurrentType(node: ts.Node, index: number) { 82 this.typeRecorder.addType2Index(node, index); 83 } 84 85 protected setVariable2Type(variableNode: ts.Node, index: number) { 86 this.typeRecorder.setVariable2Type(variableNode, index); 87 } 88 89 protected tryGetTypeIndex(typeNode: ts.Node) { 90 return this.typeRecorder.tryGetTypeIndex(typeNode); 91 } 92 93 protected getOrCreateRecordForDeclNode(typeNode: ts.Node, variableNode?: ts.Node) { 94 return this.typeChecker.getOrCreateRecordForDeclNode(typeNode, variableNode); 95 } 96 97 protected getOrCreateRecordForTypeNode(typeNode: ts.TypeNode | undefined, variableNode?: ts.Node) { 98 return this.typeChecker.getOrCreateRecordForTypeNode(typeNode, variableNode); 99 } 100 101 protected getIndexFromTypeArrayBuffer(type: BaseType): number { 102 return PandaGen.appendTypeArrayBuffer(type); 103 } 104 105 protected setTypeArrayBuffer(type: BaseType, index: number) { 106 PandaGen.setTypeArrayBuffer(type, index); 107 } 108 109} 110 111export class PlaceHolderType extends BaseType { 112 transfer2LiteralBuffer(): LiteralBuffer { 113 return new LiteralBuffer(); 114 } 115} 116 117export class TypeSummary extends BaseType { 118 preservedIndex: number = 0; 119 userDefinedClassNum: number = 0; 120 anonymousRedirect: Array<string> = new Array<string>(); 121 constructor() { 122 super(); 123 this.preservedIndex = this.getIndexFromTypeArrayBuffer(new PlaceHolderType()); 124 } 125 126 public setInfo(userDefinedClassNum: number, anonymousRedirect: Array<string>) { 127 this.userDefinedClassNum = userDefinedClassNum; 128 this.anonymousRedirect = anonymousRedirect; 129 this.setTypeArrayBuffer(this, this.preservedIndex); 130 } 131 132 transfer2LiteralBuffer(): LiteralBuffer { 133 let countBuf = new LiteralBuffer(); 134 let summaryLiterals: Array<Literal> = new Array<Literal>(); 135 summaryLiterals.push(new Literal(LiteralTag.INTEGER, L2Type._COUNTER)); 136 summaryLiterals.push(new Literal(LiteralTag.INTEGER, this.userDefinedClassNum)); 137 summaryLiterals.push(new Literal(LiteralTag.INTEGER, this.anonymousRedirect.length)); 138 for (let element of this.anonymousRedirect) { 139 summaryLiterals.push(new Literal(LiteralTag.STRING, element)); 140 } 141 countBuf.addLiterals(...summaryLiterals); 142 return countBuf; 143 } 144} 145 146export class ClassType extends BaseType { 147 modifier: number = ModifierAbstract.NONABSTRACT; // 0 -> unabstract, 1 -> abstract; 148 extendsHeritage: number = PrimitiveType.ANY; 149 implementsHeritages: Array<number> = new Array<number>(); 150 // fileds Array: [typeIndex] [public -> 0, private -> 1, protected -> 2] [readonly -> 1] 151 staticFields: Map<string, Array<number>> = new Map<string, Array<number>>(); 152 staticMethods: Map<string, number> = new Map<string, number>(); 153 fields: Map<string, Array<number>> = new Map<string, Array<number>>(); 154 methods: Map<string, number> = new Map<string, number>(); 155 typeIndex: number; 156 shiftedTypeIndex: number; 157 158 constructor(classNode: ts.ClassDeclaration | ts.ClassExpression) { 159 super(); 160 this.typeIndex = this.getIndexFromTypeArrayBuffer(new PlaceHolderType()); 161 this.shiftedTypeIndex = this.typeIndex + PrimitiveType._LENGTH; 162 // record type before its initialization, so its index can be recorded 163 // in case there's recursive reference of this type 164 this.addCurrentType(classNode, this.shiftedTypeIndex); 165 this.fillInModifiers(classNode); 166 this.fillInHeritages(classNode); 167 this.fillInFieldsAndMethods(classNode); 168 this.setTypeArrayBuffer(this, this.typeIndex); 169 } 170 171 private fillInModifiers(node: ts.ClassDeclaration | ts.ClassExpression) { 172 if (node.modifiers) { 173 for (let modifier of node.modifiers) { 174 switch (modifier.kind) { 175 case ts.SyntaxKind.AbstractKeyword: { 176 this.modifier = ModifierAbstract.ABSTRACT; 177 break; 178 } 179 default: { 180 break; 181 } 182 } 183 } 184 } 185 } 186 187 private fillInHeritages(node: ts.ClassDeclaration | ts.ClassExpression) { 188 if (node.heritageClauses) { 189 for (let heritage of node.heritageClauses) { 190 let heritageFullName = heritage.getText(); 191 for (let heritageType of heritage.types) { 192 let heritageIdentifier = <ts.Identifier>heritageType.expression; 193 let heritageTypeIndex = this.getOrCreateRecordForDeclNode(heritageIdentifier, heritageIdentifier); 194 if (heritageFullName.startsWith("extends ")) { 195 this.extendsHeritage = heritageTypeIndex; 196 } else if (heritageFullName.startsWith("implements ")) { 197 this.implementsHeritages.push(heritageTypeIndex); 198 } 199 } 200 } 201 } 202 } 203 204 private fillInFields(member: ts.PropertyDeclaration) { 205 let fieldName = jshelpers.getTextOfIdentifierOrLiteral(member.name); 206 let fieldInfo = Array<number>(PrimitiveType.ANY, AccessFlag.PUBLIC, ModifierReadonly.NONREADONLY); 207 let isStatic: boolean = false; 208 if (member.modifiers) { 209 for (let modifier of member.modifiers) { 210 switch (modifier.kind) { 211 case ts.SyntaxKind.StaticKeyword: { 212 isStatic = true; 213 break; 214 } 215 case ts.SyntaxKind.PrivateKeyword: { 216 fieldInfo[1] = AccessFlag.PRIVATE; 217 break; 218 } 219 case ts.SyntaxKind.ProtectedKeyword: { 220 fieldInfo[1] = AccessFlag.PROTECTED; 221 break; 222 } 223 case ts.SyntaxKind.ReadonlyKeyword: { 224 fieldInfo[2] = ModifierReadonly.READONLY; 225 break; 226 } 227 default: { 228 break; 229 } 230 } 231 } 232 } 233 234 let typeNode = member.type 235 let memberName = member.name 236 fieldInfo[0] = this.getOrCreateRecordForTypeNode(typeNode, memberName); 237 238 if (isStatic) { 239 this.staticFields.set(fieldName, fieldInfo); 240 } else { 241 this.fields.set(fieldName, fieldInfo); 242 } 243 } 244 245 private fillInMethods(member: ClassMemberFunction) { 246 /** 247 * a method like declaration in a new class must be a new type, 248 * create this type and add it into typeRecorder 249 */ 250 let variableNode = member.name ? member.name : undefined; 251 let funcType = new FunctionType(<ts.FunctionLikeDeclaration>member); 252 if (variableNode) { 253 this.setVariable2Type(variableNode, funcType.shiftedTypeIndex); 254 } 255 256 // Then, get the typeIndex and fill in the methods array 257 let typeIndex = this.tryGetTypeIndex(member); 258 let funcModifier = funcType.getModifier(); 259 if (funcModifier) { 260 this.staticMethods.set(funcType.getFunctionName(), typeIndex!); 261 } else { 262 this.methods.set(funcType.getFunctionName(), typeIndex!); 263 } 264 } 265 266 private fillInFieldsAndMethods(node: ts.ClassDeclaration | ts.ClassExpression) { 267 if (node.members) { 268 for (let member of node.members) { 269 switch (member.kind) { 270 case ts.SyntaxKind.MethodDeclaration: 271 case ts.SyntaxKind.Constructor: 272 case ts.SyntaxKind.GetAccessor: 273 case ts.SyntaxKind.SetAccessor: { 274 this.fillInMethods(<ClassMemberFunction>member); 275 break; 276 } 277 case ts.SyntaxKind.PropertyDeclaration: { 278 this.fillInFields(<ts.PropertyDeclaration>member); 279 break; 280 } 281 default: 282 break; 283 } 284 } 285 } 286 } 287 288 transfer2LiteralBuffer() { 289 let classTypeBuf = new LiteralBuffer(); 290 let classTypeLiterals: Array<Literal> = new Array<Literal>(); 291 // the first element is to determine the L2 type 292 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.CLASS)); 293 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.modifier)); 294 295 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.extendsHeritage)); 296 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.implementsHeritages.length)); 297 this.implementsHeritages.forEach(heritage => { 298 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, heritage)); 299 }); 300 301 // record unstatic fields and methods 302 this.transferFields2Literal(classTypeLiterals, false); 303 this.transferMethods2Literal(classTypeLiterals, false); 304 305 // record static methods and fields; 306 this.transferFields2Literal(classTypeLiterals, true); 307 this.transferMethods2Literal(classTypeLiterals, true); 308 309 classTypeBuf.addLiterals(...classTypeLiterals); 310 return classTypeBuf; 311 } 312 313 private transferFields2Literal(classTypeLiterals: Array<Literal>, isStatic: boolean) { 314 let transferredTarget: Map<string, Array<number>> = isStatic ? this.staticFields : this.fields; 315 316 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, transferredTarget.size)); 317 transferredTarget.forEach((typeInfo, name) => { 318 classTypeLiterals.push(new Literal(LiteralTag.STRING, name)); 319 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, typeInfo[0])); // typeIndex 320 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, typeInfo[1])); // accessFlag 321 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, typeInfo[2])); // readonly 322 }); 323 } 324 325 private transferMethods2Literal(classTypeLiterals: Array<Literal>, isStatic: boolean) { 326 let transferredTarget: Map<string, number> = isStatic ? this.staticMethods : this.methods; 327 328 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, transferredTarget.size)); 329 transferredTarget.forEach((typeInfo, name) => { 330 classTypeLiterals.push(new Literal(LiteralTag.STRING, name)); 331 classTypeLiterals.push(new Literal(LiteralTag.INTEGER, typeInfo)); 332 }); 333 } 334} 335 336export class ClassInstType extends BaseType { 337 shiftedReferredClassIndex: number; // the referred class in the type system; 338 typeIndex: number; 339 shiftedTypeIndex: number; 340 constructor(referredClassIndex: number) { 341 super(); 342 this.shiftedReferredClassIndex = referredClassIndex; 343 this.typeIndex = this.getIndexFromTypeArrayBuffer(this); 344 this.shiftedTypeIndex = this.typeIndex + PrimitiveType._LENGTH; 345 this.typeRecorder.setClass2InstanceMap(this.shiftedReferredClassIndex, this.shiftedTypeIndex); 346 } 347 348 transfer2LiteralBuffer(): LiteralBuffer { 349 let classInstBuf = new LiteralBuffer(); 350 let classInstLiterals: Array<Literal> = new Array<Literal>(); 351 352 classInstLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.CLASSINST)); 353 classInstLiterals.push(new Literal(LiteralTag.INTEGER, this.shiftedReferredClassIndex)); 354 classInstBuf.addLiterals(...classInstLiterals); 355 356 return classInstBuf; 357 } 358} 359 360export class FunctionType extends BaseType { 361 name: string = ''; 362 accessFlag: number = AccessFlag.PUBLIC; // 0 -> public -> 0, private -> 1, protected -> 2 363 modifierStatic: number = ModifierStatic.NONSTATIC; // 0 -> unstatic, 1 -> static 364 parameters: Array<number> = new Array<number>(); 365 returnType: number = PrimitiveType.ANY; 366 typeIndex: number; 367 shiftedTypeIndex: number; 368 369 constructor(funcNode: ts.FunctionLikeDeclaration | ts.MethodSignature) { 370 super(); 371 this.typeIndex = this.getIndexFromTypeArrayBuffer(new PlaceHolderType()); 372 this.shiftedTypeIndex = this.typeIndex + PrimitiveType._LENGTH; 373 // record type before its initialization, so its index can be recorded 374 // in case there's recursive reference of this type 375 this.addCurrentType(funcNode, this.shiftedTypeIndex); 376 377 if (funcNode.name) { 378 this.name = jshelpers.getTextOfIdentifierOrLiteral(funcNode.name); 379 } else { 380 this.name = "constructor"; 381 } 382 this.fillInModifiers(funcNode); 383 this.fillInParameters(funcNode); 384 this.fillInReturn(funcNode); 385 this.setTypeArrayBuffer(this, this.typeIndex); 386 } 387 388 public getFunctionName() { 389 return this.name; 390 } 391 392 private fillInModifiers(node: ts.FunctionLikeDeclaration | ts.MethodSignature) { 393 if (node.modifiers) { 394 for (let modifier of node.modifiers) { 395 switch (modifier.kind) { 396 case ts.SyntaxKind.PrivateKeyword: { 397 this.accessFlag = AccessFlag.PRIVATE; 398 break; 399 } 400 case ts.SyntaxKind.ProtectedKeyword: { 401 this.accessFlag = AccessFlag.PROTECTED; 402 break; 403 } 404 case ts.SyntaxKind.StaticKeyword: { 405 this.modifierStatic = ModifierStatic.STATIC; 406 break; 407 } 408 default: 409 break; 410 } 411 } 412 } 413 } 414 415 private fillInParameters(node: ts.FunctionLikeDeclaration | ts.MethodSignature) { 416 if (node.parameters) { 417 for (let parameter of node.parameters) { 418 let typeNode = parameter.type; 419 let variableNode = parameter.name; 420 let typeIndex = this.getOrCreateRecordForTypeNode(typeNode, variableNode); 421 this.parameters.push(typeIndex); 422 } 423 } 424 } 425 426 private fillInReturn(node: ts.FunctionLikeDeclaration | ts.MethodSignature) { 427 let typeNode = node.type; 428 let typeIndex = this.getOrCreateRecordForTypeNode(typeNode, typeNode); 429 this.returnType = typeIndex; 430 } 431 432 getModifier() { 433 return this.modifierStatic; 434 } 435 436 transfer2LiteralBuffer(): LiteralBuffer { 437 let funcTypeBuf = new LiteralBuffer(); 438 let funcTypeLiterals: Array<Literal> = new Array<Literal>(); 439 funcTypeLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.FUNCTION)); 440 funcTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.accessFlag)); 441 funcTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.modifierStatic)); 442 funcTypeLiterals.push(new Literal(LiteralTag.STRING, this.name)); 443 funcTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.parameters.length)); 444 this.parameters.forEach((type) => { 445 funcTypeLiterals.push(new Literal(LiteralTag.INTEGER, type)); 446 }); 447 448 funcTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.returnType)); 449 funcTypeBuf.addLiterals(...funcTypeLiterals); 450 return funcTypeBuf; 451 } 452} 453 454export class ExternalType extends BaseType { 455 fullRedirectNath: string; 456 typeIndex: number; 457 shiftedTypeIndex: number; 458 459 constructor(importName: string, redirectPath: string) { 460 super(); 461 this.fullRedirectNath = `#${importName}#${redirectPath}`; 462 this.typeIndex = this.getIndexFromTypeArrayBuffer(this); 463 this.shiftedTypeIndex = this.typeIndex + PrimitiveType._LENGTH; 464 } 465 466 transfer2LiteralBuffer(): LiteralBuffer { 467 let ImpTypeBuf = new LiteralBuffer(); 468 let ImpTypeLiterals: Array<Literal> = new Array<Literal>(); 469 ImpTypeLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.EXTERNAL)); 470 ImpTypeLiterals.push(new Literal(LiteralTag.STRING, this.fullRedirectNath)); 471 ImpTypeBuf.addLiterals(...ImpTypeLiterals); 472 return ImpTypeBuf; 473 } 474} 475 476export class UnionType extends BaseType { 477 unionedTypeArray: Array<number> = []; 478 typeIndex: number = PrimitiveType.ANY; 479 shiftedTypeIndex: number = PrimitiveType.ANY; 480 481 constructor(typeNode: ts.Node) { 482 super(); 483 this.setOrReadFromArrayRecord(typeNode); 484 } 485 486 setOrReadFromArrayRecord(typeNode: ts.Node) { 487 let unionStr = typeNode.getText(); 488 if (this.hasUnionTypeMapping(unionStr)) { 489 this.shiftedTypeIndex = this.getFromUnionTypeMap(unionStr)!; 490 return; 491 } 492 this.typeIndex = this.getIndexFromTypeArrayBuffer(new PlaceHolderType()); 493 this.shiftedTypeIndex = this.typeIndex + PrimitiveType._LENGTH; 494 this.fillInUnionArray(typeNode, this.unionedTypeArray); 495 this.setUnionTypeMap(unionStr, this.shiftedTypeIndex); 496 this.setTypeArrayBuffer(this, this.typeIndex); 497 } 498 499 hasUnionTypeMapping(unionStr: string) { 500 return this.typeRecorder.hasUnionTypeMapping(unionStr); 501 } 502 503 getFromUnionTypeMap(unionStr: string) { 504 return this.typeRecorder.getFromUnionTypeMap(unionStr); 505 } 506 507 setUnionTypeMap(unionStr: string, shiftedTypeIndex: number) { 508 return this.typeRecorder.setUnionTypeMap(unionStr, shiftedTypeIndex); 509 } 510 511 fillInUnionArray(typeNode: ts.Node, unionedTypeArray: Array<number>) { 512 for (let element of (<ts.UnionType><any>typeNode).types) { 513 let elementNode = <ts.TypeNode><any>element; 514 let typeIndex = this.getOrCreateRecordForTypeNode(elementNode, elementNode); 515 unionedTypeArray.push(typeIndex!); 516 } 517 } 518 519 transfer2LiteralBuffer(): LiteralBuffer { 520 let UnionTypeBuf = new LiteralBuffer(); 521 let UnionTypeLiterals: Array<Literal> = new Array<Literal>(); 522 UnionTypeLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.UNION)); 523 UnionTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.unionedTypeArray.length)); 524 for (let type of this.unionedTypeArray) { 525 UnionTypeLiterals.push(new Literal(LiteralTag.INTEGER, type)); 526 } 527 UnionTypeBuf.addLiterals(...UnionTypeLiterals); 528 return UnionTypeBuf; 529 } 530} 531 532export class ArrayType extends BaseType { 533 referedTypeIndex: number = PrimitiveType.ANY; 534 typeIndex: number = PrimitiveType.ANY; 535 shiftedTypeIndex: number = PrimitiveType.ANY; 536 constructor(typeNode: ts.Node) { 537 super(); 538 let elementNode = (<ts.ArrayTypeNode><any>typeNode).elementType; 539 this.referedTypeIndex = this.getOrCreateRecordForTypeNode(elementNode, elementNode); 540 this.setOrReadFromArrayRecord(); 541 } 542 543 setOrReadFromArrayRecord() { 544 if (this.hasArrayTypeMapping(this.referedTypeIndex)) { 545 this.shiftedTypeIndex = this.getFromArrayTypeMap(this.referedTypeIndex)!; 546 } else { 547 this.typeIndex = this.getIndexFromTypeArrayBuffer(this); 548 this.shiftedTypeIndex = this.typeIndex + PrimitiveType._LENGTH; 549 this.setTypeArrayBuffer(this, this.typeIndex); 550 this.setArrayTypeMap(this.referedTypeIndex, this.shiftedTypeIndex); 551 } 552 } 553 554 hasArrayTypeMapping(referedTypeIndex: number) { 555 return this.typeRecorder.hasArrayTypeMapping(referedTypeIndex); 556 } 557 558 getFromArrayTypeMap(referedTypeIndex: number) { 559 return this.typeRecorder.getFromArrayTypeMap(referedTypeIndex); 560 } 561 562 setArrayTypeMap(referedTypeIndex: number, shiftedTypeIndex: number) { 563 return this.typeRecorder.setArrayTypeMap(referedTypeIndex, shiftedTypeIndex); 564 } 565 566 transfer2LiteralBuffer(): LiteralBuffer { 567 let arrayBuf = new LiteralBuffer(); 568 let arrayLiterals: Array<Literal> = new Array<Literal>(); 569 arrayLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.ARRAY)); 570 arrayLiterals.push(new Literal(LiteralTag.INTEGER, this.referedTypeIndex)); 571 arrayBuf.addLiterals(...arrayLiterals); 572 return arrayBuf; 573 } 574} 575 576export class ObjectType extends BaseType { 577 private properties: Map<string, number> = new Map<string, number>(); 578 typeIndex: number = PrimitiveType.ANY; 579 shiftedTypeIndex: number = PrimitiveType.ANY; 580 581 constructor(objNode: ts.TypeLiteralNode) { 582 super(); 583 this.typeIndex = this.getIndexFromTypeArrayBuffer(new PlaceHolderType()); 584 this.shiftedTypeIndex = this.typeIndex + PrimitiveType._LENGTH; 585 this.fillInMembers(objNode); 586 this.setTypeArrayBuffer(this, this.typeIndex); 587 } 588 589 fillInMembers(objNode: ts.TypeLiteralNode) { 590 for (let member of objNode.members) { 591 let propertySig = <ts.PropertySignature>member; 592 let name = member.name ? member.name.getText() : "#undefined"; 593 let typeIndex = this.getOrCreateRecordForTypeNode(propertySig.type, member.name); 594 this.properties.set(name, typeIndex); 595 } 596 } 597 598 transfer2LiteralBuffer(): LiteralBuffer { 599 let objTypeBuf = new LiteralBuffer(); 600 let objLiterals: Array<Literal> = new Array<Literal>(); 601 objLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.OBJECT)); 602 objLiterals.push(new Literal(LiteralTag.INTEGER, this.properties.size)); 603 this.properties.forEach((typeIndex, name) => { 604 objLiterals.push(new Literal(LiteralTag.STRING, name)); 605 objLiterals.push(new Literal(LiteralTag.INTEGER, typeIndex)); 606 }); 607 objTypeBuf.addLiterals(...objLiterals); 608 return objTypeBuf; 609 } 610} 611 612export class InterfaceType extends BaseType { 613 heritages: Array<number> = new Array<number>(); 614 // fileds Array: [typeIndex] [public -> 0, private -> 1, protected -> 2] [readonly -> 1] 615 fields: Map<string, Array<number>> = new Map<string, Array<number>>(); 616 methods: Array<number> = new Array<number>(); 617 typeIndex: number; 618 shiftedTypeIndex: number; 619 620 constructor(interfaceNode: ts.InterfaceDeclaration) { 621 super(); 622 this.typeIndex = this.getIndexFromTypeArrayBuffer(new PlaceHolderType()); 623 this.shiftedTypeIndex = this.typeIndex + PrimitiveType._LENGTH; 624 // record type before its initialization, so its index can be recorded 625 // in case there's recursive reference of this type 626 this.addCurrentType(interfaceNode, this.shiftedTypeIndex); 627 this.fillInHeritages(interfaceNode); 628 this.fillInFieldsAndMethods(interfaceNode); 629 this.setTypeArrayBuffer(this, this.typeIndex); 630 } 631 632 private fillInHeritages(node: ts.InterfaceDeclaration) { 633 if (node.heritageClauses) { 634 for (let heritage of node.heritageClauses) { 635 for (let heritageType of heritage.types) { 636 let heritageIdentifier = <ts.Identifier>heritageType.expression; 637 let heritageTypeIndex = this.getOrCreateRecordForDeclNode(heritageIdentifier, heritageIdentifier); 638 this.heritages.push(heritageTypeIndex); 639 } 640 } 641 } 642 } 643 644 private fillInFields(member: ts.PropertySignature) { 645 let fieldName = jshelpers.getTextOfIdentifierOrLiteral(member.name); 646 let fieldInfo = Array<number>(PrimitiveType.ANY, AccessFlag.PUBLIC, ModifierReadonly.NONREADONLY); 647 if (member.modifiers) { 648 for (let modifier of member.modifiers) { 649 switch (modifier.kind) { 650 case ts.SyntaxKind.PrivateKeyword: { 651 fieldInfo[1] = AccessFlag.PRIVATE; 652 break; 653 } 654 case ts.SyntaxKind.ProtectedKeyword: { 655 fieldInfo[1] = AccessFlag.PROTECTED; 656 break; 657 } 658 case ts.SyntaxKind.ReadonlyKeyword: { 659 fieldInfo[2] = ModifierReadonly.READONLY; 660 break; 661 } 662 default: 663 break; 664 } 665 } 666 } 667 let typeNode = member.type; 668 let memberName = member.name; 669 fieldInfo[0] = this.getOrCreateRecordForTypeNode(typeNode, memberName); 670 this.fields.set(fieldName, fieldInfo); 671 } 672 673 private fillInMethods(member: ts.MethodSignature) { 674 /** 675 * a method like declaration in a new class must be a new type, 676 * create this type and add it into typeRecorder 677 */ 678 let variableNode = member.name ? member.name : undefined; 679 let funcType = new FunctionType(<ts.MethodSignature>member); 680 if (variableNode) { 681 this.setVariable2Type(variableNode, funcType.shiftedTypeIndex); 682 } 683 // Then, get the typeIndex and fill in the methods array 684 let typeIndex = this.tryGetTypeIndex(member); 685 this.methods.push(typeIndex!); 686 } 687 688 private fillInFieldsAndMethods(node: ts.InterfaceDeclaration) { 689 if (node.members) { 690 for (let member of node.members) { 691 switch (member.kind) { 692 case ts.SyntaxKind.MethodSignature: { 693 this.fillInMethods(<ts.MethodSignature>member); 694 break; 695 } 696 case ts.SyntaxKind.PropertySignature: { 697 this.fillInFields(<ts.PropertySignature>member); 698 break; 699 } 700 default: 701 break; 702 } 703 } 704 } 705 } 706 707 transfer2LiteralBuffer() { 708 let interfaceTypeBuf = new LiteralBuffer(); 709 let interfaceTypeLiterals: Array<Literal> = new Array<Literal>(); 710 // the first element is to determine the L2 type 711 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, L2Type.INTERFACE)); 712 713 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, this.heritages.length)); 714 this.heritages.forEach(heritage => { 715 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, heritage)); 716 }); 717 718 // record fields and methods 719 this.transferFields2Literal(interfaceTypeLiterals); 720 this.transferMethods2Literal(interfaceTypeLiterals); 721 722 interfaceTypeBuf.addLiterals(...interfaceTypeLiterals); 723 return interfaceTypeBuf; 724 } 725 726 private transferFields2Literal(interfaceTypeLiterals: Array<Literal>) { 727 let transferredTarget: Map<string, Array<number>> = this.fields; 728 729 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, transferredTarget.size)); 730 transferredTarget.forEach((typeInfo, name) => { 731 interfaceTypeLiterals.push(new Literal(LiteralTag.STRING, name)); 732 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, typeInfo[0])); // typeIndex 733 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, typeInfo[1])); // accessFlag 734 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, typeInfo[2])); // readonly 735 }); 736 } 737 738 private transferMethods2Literal(interfaceTypeLiterals: Array<Literal>) { 739 let transferredTarget: Array<number> = this.methods; 740 741 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, transferredTarget.length)); 742 transferredTarget.forEach(method => { 743 interfaceTypeLiterals.push(new Literal(LiteralTag.INTEGER, method)); 744 }); 745 } 746} 747