mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 15:12:12 +00:00
Cleanup
This commit is contained in:
parent
ce57820f59
commit
7d85b0cc7f
@ -7,7 +7,7 @@ AssemblyScript NEXT
|
||||
|
||||
By compiling syntactially but not necessarily semantically valid TypeScript to [Binaryen](https://github.com/WebAssembly/binaryen) IR, the resulting module can be validated, optimized, emitted in WebAssembly text or binary format and converted to [asm.js](http://asmjs.org) as a polyfill.
|
||||
|
||||
The compiler itself utilizies "portable definitions" so it can be compiled to both JavaScript using `tsc` and, eventually, to WebAssembly using `asc`.
|
||||
The compiler itself utilizes "portable definitions" so it can be compiled to both JavaScript using `tsc` and, eventually, to WebAssembly using `asc`.
|
||||
|
||||
Development status
|
||||
------------------
|
||||
@ -32,7 +32,7 @@ $> cd next
|
||||
$> npm install
|
||||
```
|
||||
|
||||
Author your module either using
|
||||
Author your module using either
|
||||
|
||||
* the [assembly definitions](./std/assembly.d.ts) ([base config](./std/assembly.json)) if all you care about is targeting WebAssembly/asm.js or
|
||||
* the [portable definitions](./std/portable.d.ts) ([base config](./std/portable.json)) if you also want to compile to JavaScript using `tsc`
|
||||
|
@ -3,7 +3,7 @@ import { DiagnosticCode } from "./diagnostics";
|
||||
import { Node, Expression } from "./ast";
|
||||
import { Type } from "./types";
|
||||
import { Module, ExpressionRef, UnaryOp, BinaryOp, HostOp, NativeType, FunctionTypeRef } from "./module";
|
||||
import { Program, FunctionPrototype, Local } from "./program";
|
||||
import { Program, ElementFlags, FunctionPrototype, Local } from "./program";
|
||||
|
||||
/** Initializes the specified program with built-in functions. */
|
||||
export function initialize(program: Program): void {
|
||||
@ -41,7 +41,7 @@ export function initialize(program: Program): void {
|
||||
function addFunction(program: Program, name: string, isGeneric: bool = false): void {
|
||||
let prototype: FunctionPrototype = new FunctionPrototype(program, name, null, null);
|
||||
prototype.isBuiltIn = true;
|
||||
prototype.isGeneric = isGeneric;
|
||||
if (isGeneric) prototype.isGeneric = true;
|
||||
program.elements.set(name, prototype);
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@ import {
|
||||
ClassPrototype,
|
||||
Class, Element,
|
||||
ElementKind,
|
||||
ElementFlags,
|
||||
Enum,
|
||||
FunctionPrototype,
|
||||
Function,
|
||||
@ -201,7 +202,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
if (!typeRef)
|
||||
typeRef = this.module.addFunctionType("v", NativeType.None, []);
|
||||
this.module.setStart(
|
||||
this.module.addFunction(this.startFunction.template.internalName, typeRef, typesToNativeTypes(this.startFunction.additionalLocals), this.module.createBlock(null, this.startFunctionBody))
|
||||
this.module.addFunction(this.startFunction.prototype.internalName, typeRef, typesToNativeTypes(this.startFunction.additionalLocals), this.module.createBlock(null, this.startFunctionBody))
|
||||
);
|
||||
}
|
||||
|
||||
@ -314,11 +315,11 @@ export class Compiler extends DiagnosticEmitter {
|
||||
return <Global>element;
|
||||
}
|
||||
|
||||
compileGlobal(element: Global): bool {
|
||||
if (element.isCompiled)
|
||||
compileGlobal(global: Global): bool {
|
||||
if (global.isCompiled)
|
||||
return true;
|
||||
const declaration: VariableLikeDeclarationStatement | null = element.declaration;
|
||||
let type: Type | null = element.type;
|
||||
const declaration: VariableLikeDeclarationStatement | null = global.declaration;
|
||||
let type: Type | null = global.type;
|
||||
if (!type) {
|
||||
if (!declaration)
|
||||
throw new Error("unexpected missing declaration");
|
||||
@ -327,33 +328,33 @@ export class Compiler extends DiagnosticEmitter {
|
||||
type = this.program.resolveType(declaration.type); // reports
|
||||
if (!type)
|
||||
return false;
|
||||
element.type = type;
|
||||
global.type = type;
|
||||
}
|
||||
if (this.module.noEmit)
|
||||
return true;
|
||||
const nativeType: NativeType = typeToNativeType(<Type>type);
|
||||
let initializer: ExpressionRef;
|
||||
let initializeInStart: bool = false;
|
||||
if (element.hasConstantValue) {
|
||||
if (global.hasConstantValue) {
|
||||
if (type.isLongInteger)
|
||||
initializer = element.constantIntegerValue ? this.module.createI64(element.constantIntegerValue.lo, element.constantIntegerValue.hi) : this.module.createI64(0, 0);
|
||||
initializer = global.constantIntegerValue ? this.module.createI64(global.constantIntegerValue.lo, global.constantIntegerValue.hi) : this.module.createI64(0, 0);
|
||||
else if (type.kind == TypeKind.F32)
|
||||
initializer = this.module.createF32(element.constantFloatValue);
|
||||
initializer = this.module.createF32(global.constantFloatValue);
|
||||
else if (type.kind == TypeKind.F64)
|
||||
initializer = this.module.createF64(element.constantFloatValue);
|
||||
initializer = this.module.createF64(global.constantFloatValue);
|
||||
else if (type.isSmallInteger) {
|
||||
if (type.isSignedInteger) {
|
||||
const shift: i32 = type.smallIntegerShift;
|
||||
initializer = this.module.createI32(element.constantIntegerValue ? element.constantIntegerValue.toI32() << shift >> shift : 0);
|
||||
initializer = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() << shift >> shift : 0);
|
||||
} else
|
||||
initializer = this.module.createI32(element.constantIntegerValue ? element.constantIntegerValue.toI32() & type.smallIntegerMask: 0);
|
||||
initializer = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() & type.smallIntegerMask: 0);
|
||||
} else
|
||||
initializer = this.module.createI32(element.constantIntegerValue ? element.constantIntegerValue.toI32() : 0);
|
||||
initializer = this.module.createI32(global.constantIntegerValue ? global.constantIntegerValue.toI32() : 0);
|
||||
} else if (declaration) {
|
||||
if (declaration.initializer) {
|
||||
initializer = this.compileExpression(declaration.initializer, type);
|
||||
if (_BinaryenExpressionGetId(initializer) != ExpressionId.Const) {
|
||||
if (!element.isMutable) {
|
||||
if (!global.isMutable) {
|
||||
initializer = this.precomputeExpressionRef(initializer);
|
||||
if (_BinaryenExpressionGetId(initializer) != ExpressionId.Const) {
|
||||
this.warning(DiagnosticCode.Compiling_constant_global_with_non_constant_initializer_as_mutable, declaration.range);
|
||||
@ -366,34 +367,35 @@ export class Compiler extends DiagnosticEmitter {
|
||||
initializer = typeToNativeZero(this.module, type);
|
||||
} else
|
||||
throw new Error("unexpected missing declaration or constant value");
|
||||
const internalName: string = element.internalName;
|
||||
const internalName: string = global.internalName;
|
||||
if (initializeInStart) {
|
||||
this.module.addGlobal(internalName, nativeType, true, typeToNativeZero(this.module, type));
|
||||
this.startFunctionBody.push(this.module.createSetGlobal(internalName, initializer));
|
||||
} else {
|
||||
this.module.addGlobal(internalName, nativeType, element.isMutable, initializer);
|
||||
if (!element.isMutable) {
|
||||
element.hasConstantValue = true;
|
||||
this.module.addGlobal(internalName, nativeType, global.isMutable, initializer);
|
||||
if (!global.isMutable) {
|
||||
const exprType: NativeType = _BinaryenExpressionGetType(initializer);
|
||||
switch (exprType) {
|
||||
case NativeType.I32:
|
||||
element.constantIntegerValue = new I64(_BinaryenConstGetValueI32(initializer), 0);
|
||||
global.constantIntegerValue = new I64(_BinaryenConstGetValueI32(initializer), 0);
|
||||
break;
|
||||
case NativeType.I64:
|
||||
element.constantIntegerValue = new I64(_BinaryenConstGetValueI64Low(initializer), _BinaryenConstGetValueI64High(initializer));
|
||||
global.constantIntegerValue = new I64(_BinaryenConstGetValueI64Low(initializer), _BinaryenConstGetValueI64High(initializer));
|
||||
break;
|
||||
case NativeType.F32:
|
||||
element.constantFloatValue = _BinaryenConstGetValueF32(initializer);
|
||||
global.constantFloatValue = _BinaryenConstGetValueF32(initializer);
|
||||
break;
|
||||
case NativeType.F64:
|
||||
element.constantFloatValue = _BinaryenConstGetValueF64(initializer);
|
||||
global.constantFloatValue = _BinaryenConstGetValueF64(initializer);
|
||||
break;
|
||||
default:
|
||||
throw new Error("unexpected initializer type");
|
||||
}
|
||||
global.hasConstantValue = true;
|
||||
}
|
||||
}
|
||||
return element.isCompiled = true;
|
||||
global.isCompiled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// enums
|
||||
@ -446,8 +448,8 @@ export class Compiler extends DiagnosticEmitter {
|
||||
} else {
|
||||
this.module.addGlobal(val.internalName, NativeType.I32, false, initializer);
|
||||
if (_BinaryenExpressionGetType(initializer) == NativeType.I32) {
|
||||
val.hasConstantValue = true;
|
||||
val.constantValue = _BinaryenConstGetValueI32(initializer);
|
||||
val.hasConstantValue = true;
|
||||
} else
|
||||
throw new Error("unexpected initializer type");
|
||||
}
|
||||
@ -483,11 +485,11 @@ export class Compiler extends DiagnosticEmitter {
|
||||
if (instance.isCompiled)
|
||||
return true;
|
||||
|
||||
const declaration: FunctionDeclaration | null = instance.template.declaration;
|
||||
const declaration: FunctionDeclaration | null = instance.prototype.declaration;
|
||||
if (!declaration)
|
||||
throw new Error("unexpected missing declaration");
|
||||
|
||||
if (instance.isDeclare) {
|
||||
if (instance.isDeclared) {
|
||||
if (declaration.statements) {
|
||||
this.error(DiagnosticCode.An_implementation_cannot_be_declared_in_ambient_contexts, declaration.identifier.range);
|
||||
return false;
|
||||
@ -502,7 +504,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
// compile statements
|
||||
let stmts: ExpressionRef[] | null = null;
|
||||
if (!instance.isDeclare) {
|
||||
if (!instance.isDeclared) {
|
||||
const previousFunction: Function = this.currentFunction;
|
||||
this.currentFunction = instance;
|
||||
stmts = this.compileStatements(<Statement[]>declaration.statements);
|
||||
@ -525,7 +527,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
// create the function
|
||||
const internalName: string = instance.internalName;
|
||||
if (instance.isDeclare) {
|
||||
if (instance.isDeclared) {
|
||||
this.module.addFunctionImport(internalName, "env", declaration.identifier.name, typeRef);
|
||||
} else {
|
||||
this.module.addFunction(internalName, typeRef, typesToNativeTypes(instance.additionalLocals), this.module.createBlock(null, <ExpressionRef[]>stmts, NativeType.None));
|
||||
@ -580,7 +582,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
switch (element.kind) {
|
||||
|
||||
case ElementKind.CLASS_PROTOTYPE:
|
||||
if ((noTreeShaking || (<ClassPrototype>element).isExport) && !(<ClassPrototype>element).isGeneric)
|
||||
if ((noTreeShaking || (<ClassPrototype>element).isExported) && !(<ClassPrototype>element).isGeneric)
|
||||
this.compileClassUsingTypeArguments(<ClassPrototype>element, []);
|
||||
break;
|
||||
|
||||
@ -589,7 +591,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
break;
|
||||
|
||||
case ElementKind.FUNCTION_PROTOTYPE:
|
||||
if ((noTreeShaking || (<FunctionPrototype>element).isExport) && !(<FunctionPrototype>element).isGeneric)
|
||||
if ((noTreeShaking || (<FunctionPrototype>element).isExported) && !(<FunctionPrototype>element).isGeneric)
|
||||
this.compileFunctionUsingTypeArguments(<FunctionPrototype>element, []);
|
||||
break;
|
||||
|
||||
@ -1680,7 +1682,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
this.compileFunction(functionInstance);
|
||||
|
||||
// imported function
|
||||
if (functionInstance.isDeclare)
|
||||
if (functionInstance.isDeclared)
|
||||
return this.module.createCallImport(functionInstance.internalName, operands, typeToNativeType(functionInstance.returnType));
|
||||
|
||||
// internal function
|
||||
|
366
src/program.ts
366
src/program.ts
@ -61,6 +61,7 @@ class QueuedImport {
|
||||
|
||||
const noTypesYet: Map<string,Type> = new Map();
|
||||
|
||||
/** Represents an AssemblyScript program. */
|
||||
export class Program extends DiagnosticEmitter {
|
||||
|
||||
/** Array of source files. */
|
||||
@ -76,6 +77,7 @@ export class Program extends DiagnosticEmitter {
|
||||
/** Exports of individual files by internal name. Not global exports. */
|
||||
exports: Map<string,Element> = new Map();
|
||||
|
||||
/** Constructs a new program, optionally inheriting parser diagnostics. */
|
||||
constructor(diagnostics: DiagnosticMessage[] | null = null) {
|
||||
super(diagnostics);
|
||||
this.sources = new Array();
|
||||
@ -152,7 +154,7 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
let element: Element | null;
|
||||
|
||||
// queued imports should be resolvable now
|
||||
// queued imports should be resolvable now through traversing exports and queued exports
|
||||
for (let i: i32 = 0; i < queuedImports.length;) {
|
||||
const queuedImport: QueuedImport = queuedImports[i];
|
||||
element = this.tryResolveImport(queuedImport.referencedName, queuedExports);
|
||||
@ -165,7 +167,7 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
// queued exports should be resolvable noww
|
||||
// queued exports should be resolvable now that imports are finalized
|
||||
for (let [exportName, queuedExport] of queuedExports) {
|
||||
let currentExport: QueuedExport | null = queuedExport;
|
||||
do {
|
||||
@ -190,6 +192,7 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/** Tries to resolve an import by traversing exports and queued exports. */
|
||||
private tryResolveImport(referencedName: string, queuedExports: Map<string,QueuedExport>): Element | null {
|
||||
let element: Element | null;
|
||||
do {
|
||||
@ -215,7 +218,7 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
const prototype: ClassPrototype = new ClassPrototype(this, internalName, declaration);
|
||||
this.elements.set(internalName, prototype);
|
||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||
if (prototype.isExported) {
|
||||
if (this.exports.has(internalName))
|
||||
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.identifier.range, internalName);
|
||||
else
|
||||
@ -281,7 +284,7 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
const enm: Enum = new Enum(this, internalName, declaration);
|
||||
this.elements.set(internalName, enm);
|
||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||
if (enm.isExported) {
|
||||
if (this.exports.has(internalName))
|
||||
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.identifier.range, internalName);
|
||||
else
|
||||
@ -311,12 +314,10 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
private initializeExport(member: ExportMember, internalPath: string | null, queuedExports: Map<string,QueuedExport>): void {
|
||||
const externalName: string = member.range.source.internalPath + PATH_DELIMITER + member.externalIdentifier.name;
|
||||
|
||||
if (this.exports.has(externalName)) {
|
||||
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, member.externalIdentifier.range, externalName);
|
||||
return;
|
||||
}
|
||||
|
||||
let referencedName: string;
|
||||
|
||||
// export local element
|
||||
@ -393,15 +394,12 @@ export class Program extends DiagnosticEmitter {
|
||||
return;
|
||||
}
|
||||
this.elements.set(internalName, prototype);
|
||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||
if (prototype.isExported) {
|
||||
if (this.exports.has(internalName))
|
||||
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.identifier.range, internalName);
|
||||
else
|
||||
this.exports.set(internalName, prototype);
|
||||
}
|
||||
if (hasModifier(ModifierKind.DECLARE, declaration.modifiers)) {
|
||||
prototype.isDeclare = true;
|
||||
}
|
||||
}
|
||||
|
||||
private initializeImports(statement: ImportStatement, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
|
||||
@ -459,16 +457,17 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
private initializeInterface(declaration: InterfaceDeclaration): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const interfacePrototype: InterfacePrototype = new InterfacePrototype(this, internalName, declaration);
|
||||
const prototype: InterfacePrototype = new InterfacePrototype(this, internalName, declaration);
|
||||
if (this.elements.has(internalName))
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
else
|
||||
this.elements.set(internalName, interfacePrototype);
|
||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||
this.elements.set(internalName, prototype);
|
||||
|
||||
if (prototype.isExported) {
|
||||
if (this.exports.has(internalName))
|
||||
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.identifier.range, internalName);
|
||||
else
|
||||
this.exports.set(internalName, interfacePrototype);
|
||||
this.exports.set(internalName, prototype);
|
||||
}
|
||||
const memberDeclarations: DeclarationStatement[] = declaration.members;
|
||||
for (let j: i32 = 0, l: i32 = memberDeclarations.length; j < l; ++j) {
|
||||
@ -476,11 +475,11 @@ export class Program extends DiagnosticEmitter {
|
||||
switch (memberDeclaration.kind) {
|
||||
|
||||
case NodeKind.FIELD:
|
||||
this.initializeField(<FieldDeclaration>memberDeclaration, interfacePrototype);
|
||||
this.initializeField(<FieldDeclaration>memberDeclaration, prototype);
|
||||
break;
|
||||
|
||||
case NodeKind.METHOD:
|
||||
this.initializeMethod(<MethodDeclaration>memberDeclaration, interfacePrototype);
|
||||
this.initializeMethod(<MethodDeclaration>memberDeclaration, prototype);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -492,11 +491,12 @@ export class Program extends DiagnosticEmitter {
|
||||
private initializeNamespace(declaration: NamespaceDeclaration): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const namespace: Namespace = new Namespace(this, internalName, declaration);
|
||||
|
||||
if (this.elements.has(internalName))
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
else {
|
||||
this.elements.set(internalName, namespace);
|
||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||
if (namespace.isExported) {
|
||||
if (this.exports.has(internalName))
|
||||
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.identifier.range, internalName);
|
||||
else
|
||||
@ -504,8 +504,8 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
}
|
||||
const members: Statement[] = declaration.members;
|
||||
for (let j: i32 = 0, l: i32 = members.length; j < l; ++j) {
|
||||
const statement: Statement = members[j];
|
||||
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i) {
|
||||
const statement: Statement = members[i];
|
||||
switch (statement.kind) {
|
||||
|
||||
case NodeKind.CLASS:
|
||||
@ -540,7 +540,6 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
private initializeVariables(statement: VariableStatement, isNamespaceMember: bool = false): void {
|
||||
const declarations: VariableDeclaration[] = statement.declarations;
|
||||
const isExport: bool = !isNamespaceMember && hasModifier(ModifierKind.EXPORT, statement.modifiers);
|
||||
for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i) {
|
||||
const declaration: VariableDeclaration = declarations[i];
|
||||
const internalName: string = declaration.internalName;
|
||||
@ -549,7 +548,7 @@ export class Program extends DiagnosticEmitter {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
else {
|
||||
this.elements.set(internalName, global);
|
||||
if (isExport) {
|
||||
if (global.isExported) {
|
||||
if (this.exports.has(internalName))
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
else
|
||||
@ -559,6 +558,7 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/** Resolves a {@link TypeNode} to a concrete {@link Type}. */
|
||||
resolveType(node: TypeNode, contextualTypeArguments: Map<string,Type> | null = null, reportNotFound: bool = true): Type | null {
|
||||
|
||||
// resolve parameters
|
||||
@ -596,6 +596,7 @@ export class Program extends DiagnosticEmitter {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Resolves {@link TypeParameter}s to concrete {@link Type}s. */
|
||||
resolveTypeArguments(typeParameters: TypeParameter[], typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): Type[] | null {
|
||||
const parameterCount: i32 = typeParameters.length;
|
||||
const argumentCount: i32 = typeArgumentNodes ? typeArgumentNodes.length : 0;
|
||||
@ -684,83 +685,193 @@ function checkGlobalDecorator(decorators: Decorator[]): string | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Indicates the specific kind of an {@link Element}. */
|
||||
export enum ElementKind {
|
||||
/** A {@link ClassPrototype}. */
|
||||
CLASS_PROTOTYPE,
|
||||
/** A {@link Class}. */
|
||||
CLASS,
|
||||
/** An {@link Enum}. */
|
||||
ENUM,
|
||||
/** An {@link EnumValue}. */
|
||||
ENUMVALUE,
|
||||
/** A {@link FieldPrototype}. */
|
||||
FIELD_PROTOTYPE,
|
||||
/** A {@link Field}. */
|
||||
FIELD,
|
||||
/** A {@link FunctionPrototype}. */
|
||||
FUNCTION_PROTOTYPE,
|
||||
/** A {@link Function}. */
|
||||
FUNCTION,
|
||||
/** A {@link Global}. */
|
||||
GLOBAL,
|
||||
/** An {@link InterfacePrototype}. */
|
||||
INTERFACE_PROTOTYPE,
|
||||
/** An {@link Interface}. */
|
||||
INTERFACE,
|
||||
/** A {@link Local}. */
|
||||
LOCAL,
|
||||
/** A {@link Namespace}. */
|
||||
NAMESPACE
|
||||
}
|
||||
|
||||
/** Indicates traits of an {@link Element}. */
|
||||
export enum ElementFlags {
|
||||
/** No flags set. */
|
||||
NONE = 0,
|
||||
/** Is compiled. */
|
||||
COMPILED = 1 << 0,
|
||||
/** Is an import. */
|
||||
IMPORTED = 1 << 1,
|
||||
/** Is an export. */
|
||||
EXPORTED = 1 << 2,
|
||||
/** Is built-in. */
|
||||
BUILTIN = 1 << 3,
|
||||
/** Is declared. */
|
||||
DECLARED = 1 << 4,
|
||||
/** Is generic. */
|
||||
GENERIC = 1 << 5,
|
||||
/** Is constant. */
|
||||
CONSTANT = 1 << 6,
|
||||
/** Has constant value. */
|
||||
CONSTANT_VALUE = 1 << 7,
|
||||
/** Is instance member. */
|
||||
INSTANCE = 1 << 8,
|
||||
/** Is getter. */
|
||||
GETTER = 1 << 9,
|
||||
/** Is setter. */
|
||||
SETTER = 1 << 10
|
||||
}
|
||||
|
||||
/** Base class of all program elements. */
|
||||
export abstract class Element {
|
||||
|
||||
/** Specific element kind. */
|
||||
kind: ElementKind;
|
||||
/** Containing {@link Program}. */
|
||||
program: Program;
|
||||
/** Internal name referring to this element. */
|
||||
internalName: string;
|
||||
isCompiled: bool = false;
|
||||
isImport: bool = false;
|
||||
isBuiltIn: bool = false;
|
||||
isDeclare: bool = false;
|
||||
/** Element flags. */
|
||||
flags: ElementFlags = ElementFlags.NONE;
|
||||
|
||||
constructor(program: Program, internalName: string) {
|
||||
/** Constructs a new element, linking it to its containing {@link Program}. */
|
||||
protected constructor(program: Program, internalName: string) {
|
||||
this.program = program;
|
||||
this.internalName = internalName;
|
||||
}
|
||||
|
||||
/** Whether compiled or not. */
|
||||
get isCompiled(): bool { return (this.flags & ElementFlags.COMPILED) != 0; }
|
||||
set isCompiled(is: bool) { if (is) this.flags |= ElementFlags.COMPILED; else this.flags &= ~ElementFlags.COMPILED; }
|
||||
|
||||
/** Whether imported or not. */
|
||||
get isImported(): bool { return (this.flags & ElementFlags.IMPORTED) != 0; }
|
||||
set isImported(is: bool) { if (is) this.flags |= ElementFlags.IMPORTED; else this.flags &= ~ElementFlags.IMPORTED; }
|
||||
|
||||
/** Whether exported or not. */
|
||||
get isExported(): bool { return (this.flags & ElementFlags.EXPORTED) != 0; }
|
||||
set isExported(is: bool) { if (is) this.flags |= ElementFlags.EXPORTED; else this.flags &= ~ElementFlags.EXPORTED; }
|
||||
|
||||
/** Whether built-in or not. */
|
||||
get isBuiltIn(): bool { return (this.flags & ElementFlags.BUILTIN) != 0; }
|
||||
set isBuiltIn(is: bool) { if (is) this.flags |= ElementFlags.BUILTIN; else this.flags &= ~ElementFlags.BUILTIN; }
|
||||
|
||||
/** Whether declared or not. */
|
||||
get isDeclared(): bool { return (this.flags & ElementFlags.DECLARED) != 0; }
|
||||
set isDeclared(is: bool) { if (is) this.flags |= ElementFlags.DECLARED; else this.flags &= ~ElementFlags.DECLARED; }
|
||||
|
||||
/** Whether generic or not. */
|
||||
get isGeneric(): bool { return (this.flags & ElementFlags.GENERIC) != 0; }
|
||||
set isGeneric(is: bool) { if (is) this.flags |= ElementFlags.GENERIC; else this.flags &= ~ElementFlags.GENERIC; }
|
||||
|
||||
/** Whether constant or not. */
|
||||
get isConstant(): bool { return (this.flags & ElementFlags.CONSTANT) != 0; }
|
||||
set isConstant(is: bool) { if (is) this.flags |= ElementFlags.CONSTANT; else this.flags &= ~ElementFlags.CONSTANT; }
|
||||
|
||||
/** Whether mutable or not. */
|
||||
get isMutable(): bool { return !(this.flags & ElementFlags.CONSTANT); } // reuses constant flag
|
||||
set isMutable(is: bool) { if (is) this.flags &= ~ElementFlags.CONSTANT; else this.flags |= ElementFlags.CONSTANT; }
|
||||
|
||||
/** Whether this element has a constant value or not. */
|
||||
get hasConstantValue(): bool { return (this.flags & ElementFlags.CONSTANT_VALUE) != 0; }
|
||||
set hasConstantValue(is: bool) { if (is) this.flags |= ElementFlags.CONSTANT_VALUE; else this.flags &= ~ElementFlags.CONSTANT_VALUE; }
|
||||
|
||||
/** Whether an instance member or not. */
|
||||
get isInstance(): bool { return (this.flags & ElementFlags.INSTANCE) != 0; }
|
||||
set isInstance(is: bool) { if (is) this.flags |= ElementFlags.INSTANCE; else this.flags &= ~ElementFlags.INSTANCE; }
|
||||
}
|
||||
|
||||
/** A namespace. Also the base class of other namespace-like program elements. */
|
||||
export class Namespace extends Element {
|
||||
|
||||
kind = ElementKind.NAMESPACE;
|
||||
|
||||
/** Declaration reference. */
|
||||
declaration: NamespaceDeclaration | null;
|
||||
/** Member elements. */
|
||||
members: Map<string,Element> = new Map();
|
||||
|
||||
constructor(program: Program, internalName: string, declaration: NamespaceDeclaration | null) {
|
||||
/** Constructs a new namespace. */
|
||||
constructor(program: Program, internalName: string, declaration: NamespaceDeclaration | null = null) {
|
||||
super(program, internalName);
|
||||
this.declaration = declaration;
|
||||
if ((this.declaration = declaration) && this.declaration.modifiers) {
|
||||
for (let i: i32 = 0, k: i32 = this.declaration.modifiers.length; i < k; ++i) {
|
||||
switch (this.declaration.modifiers[i].modifierKind) {
|
||||
case ModifierKind.IMPORT: this.isImported = true; break;
|
||||
case ModifierKind.EXPORT: this.isExported = true; break;
|
||||
case ModifierKind.DECLARE: this.isDeclared = true; break;
|
||||
default: throw new Error("unexpected modifier");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : false; }
|
||||
}
|
||||
|
||||
/** An enum. */
|
||||
export class Enum extends Namespace {
|
||||
|
||||
kind = ElementKind.ENUM;
|
||||
|
||||
/** Declaration reference. */
|
||||
declaration: EnumDeclaration | null;
|
||||
/** Enum members. */
|
||||
members: Map<string,EnumValue> = new Map(); // more specific
|
||||
|
||||
/** Constructs a new enum. */
|
||||
constructor(program: Program, internalName: string, declaration: EnumDeclaration | null = null) {
|
||||
super(program, internalName, null);
|
||||
this.declaration = declaration;
|
||||
if ((this.declaration = declaration) && this.declaration.modifiers) {
|
||||
for (let i: i32 = 0, k = this.declaration.modifiers.length; i < k; ++i) {
|
||||
switch (this.declaration.modifiers[i].modifierKind) {
|
||||
case ModifierKind.EXPORT: this.isExported = true; break;
|
||||
case ModifierKind.IMPORT: this.isImported = true; break;
|
||||
case ModifierKind.DECLARE: this.isDeclared = true; break;
|
||||
case ModifierKind.CONST: this.isConstant = true; break;
|
||||
default: throw new Error("unexpected modifier");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't exports */ false; }
|
||||
get isConstant(): bool { return this.declaration ? hasModifier(ModifierKind.CONST, this.declaration.modifiers) : /* internals are const */ true; }
|
||||
}
|
||||
|
||||
/** An enum value. */
|
||||
export class EnumValue extends Element {
|
||||
|
||||
kind = ElementKind.ENUMVALUE;
|
||||
|
||||
/** Declaration reference. */
|
||||
declaration: EnumValueDeclaration | null;
|
||||
/** Parent enum. */
|
||||
enum: Enum;
|
||||
hasConstantValue: bool;
|
||||
/** Constant value, if applicable. */
|
||||
constantValue: i32 = 0;
|
||||
|
||||
constructor(enm: Enum, program: Program, internalName: string, declaration: EnumValueDeclaration | null = null) {
|
||||
super(program, internalName);
|
||||
this.enum = enm;
|
||||
if (!(this.declaration = declaration)) this.hasConstantValue = true;
|
||||
if (!(this.declaration = declaration))
|
||||
this.hasConstantValue = true; // built-ins have constant values
|
||||
}
|
||||
}
|
||||
|
||||
@ -768,29 +879,50 @@ export class EnumValue extends Element {
|
||||
export class Global extends Element {
|
||||
|
||||
kind = ElementKind.GLOBAL;
|
||||
|
||||
/** Declaration reference. */
|
||||
declaration: VariableLikeDeclarationStatement | null;
|
||||
/** Resolved type, if resolved. */
|
||||
type: Type | null;
|
||||
hasConstantValue: bool = false;
|
||||
/** Constant integer value, if applicable. */
|
||||
constantIntegerValue: I64 | null = null;
|
||||
/** Constant float value, if applicable. */
|
||||
constantFloatValue: f64 = 0;
|
||||
|
||||
constructor(program: Program, internalName: string, declaration: VariableLikeDeclarationStatement | null, type: Type | null) {
|
||||
constructor(program: Program, internalName: string, declaration: VariableLikeDeclarationStatement | null = null, type: Type | null = null) {
|
||||
super(program, internalName);
|
||||
if (!(this.declaration = declaration)) this.hasConstantValue = true;
|
||||
this.type = type; // resolved later if `null`, also updates constantKind
|
||||
if (this.declaration = declaration) {
|
||||
if (this.declaration.modifiers) {
|
||||
for (let i: i32 = 0, k = this.declaration.modifiers.length; i < k; ++i) {
|
||||
switch (this.declaration.modifiers[i].modifierKind) {
|
||||
case ModifierKind.IMPORT: this.isImported = true; break;
|
||||
case ModifierKind.EXPORT: this.isExported = true; break;
|
||||
case ModifierKind.CONST: this.isConstant = true; break;
|
||||
case ModifierKind.DECLARE: this.isDeclared = true; break;
|
||||
default: throw new Error("unexpected modifier");
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.hasConstantValue = true; // built-ins have constant values
|
||||
}
|
||||
this.type = type; // resolved later if `null`
|
||||
}
|
||||
|
||||
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't exports */ false; }
|
||||
get isMutable(): bool { return this.declaration ? !hasModifier(ModifierKind.CONST, this.declaration.modifiers) : /* internals are immutable */ false; }
|
||||
}
|
||||
|
||||
/** A function parameter. */
|
||||
export class Parameter {
|
||||
|
||||
// not an Element on its own
|
||||
|
||||
/** Parameter name. */
|
||||
name: string;
|
||||
/** Parameter type. */
|
||||
type: Type;
|
||||
/** Parameter initializer. */
|
||||
initializer: Expression | null;
|
||||
|
||||
/** Constructs a new function parameter. */
|
||||
constructor(name: string, type: Type, initializer: Expression | null = null) {
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
@ -802,7 +934,10 @@ export class Parameter {
|
||||
export class Local extends Element {
|
||||
|
||||
kind = ElementKind.LOCAL;
|
||||
|
||||
/** Local index. */
|
||||
index: i32;
|
||||
/** Local type. */
|
||||
type: Type;
|
||||
|
||||
constructor(program: Program, internalName: string, index: i32, type: Type) {
|
||||
@ -816,22 +951,44 @@ export class Local extends Element {
|
||||
export class FunctionPrototype extends Element {
|
||||
|
||||
kind = ElementKind.FUNCTION_PROTOTYPE;
|
||||
declaration: FunctionDeclaration | null;
|
||||
classPrototype: ClassPrototype | null;
|
||||
instances: Map<string,Function> = new Map();
|
||||
isGeneric: bool;
|
||||
|
||||
/** Declaration reference. */
|
||||
declaration: FunctionDeclaration | null;
|
||||
/** Class prototype reference. */
|
||||
classPrototype: ClassPrototype | null;
|
||||
/** Resolved instances. */
|
||||
instances: Map<string,Function> = new Map();
|
||||
|
||||
/** Constructs a new function prototype. */
|
||||
constructor(program: Program, internalName: string, declaration: FunctionDeclaration | null, classPrototype: ClassPrototype | null = null) {
|
||||
super(program, internalName);
|
||||
this.declaration = declaration;
|
||||
this.classPrototype = classPrototype;
|
||||
this.isGeneric = declaration ? declaration.typeParameters.length > 0 : false; // built-ins set this
|
||||
if (this.declaration = declaration) {
|
||||
if (this.declaration.modifiers)
|
||||
for (let i: i32 = 0, k: i32 = this.declaration.modifiers.length; i < k; ++i) {
|
||||
switch (this.declaration.modifiers[i].modifierKind) {
|
||||
case ModifierKind.IMPORT: this.isImported = true; break;
|
||||
case ModifierKind.EXPORT: this.isExported = true; break;
|
||||
case ModifierKind.DECLARE: this.isDeclared = true; break;
|
||||
case ModifierKind.GET: this.isGetter = true; break;
|
||||
case ModifierKind.SET: this.isSetter = true; break;
|
||||
default: throw new Error("unexpected modifier");
|
||||
}
|
||||
}
|
||||
if (this.declaration.typeParameters.length)
|
||||
this.isGeneric = true;
|
||||
}
|
||||
if (this.classPrototype = classPrototype) {
|
||||
this.isInstance = true;
|
||||
}
|
||||
}
|
||||
|
||||
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't file-level exports */ false; }
|
||||
get isInstance(): bool { return this.classPrototype != null; }
|
||||
get isGetter(): bool { return this.declaration ? hasModifier(ModifierKind.GET, this.declaration.modifiers) : /* internals aren't getters */ false; }
|
||||
get isSetter(): bool { return this.declaration ? hasModifier(ModifierKind.SET, this.declaration.modifiers) : /* internals aren't setters */ false; }
|
||||
/** Whether a getter function or not. */
|
||||
get isGetter(): bool { return (this.flags & ElementFlags.GETTER) != 0; }
|
||||
set isGetter(is: bool) { if (is) this.flags |= ElementFlags.GETTER; else this.flags &= ~ElementFlags.GETTER; }
|
||||
|
||||
/** Whether a setter function or not. */
|
||||
get isSetter(): bool { return (this.flags & ElementFlags.SETTER) != 0; }
|
||||
set isSetter(is: bool) { if (is) this.flags |= ElementFlags.SETTER; else this.flags &= ~ElementFlags.SETTER; }
|
||||
|
||||
resolve(typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null): Function | null {
|
||||
const instanceKey: string = typesToString(typeArguments, "", "");
|
||||
@ -912,8 +1069,8 @@ export class Function extends Element {
|
||||
|
||||
kind = ElementKind.FUNCTION;
|
||||
|
||||
/** Underlying function template. */
|
||||
template: FunctionPrototype;
|
||||
/** Prototype reference. */
|
||||
prototype: FunctionPrototype;
|
||||
/** Concrete type arguments. */
|
||||
typeArguments: Type[];
|
||||
/** Concrete function parameters. Excluding `this` if an instance method. */
|
||||
@ -937,13 +1094,12 @@ export class Function extends Element {
|
||||
/** Constructs a new concrete function. */
|
||||
constructor(prototype: FunctionPrototype, internalName: string, typeArguments: Type[], parameters: Parameter[], returnType: Type, instanceMethodOf: Class | null) {
|
||||
super(prototype.program, internalName);
|
||||
this.template = prototype;
|
||||
this.prototype = prototype;
|
||||
this.typeArguments = typeArguments;
|
||||
this.parameters = parameters;
|
||||
this.returnType = returnType;
|
||||
this.instanceMethodOf = instanceMethodOf;
|
||||
this.isBuiltIn = prototype.isBuiltIn;
|
||||
this.isDeclare = prototype.isDeclare;
|
||||
this.flags = prototype.flags;
|
||||
let localIndex: i32 = 0;
|
||||
if (instanceMethodOf) {
|
||||
this.locals.set("this", new Local(prototype.program, "this", localIndex++, instanceMethodOf.type));
|
||||
@ -964,7 +1120,7 @@ export class Function extends Element {
|
||||
// if it has a name, check previously as this method will throw otherwise
|
||||
let localIndex = this.parameters.length + this.additionalLocals.length;
|
||||
if (this.isInstance) localIndex++; // plus 'this'
|
||||
const local: Local = new Local(this.template.program, name ? name : "anonymous$" + localIndex.toString(10), localIndex, type);
|
||||
const local: Local = new Local(this.prototype.program, name ? name : "anonymous$" + localIndex.toString(10), localIndex, type);
|
||||
if (name) {
|
||||
if (this.locals.has(<string>name))
|
||||
throw new Error("unexpected duplicate local name");
|
||||
@ -1050,30 +1206,45 @@ export class Function extends Element {
|
||||
export class FieldPrototype extends Element {
|
||||
|
||||
kind = ElementKind.FIELD_PROTOTYPE;
|
||||
|
||||
/** Declaration reference. */
|
||||
declaration: FieldDeclaration | null;
|
||||
/** Parent class prototype. */
|
||||
classPrototype: ClassPrototype;
|
||||
|
||||
constructor(classPrototype: ClassPrototype, internalName: string, declaration: FieldDeclaration | null) {
|
||||
/** Constructs a new field prototype. */
|
||||
constructor(classPrototype: ClassPrototype, internalName: string, declaration: FieldDeclaration | null = null) {
|
||||
super(classPrototype.program, internalName);
|
||||
this.classPrototype = classPrototype;
|
||||
if ((this.declaration = declaration) && this.declaration.modifiers) {
|
||||
for (let i: i32 = 0, k = this.declaration.modifiers.length; i < k; ++i) {
|
||||
switch (this.declaration.modifiers[i].modifierKind) {
|
||||
case ModifierKind.EXPORT: this.isExported = true; break;
|
||||
default: throw new Error("unexpected modifier");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't file-level exports */ false; }
|
||||
}
|
||||
|
||||
/** A resolved instance field. */
|
||||
export class Field extends Element {
|
||||
|
||||
kind = ElementKind.FIELD;
|
||||
template: FieldPrototype;
|
||||
|
||||
/** Field prototype reference. */
|
||||
prototype: FieldPrototype;
|
||||
/** Resolved type. */
|
||||
type: Type;
|
||||
hasConstantValue: bool = false;
|
||||
/** Constant integer value, if applicable. */
|
||||
constantIntegerValue: I64 | null = null;
|
||||
/** Constant float value, if applicable. */
|
||||
constantFloatValue: f64 = 0;
|
||||
|
||||
constructor(template: FieldPrototype, internalName: string, type: Type) {
|
||||
super(template.program, internalName);
|
||||
if (!this.template.declaration) this.hasConstantValue = true;
|
||||
/** Constructs a new field. */
|
||||
constructor(prototype: FieldPrototype, internalName: string, type: Type) {
|
||||
super(prototype.program, internalName);
|
||||
this.flags = prototype.flags;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
@ -1082,19 +1253,31 @@ export class Field extends Element {
|
||||
export class ClassPrototype extends Namespace {
|
||||
|
||||
kind = ElementKind.CLASS_PROTOTYPE;
|
||||
|
||||
/** Declaration reference. */
|
||||
declaration: ClassDeclaration | null;
|
||||
/** Resolved instances. */
|
||||
instances: Map<string,Class>;
|
||||
isGeneric: bool;
|
||||
|
||||
constructor(program: Program, internalName: string, declaration: ClassDeclaration | null = null) {
|
||||
super(program, internalName, null);
|
||||
this.declaration = declaration;
|
||||
if (this.declaration = declaration) {
|
||||
if (this.declaration.modifiers) {
|
||||
for (let i: i32 = 0, k: i32 = this.declaration.modifiers.length; i < k; ++i) {
|
||||
switch (this.declaration.modifiers[i].modifierKind) {
|
||||
case ModifierKind.IMPORT: this.isImported = true; break;
|
||||
case ModifierKind.EXPORT: this.isExported = true; break;
|
||||
case ModifierKind.DECLARE: this.isDeclared = true; break;
|
||||
default: throw new Error("unexpected modifier");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.declaration.typeParameters.length)
|
||||
this.isGeneric = true;
|
||||
}
|
||||
this.instances = new Map();
|
||||
this.isGeneric = declaration ? declaration.typeParameters.length > 0 : false; // builtins can set this
|
||||
}
|
||||
|
||||
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't file-level exports */ false; }
|
||||
|
||||
resolve(typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null): Class {
|
||||
const key: string = typesToString(typeArguments, "", "");
|
||||
let instance: Class | null = <Class | null>this.instances.get(key);
|
||||
@ -1125,20 +1308,26 @@ export class ClassPrototype extends Namespace {
|
||||
export class Class extends Namespace {
|
||||
|
||||
kind = ElementKind.CLASS;
|
||||
declaration: ClassDeclaration | null;
|
||||
template: ClassPrototype;
|
||||
|
||||
/** Prototype reference. */
|
||||
prototype: ClassPrototype;
|
||||
/** Resolved type arguments. */
|
||||
typeArguments: Type[];
|
||||
base: Class | null;
|
||||
/** Resolved class type. */
|
||||
type: Type;
|
||||
/** Base class, if applicable. */
|
||||
base: Class | null;
|
||||
|
||||
contextualTypeArguments: Map<string,Type> = new Map();
|
||||
|
||||
constructor(template: ClassPrototype, internalName: string, typeArguments: Type[], base: Class | null) {
|
||||
super(template.program, internalName, template.declaration);
|
||||
this.template = template;
|
||||
/** Constructs a new class. */
|
||||
constructor(prototype: ClassPrototype, internalName: string, typeArguments: Type[] = [], base: Class | null = null) {
|
||||
super(prototype.program, internalName, prototype.declaration);
|
||||
this.prototype = prototype;
|
||||
this.flags = prototype.flags;
|
||||
this.typeArguments = typeArguments;
|
||||
this.base = base;
|
||||
this.type = (template.program.target == Target.WASM64 ? Type.usize64 : Type.usize32).asClass(this);
|
||||
this.type = (prototype.program.target == Target.WASM64 ? Type.usize64 : Type.usize32).asClass(this);
|
||||
|
||||
// inherit base class contextual type arguments
|
||||
if (base)
|
||||
@ -1146,7 +1335,7 @@ export class Class extends Namespace {
|
||||
this.contextualTypeArguments.set(name, type);
|
||||
|
||||
// apply instance-specific contextual type arguments
|
||||
const declaration: ClassDeclaration | null = this.template.declaration;
|
||||
const declaration: ClassDeclaration | null = this.prototype.declaration;
|
||||
if (declaration) { // irrelevant for built-ins
|
||||
const typeParameters: TypeParameter[] = declaration.typeParameters;
|
||||
if (typeParameters.length != typeArguments.length)
|
||||
@ -1165,9 +1354,12 @@ export class Class extends Namespace {
|
||||
export class InterfacePrototype extends ClassPrototype {
|
||||
|
||||
kind = ElementKind.INTERFACE_PROTOTYPE;
|
||||
|
||||
/** Declaration reference. */
|
||||
declaration: InterfaceDeclaration | null;
|
||||
|
||||
constructor(program: Program, internalName: string, declaration: InterfaceDeclaration | null) {
|
||||
/** Constructs a new interface prototype. */
|
||||
constructor(program: Program, internalName: string, declaration: InterfaceDeclaration | null = null) {
|
||||
super(program, internalName, declaration);
|
||||
}
|
||||
}
|
||||
@ -1176,10 +1368,14 @@ export class InterfacePrototype extends ClassPrototype {
|
||||
export class Interface extends Class {
|
||||
|
||||
kind = ElementKind.INTERFACE;
|
||||
template: InterfacePrototype;
|
||||
|
||||
/** Prototype reference. */
|
||||
prototype: InterfacePrototype;
|
||||
/** Base interface, if applcable. */
|
||||
base: Interface | null;
|
||||
|
||||
constructor(template: InterfacePrototype, internalName: string, typeArguments: Type[], base: Interface | null) {
|
||||
super(template, internalName, typeArguments, base);
|
||||
/** Constructs a new interface. */
|
||||
constructor(prototype: InterfacePrototype, internalName: string, typeArguments: Type[] = [], base: Interface | null = null) {
|
||||
super(prototype, internalName, typeArguments, base);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user