mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-07-07 02:21:55 +00:00
Getters & setters (static); Instantiate compiler tests; Cleanup
This commit is contained in:
450
src/program.ts
450
src/program.ts
@ -7,7 +7,11 @@ import {
|
||||
} from "./compiler";
|
||||
|
||||
import {
|
||||
PATH_DELIMITER
|
||||
PATH_DELIMITER,
|
||||
GETTER_PREFIX,
|
||||
SETTER_PREFIX,
|
||||
STATIC_DELIMITER,
|
||||
INSTANCE_DELIMITER
|
||||
} from "./constants";
|
||||
|
||||
import {
|
||||
@ -60,7 +64,8 @@ import {
|
||||
VariableDeclaration,
|
||||
VariableStatement,
|
||||
|
||||
hasModifier
|
||||
hasModifier,
|
||||
mangleInternalName
|
||||
} from "./ast";
|
||||
|
||||
import {
|
||||
@ -88,7 +93,7 @@ export class Program extends DiagnosticEmitter {
|
||||
sources: Source[];
|
||||
/** Diagnostic offset used where sequentially obtaining the next diagnostic. */
|
||||
diagnosticsOffset: i32 = 0;
|
||||
/** WASM target. */
|
||||
/** WebAssembly target. */
|
||||
target: Target = Target.WASM32; // set on initialization
|
||||
/** Elements by internal name. */
|
||||
elements: Map<string,Element> = new Map();
|
||||
@ -102,7 +107,7 @@ export class Program extends DiagnosticEmitter {
|
||||
/** Constructs a new program, optionally inheriting parser diagnostics. */
|
||||
constructor(diagnostics: DiagnosticMessage[] | null = null) {
|
||||
super(diagnostics);
|
||||
this.sources = new Array();
|
||||
this.sources = [];
|
||||
}
|
||||
|
||||
/** Initializes the program and its elements prior to compilation. */
|
||||
@ -130,15 +135,15 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
initializeBuiltins(this);
|
||||
|
||||
const queuedExports: Map<string,QueuedExport> = new Map();
|
||||
const queuedImports: QueuedImport[] = new Array();
|
||||
const queuedExports = new Map<string,QueuedExport>();
|
||||
const queuedImports = new Array<QueuedImport>();
|
||||
|
||||
// build initial lookup maps of internal names to declarations
|
||||
for (let i: i32 = 0, k: i32 = this.sources.length; i < k; ++i) {
|
||||
const source: Source = this.sources[i];
|
||||
const statements: Statement[] = source.statements;
|
||||
for (let j: i32 = 0, l: i32 = statements.length; j < l; ++j) {
|
||||
const statement: Statement = statements[j];
|
||||
for (let i = 0, k = this.sources.length; i < k; ++i) {
|
||||
const source = this.sources[i];
|
||||
const statements = source.statements;
|
||||
for (let j = 0, l = statements.length; j < l; ++j) {
|
||||
const statement = statements[j];
|
||||
switch (statement.kind) {
|
||||
|
||||
case NodeKind.CLASS:
|
||||
@ -183,15 +188,15 @@ export class Program extends DiagnosticEmitter {
|
||||
let element: Element | null;
|
||||
|
||||
// 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];
|
||||
for (let j = 0; j < queuedImports.length;) {
|
||||
const queuedImport = queuedImports[j];
|
||||
element = this.tryResolveImport(queuedImport.referencedName, queuedExports);
|
||||
if (element) {
|
||||
this.elements.set(queuedImport.internalName, element);
|
||||
queuedImports.splice(i, 1);
|
||||
queuedImports.splice(j, 1);
|
||||
} else {
|
||||
this.error(DiagnosticCode.Module_0_has_no_exported_member_1, queuedImport.declaration.range, (<ImportStatement>queuedImport.declaration.parent).path.value, queuedImport.declaration.externalIdentifier.name);
|
||||
++i;
|
||||
++j;
|
||||
}
|
||||
}
|
||||
|
||||
@ -200,16 +205,16 @@ export class Program extends DiagnosticEmitter {
|
||||
let currentExport: QueuedExport | null = queuedExport;
|
||||
do {
|
||||
if (currentExport.isReExport) {
|
||||
element = <Element | null>this.exports.get(currentExport.referencedName);
|
||||
element = this.exports.get(currentExport.referencedName);
|
||||
if (element) {
|
||||
this.exports.set(exportName, element);
|
||||
break;
|
||||
}
|
||||
currentExport = <QueuedExport | null>queuedExports.get(currentExport.referencedName);
|
||||
currentExport = queuedExports.get(currentExport.referencedName);
|
||||
if (!currentExport)
|
||||
this.error(DiagnosticCode.Module_0_has_no_exported_member_1, queuedExport.member.externalIdentifier.range, (<StringLiteralExpression>(<ExportStatement>queuedExport.member.parent).path).value, queuedExport.member.externalIdentifier.name);
|
||||
} else {
|
||||
element = <Element | null>this.elements.get(currentExport.referencedName);
|
||||
element = this.elements.get(currentExport.referencedName);
|
||||
if (element)
|
||||
this.exports.set(exportName, element);
|
||||
else
|
||||
@ -224,29 +229,30 @@ export class Program extends DiagnosticEmitter {
|
||||
private tryResolveImport(referencedName: string, queuedExports: Map<string,QueuedExport>): Element | null {
|
||||
let element: Element | null;
|
||||
do {
|
||||
element = <Element | null>this.exports.get(referencedName);
|
||||
element = this.exports.get(referencedName);
|
||||
if (element)
|
||||
return element;
|
||||
const queuedExport: QueuedExport | null = <QueuedExport | null>queuedExports.get(referencedName);
|
||||
const queuedExport = queuedExports.get(referencedName);
|
||||
if (!queuedExport)
|
||||
return null;
|
||||
if (queuedExport.isReExport) {
|
||||
referencedName = queuedExport.referencedName;
|
||||
continue;
|
||||
}
|
||||
return <Element | null>this.elements.get(queuedExport.referencedName);
|
||||
return this.elements.get(queuedExport.referencedName);
|
||||
} while (true);
|
||||
}
|
||||
|
||||
private initializeClass(declaration: ClassDeclaration, namespace: Element | null = null): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const internalName = declaration.internalName;
|
||||
if (this.elements.has(internalName)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
|
||||
return;
|
||||
}
|
||||
const prototype: ClassPrototype = new ClassPrototype(this, declaration.name.name, internalName, declaration);
|
||||
const prototype = new ClassPrototype(this, declaration.name.name, internalName, declaration);
|
||||
this.elements.set(internalName, prototype);
|
||||
|
||||
// add program-level alias if annotated as @global
|
||||
if (hasDecorator("global", declaration.decorators)) {
|
||||
if (this.elements.has(declaration.name.name))
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
|
||||
@ -254,6 +260,7 @@ export class Program extends DiagnosticEmitter {
|
||||
this.elements.set(declaration.name.name, prototype);
|
||||
}
|
||||
|
||||
// add as namespace member if applicable
|
||||
if (namespace) {
|
||||
if (namespace.members) {
|
||||
if (namespace.members.has(declaration.name.name)) {
|
||||
@ -263,6 +270,8 @@ export class Program extends DiagnosticEmitter {
|
||||
} else
|
||||
namespace.members = new Map();
|
||||
namespace.members.set(declaration.name.name, prototype);
|
||||
|
||||
// otherwise add to file-level exports if exported
|
||||
} else if (prototype.isExported) {
|
||||
if (this.exports.has(internalName)) {
|
||||
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.name.range, internalName);
|
||||
@ -271,27 +280,28 @@ export class Program extends DiagnosticEmitter {
|
||||
this.exports.set(internalName, prototype);
|
||||
}
|
||||
|
||||
const memberDeclarations: DeclarationStatement[] = declaration.members;
|
||||
for (let j: i32 = 0, l: i32 = memberDeclarations.length; j < l; ++j) {
|
||||
switch (memberDeclarations[j].kind) {
|
||||
// initialize members
|
||||
const memberDeclarations = declaration.members;
|
||||
for (let i = 0, k = memberDeclarations.length; i < k; ++i) {
|
||||
switch (memberDeclarations[i].kind) {
|
||||
|
||||
case NodeKind.FIELD:
|
||||
this.initializeField(<FieldDeclaration>memberDeclarations[j], prototype);
|
||||
this.initializeField(<FieldDeclaration>memberDeclarations[i], prototype);
|
||||
break;
|
||||
|
||||
case NodeKind.METHOD:
|
||||
this.initializeMethod(<MethodDeclaration>memberDeclarations[j], prototype);
|
||||
case NodeKind.METHOD: // also getter/setter
|
||||
this.initializeMethod(<MethodDeclaration>memberDeclarations[i], prototype);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("unexpected class member");
|
||||
throw new Error("class member expected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private initializeField(declaration: FieldDeclaration, classPrototype: ClassPrototype): void {
|
||||
const name: string = declaration.name.name;
|
||||
const internalName: string = declaration.internalName;
|
||||
const name = declaration.name.name;
|
||||
const internalName = declaration.internalName;
|
||||
|
||||
// static fields become global variables
|
||||
if (hasModifier(ModifierKind.STATIC, declaration.modifiers)) {
|
||||
@ -306,7 +316,7 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
} else
|
||||
classPrototype.members = new Map();
|
||||
const staticField: Global = new Global(this, internalName, declaration, null);
|
||||
const staticField = new Global(this, internalName, declaration, null);
|
||||
classPrototype.members.set(name, staticField);
|
||||
this.elements.set(internalName, staticField);
|
||||
|
||||
@ -325,11 +335,17 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
private initializeMethod(declaration: MethodDeclaration, classPrototype: ClassPrototype): void {
|
||||
let name: string = declaration.name.name;
|
||||
const internalName: string = declaration.internalName;
|
||||
let isGetter = false;
|
||||
if ((isGetter = hasModifier(ModifierKind.GET, declaration.modifiers)) || hasModifier(ModifierKind.SET, declaration.modifiers)) {
|
||||
this.initializeAccessor(declaration, classPrototype, isGetter);
|
||||
return;
|
||||
}
|
||||
const name = declaration.name.name;
|
||||
const internalName = declaration.internalName;
|
||||
|
||||
// static methods become global functions
|
||||
if (hasModifier(ModifierKind.STATIC, declaration.modifiers)) {
|
||||
|
||||
if (this.elements.has(internalName)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, declaration.internalName);
|
||||
return;
|
||||
@ -359,13 +375,64 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
private initializeAccessor(declaration: MethodDeclaration, classPrototype: ClassPrototype, isGetter: bool): void {
|
||||
const propertyName = declaration.name.name;
|
||||
const internalPropertyName = declaration.internalName;
|
||||
|
||||
let propertyElement = this.elements.get(internalPropertyName);
|
||||
if (propertyElement) {
|
||||
if (propertyElement.kind != ElementKind.PROPERTY || (isGetter ? (<Property>propertyElement).getterPrototype : (<Property>propertyElement).setterPrototype)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalPropertyName);
|
||||
return;
|
||||
}
|
||||
} else
|
||||
propertyElement = new Property(this, propertyName, internalPropertyName, classPrototype);
|
||||
|
||||
let name = (isGetter ? GETTER_PREFIX : SETTER_PREFIX) + propertyName;
|
||||
|
||||
// static accessors become global functions
|
||||
if (hasModifier(ModifierKind.STATIC, declaration.modifiers)) {
|
||||
const internalStaticName = classPrototype.internalName + STATIC_DELIMITER + name;
|
||||
if (this.elements.has(internalStaticName)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalStaticName);
|
||||
return;
|
||||
}
|
||||
const staticPrototype = new FunctionPrototype(this, name, internalStaticName, declaration, null);
|
||||
if (isGetter)
|
||||
(<Property>propertyElement).getterPrototype = staticPrototype;
|
||||
else
|
||||
(<Property>propertyElement).setterPrototype = staticPrototype;
|
||||
if (!classPrototype.members)
|
||||
classPrototype.members = new Map();
|
||||
classPrototype.members.set(propertyName, propertyElement); // checked above
|
||||
this.elements.set(internalPropertyName, propertyElement);
|
||||
|
||||
// instance accessors are remembered until resolved
|
||||
} else {
|
||||
const internalInstanceName = classPrototype.internalName + INSTANCE_DELIMITER + name;
|
||||
if (classPrototype.instanceMembers) {
|
||||
if (classPrototype.instanceMembers.has(name)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, declaration.internalName);
|
||||
return;
|
||||
}
|
||||
} else
|
||||
classPrototype.instanceMembers = new Map();
|
||||
const instancePrototype = new FunctionPrototype(this, name, internalInstanceName, declaration, classPrototype);
|
||||
if (isGetter)
|
||||
(<Property>propertyElement).getterPrototype = instancePrototype;
|
||||
else
|
||||
(<Property>propertyElement).setterPrototype = instancePrototype;
|
||||
classPrototype.instanceMembers.set(name, propertyElement);
|
||||
}
|
||||
}
|
||||
|
||||
private initializeEnum(declaration: EnumDeclaration, namespace: Element | null = null): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const internalName = declaration.internalName;
|
||||
if (this.elements.has(internalName)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
|
||||
return;
|
||||
}
|
||||
const enm: Enum = new Enum(this, internalName, declaration);
|
||||
const enm = new Enum(this, internalName, declaration);
|
||||
this.elements.set(internalName, enm);
|
||||
|
||||
if (namespace) {
|
||||
@ -385,14 +452,14 @@ export class Program extends DiagnosticEmitter {
|
||||
this.exports.set(internalName, enm);
|
||||
}
|
||||
|
||||
const values: EnumValueDeclaration[] = declaration.values;
|
||||
const values = declaration.values;
|
||||
for (let i: i32 = 0, k: i32 = values.length; i < k; ++i)
|
||||
this.initializeEnumValue(values[i], enm);
|
||||
}
|
||||
|
||||
private initializeEnumValue(declaration: EnumValueDeclaration, enm: Enum): void {
|
||||
const name: string = declaration.name.name;
|
||||
const internalName: string = declaration.internalName;
|
||||
const name = declaration.name.name;
|
||||
const internalName = declaration.internalName;
|
||||
if (enm.members) {
|
||||
if (enm.members.has(name)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
|
||||
@ -400,13 +467,13 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
} else
|
||||
enm.members = new Map();
|
||||
const value: EnumValue = new EnumValue(enm, this, internalName, declaration);
|
||||
const value = new EnumValue(enm, this, internalName, declaration);
|
||||
enm.members.set(name, value);
|
||||
}
|
||||
|
||||
private initializeExports(statement: ExportStatement, queuedExports: Map<string,QueuedExport>): void {
|
||||
const members: ExportMember[] = statement.members;
|
||||
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i)
|
||||
const members = statement.members;
|
||||
for (let i = 0, k = members.length; i < k; ++i)
|
||||
this.initializeExport(members[i], statement.internalPath, queuedExports);
|
||||
}
|
||||
|
||||
@ -433,7 +500,7 @@ export class Program extends DiagnosticEmitter {
|
||||
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, member.externalIdentifier.range, externalName);
|
||||
return;
|
||||
}
|
||||
const queuedExport: QueuedExport = new QueuedExport();
|
||||
const queuedExport = new QueuedExport();
|
||||
queuedExport.isReExport = false;
|
||||
queuedExport.referencedName = referencedName; // -> internal name
|
||||
queuedExport.member = member;
|
||||
@ -450,9 +517,9 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
// walk already known queued exports
|
||||
const seen: Set<QueuedExport> = new Set();
|
||||
while (queuedExports.has(referencedName)) {
|
||||
const queuedExport: QueuedExport = <QueuedExport>queuedExports.get(referencedName);
|
||||
const seen = new Set<QueuedExport>();
|
||||
let queuedExport: QueuedExport | null;
|
||||
while (queuedExport = queuedExports.get(referencedName)) {
|
||||
if (queuedExport.isReExport) {
|
||||
if (this.exports.has(queuedExport.referencedName)) {
|
||||
this.exports.set(externalName, <Element>this.exports.get(referencedName));
|
||||
@ -476,7 +543,7 @@ export class Program extends DiagnosticEmitter {
|
||||
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, member.externalIdentifier.range, externalName);
|
||||
return;
|
||||
}
|
||||
const queuedReExport: QueuedExport = new QueuedExport();
|
||||
const queuedReExport = new QueuedExport();
|
||||
queuedReExport.isReExport = true;
|
||||
queuedReExport.referencedName = referencedName; // -> export name
|
||||
queuedReExport.member = member;
|
||||
@ -485,12 +552,12 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
private initializeFunction(declaration: FunctionDeclaration, namespace: Element | null = null): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const internalName = declaration.internalName;
|
||||
if (this.elements.has(internalName)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
|
||||
return;
|
||||
}
|
||||
const prototype: FunctionPrototype = new FunctionPrototype(this, declaration.name.name, internalName, declaration, null);
|
||||
const prototype = new FunctionPrototype(this, declaration.name.name, internalName, declaration, null);
|
||||
this.elements.set(internalName, prototype);
|
||||
|
||||
if (hasDecorator("global", declaration.decorators)) {
|
||||
@ -519,14 +586,12 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
private initializeImports(statement: ImportStatement, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
|
||||
const declarations: ImportDeclaration[] | null = statement.declarations;
|
||||
const declarations = statement.declarations;
|
||||
if (declarations) {
|
||||
for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i) {
|
||||
const declaration: ImportDeclaration = declarations[i];
|
||||
this.initializeImport(declaration, statement.internalPath, queuedExports, queuedImports);
|
||||
}
|
||||
for (let i = 0, k = declarations.length; i < k; ++i)
|
||||
this.initializeImport(declarations[i], statement.internalPath, queuedExports, queuedImports);
|
||||
} else if (statement.namespaceName) {
|
||||
const internalName: string = statement.range.source.internalPath + "/" + statement.namespaceName.name;
|
||||
const internalName = statement.range.source.internalPath + "/" + statement.namespaceName.name;
|
||||
if (this.elements.has(internalName)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, statement.namespaceName.range, internalName);
|
||||
return;
|
||||
@ -537,13 +602,13 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
private initializeImport(declaration: ImportDeclaration, internalPath: string, queuedExports: Map<string,QueuedExport>, queuedImports: QueuedImport[]): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const internalName = declaration.internalName;
|
||||
if (this.elements.has(internalName)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
|
||||
return;
|
||||
}
|
||||
|
||||
let referencedName: string = internalPath + PATH_DELIMITER + declaration.externalIdentifier.name;
|
||||
let referencedName = internalPath + PATH_DELIMITER + declaration.externalIdentifier.name;
|
||||
|
||||
// resolve right away if the export exists
|
||||
if (this.exports.has(referencedName)) {
|
||||
@ -552,9 +617,9 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
// walk already known queued exports
|
||||
const seen: Set<QueuedExport> = new Set();
|
||||
while (queuedExports.has(referencedName)) {
|
||||
const queuedExport: QueuedExport = <QueuedExport>queuedExports.get(referencedName);
|
||||
const seen = new Set<QueuedExport>();
|
||||
let queuedExport: QueuedExport | null;
|
||||
while (queuedExport = queuedExports.get(referencedName)) {
|
||||
if (queuedExport.isReExport) {
|
||||
if (this.exports.has(queuedExport.referencedName)) {
|
||||
this.elements.set(internalName, <Element>this.exports.get(referencedName));
|
||||
@ -574,7 +639,7 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
// otherwise queue it
|
||||
const queuedImport: QueuedImport = new QueuedImport();
|
||||
const queuedImport = new QueuedImport();
|
||||
queuedImport.internalName = internalName;
|
||||
queuedImport.referencedName = referencedName;
|
||||
queuedImport.declaration = declaration;
|
||||
@ -582,8 +647,8 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
private initializeInterface(declaration: InterfaceDeclaration, namespace: Element | null = null): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const prototype: InterfacePrototype = new InterfacePrototype(this, declaration.name.name, internalName, declaration);
|
||||
const internalName = declaration.internalName;
|
||||
const prototype = new InterfacePrototype(this, declaration.name.name, internalName, declaration);
|
||||
|
||||
if (this.elements.has(internalName)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
|
||||
@ -608,8 +673,8 @@ export class Program extends DiagnosticEmitter {
|
||||
this.exports.set(internalName, prototype);
|
||||
}
|
||||
|
||||
const memberDeclarations: DeclarationStatement[] = declaration.members;
|
||||
for (let i: i32 = 0, k: i32 = memberDeclarations.length; i < k; ++i) {
|
||||
const memberDeclarations = declaration.members;
|
||||
for (let i = 0, k = memberDeclarations.length; i < k; ++i) {
|
||||
switch (memberDeclarations[i].kind) {
|
||||
|
||||
case NodeKind.FIELD:
|
||||
@ -621,15 +686,15 @@ export class Program extends DiagnosticEmitter {
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("unexpected interface member");
|
||||
throw new Error("interface member expected");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private initializeNamespace(declaration: NamespaceDeclaration, parentNamespace: Element | null = null): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const internalName = declaration.internalName;
|
||||
|
||||
let namespace: Element | null = this.elements.get(internalName);
|
||||
let namespace = this.elements.get(internalName);
|
||||
if (!namespace) {
|
||||
namespace = new Namespace(this, internalName, declaration);
|
||||
this.elements.set(internalName, namespace);
|
||||
@ -652,8 +717,8 @@ export class Program extends DiagnosticEmitter {
|
||||
this.exports.set(internalName, namespace);
|
||||
}
|
||||
|
||||
const members: Statement[] = declaration.members;
|
||||
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i) {
|
||||
const members = declaration.members;
|
||||
for (let i = 0, k = members.length; i < k; ++i) {
|
||||
switch (members[i].kind) {
|
||||
|
||||
case NodeKind.CLASS:
|
||||
@ -692,7 +757,7 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
private initializeType(declaration: TypeDeclaration, namespace: Element | null = null): void {
|
||||
// type aliases are program globals
|
||||
const name: string = declaration.name.name;
|
||||
const name = declaration.name.name;
|
||||
if (this.types.has(name) || this.typeAliases.has(name)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, name);
|
||||
return;
|
||||
@ -701,16 +766,16 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
private initializeVariables(statement: VariableStatement, namespace: Element | null = null): void {
|
||||
const declarations: VariableDeclaration[] = statement.declarations;
|
||||
for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i) {
|
||||
const declaration: VariableDeclaration = declarations[i];
|
||||
const internalName: string = declaration.internalName;
|
||||
const declarations = statement.declarations;
|
||||
for (let i = 0, k = declarations.length; i < k; ++i) {
|
||||
const declaration = declarations[i];
|
||||
const internalName = declaration.internalName;
|
||||
if (this.elements.has(internalName)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, internalName);
|
||||
continue;
|
||||
}
|
||||
|
||||
const global: Global = new Global(this, internalName, declaration, null);
|
||||
const global = new Global(this, internalName, declaration, null);
|
||||
this.elements.set(internalName, global);
|
||||
|
||||
if (hasDecorator("global", declaration.decorators)) {
|
||||
@ -742,20 +807,20 @@ export class Program extends DiagnosticEmitter {
|
||||
resolveType(node: TypeNode, contextualTypeArguments: Map<string,Type> | null = null, reportNotFound: bool = true): Type | null {
|
||||
|
||||
// resolve parameters
|
||||
const k: i32 = node.typeArguments.length;
|
||||
const paramTypes: Type[] = new Array(k);
|
||||
for (let i: i32 = 0; i < k; ++i) {
|
||||
const paramType: Type | null = this.resolveType(node.typeArguments[i], contextualTypeArguments, reportNotFound);
|
||||
const k = node.typeArguments.length;
|
||||
const paramTypes = new Array<Type>(k);
|
||||
for (let i = 0; i < k; ++i) {
|
||||
const paramType = this.resolveType(node.typeArguments[i], contextualTypeArguments, reportNotFound);
|
||||
if (!paramType)
|
||||
return null;
|
||||
paramTypes[i] = <Type>paramType;
|
||||
paramTypes[i] = paramType;
|
||||
}
|
||||
|
||||
let globalName: string = node.identifier.name;
|
||||
let globalName = node.identifier.name;
|
||||
if (k) // can't be a placeholder if it has parameters
|
||||
globalName += typesToString(paramTypes);
|
||||
else if (contextualTypeArguments) {
|
||||
const placeholderType: Type | null = <Type | null>contextualTypeArguments.get(globalName);
|
||||
const placeholderType = contextualTypeArguments.get(globalName);
|
||||
if (placeholderType)
|
||||
return placeholderType;
|
||||
}
|
||||
@ -763,15 +828,15 @@ export class Program extends DiagnosticEmitter {
|
||||
let type: Type | null;
|
||||
|
||||
// check file-global type
|
||||
if (type = <Type | null>this.types.get(node.range.source.internalPath + PATH_DELIMITER + globalName))
|
||||
if (type = this.types.get(node.range.source.internalPath + PATH_DELIMITER + globalName))
|
||||
return type;
|
||||
|
||||
// check program-global type
|
||||
if (type = <Type | null>this.types.get(globalName))
|
||||
if (type = this.types.get(globalName))
|
||||
return type;
|
||||
|
||||
// check type alias
|
||||
let alias: TypeNode | null = <TypeNode | null>this.typeAliases.get(globalName);
|
||||
let alias = this.typeAliases.get(globalName);
|
||||
if (alias && (type = this.resolveType(alias, null, reportNotFound)))
|
||||
return type;
|
||||
|
||||
@ -783,8 +848,8 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
/** Resolves an array of type parameters to concrete types. */
|
||||
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;
|
||||
const parameterCount = typeParameters.length;
|
||||
const argumentCount = typeArgumentNodes ? typeArgumentNodes.length : 0;
|
||||
if (parameterCount != argumentCount) {
|
||||
if (argumentCount)
|
||||
this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, Range.join((<TypeNode[]>typeArgumentNodes)[0].range, (<TypeNode[]>typeArgumentNodes)[argumentCount - 1].range), parameterCount.toString(10), argumentCount.toString(10));
|
||||
@ -792,9 +857,9 @@ export class Program extends DiagnosticEmitter {
|
||||
this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, alternativeReportNode.range.atEnd, parameterCount.toString(10), "0");
|
||||
return null;
|
||||
}
|
||||
const typeArguments: Type[] = new Array(parameterCount);
|
||||
for (let i: i32 = 0; i < parameterCount; ++i) {
|
||||
const type: Type | null = this.resolveType((<TypeNode[]>typeArgumentNodes)[i], contextualTypeArguments, true); // reports
|
||||
const typeArguments = new Array<Type>(parameterCount);
|
||||
for (let i = 0; i < parameterCount; ++i) {
|
||||
const type = this.resolveType((<TypeNode[]>typeArgumentNodes)[i], contextualTypeArguments, true); // reports
|
||||
if (!type)
|
||||
return null;
|
||||
// TODO: check extendsType
|
||||
@ -805,8 +870,8 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
/** Resolves an identifier to the element is refers to. */
|
||||
resolveIdentifier(identifier: IdentifierExpression, contextualFunction: Function): Element | null {
|
||||
const name: string = identifier.name;
|
||||
const local: Local | null = <Local | null>contextualFunction.locals.get(name);
|
||||
const name = identifier.name;
|
||||
const local = contextualFunction.locals.get(name);
|
||||
if (local)
|
||||
return local;
|
||||
let element: Element | null;
|
||||
@ -820,7 +885,7 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
/** Resolves a property access the element it refers to. */
|
||||
resolvePropertyAccess(propertyAccess: PropertyAccessExpression, contextualFunction: Function): Element | null {
|
||||
const expression: Expression = propertyAccess.expression;
|
||||
const expression = propertyAccess.expression;
|
||||
let target: Element | null = null;
|
||||
if (expression.kind == NodeKind.IDENTIFIER) {
|
||||
target = this.resolveIdentifier(<IdentifierExpression>expression, contextualFunction);
|
||||
@ -830,9 +895,9 @@ export class Program extends DiagnosticEmitter {
|
||||
throw new Error("unexpected target kind");
|
||||
if (!target)
|
||||
return null;
|
||||
const propertyName: string = propertyAccess.property.name;
|
||||
const propertyName = propertyAccess.property.name;
|
||||
if (target.members) {
|
||||
const member: Element | null = target.members.get(propertyName);
|
||||
const member = target.members.get(propertyName);
|
||||
if (member)
|
||||
return member;
|
||||
}
|
||||
@ -869,11 +934,10 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
function hasDecorator(name: string, decorators: Decorator[] | null): bool {
|
||||
if (decorators)
|
||||
for (let i: i32 = 0, k: i32 = decorators.length; i < k; ++i) {
|
||||
const decorator: Decorator = decorators[i];
|
||||
const expression: Expression = decorator.name;
|
||||
const args: Expression[] = decorator.arguments;
|
||||
if (expression.kind == NodeKind.IDENTIFIER && args.length <= 1 && (<IdentifierExpression>expression).name == name)
|
||||
for (let i = 0, k = decorators.length; i < k; ++i) {
|
||||
const decorator = decorators[i];
|
||||
const expression = decorator.name;
|
||||
if (expression.kind == NodeKind.IDENTIFIER && decorator.arguments.length <= 1 && (<IdentifierExpression>expression).name == name)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -905,9 +969,7 @@ export enum ElementKind {
|
||||
FIELD_PROTOTYPE,
|
||||
/** A {@link Field}. */
|
||||
FIELD,
|
||||
/** A {@link PropertyPrototype}. */
|
||||
PROPERTY_PROTOTYPE,
|
||||
/** A {@link Property}. */
|
||||
/** A {@link PropertyContainer}. */
|
||||
PROPERTY,
|
||||
/** A {@link Namespace}. */
|
||||
NAMESPACE
|
||||
@ -1028,7 +1090,7 @@ export class Namespace extends Element {
|
||||
constructor(program: Program, internalName: string, declaration: NamespaceDeclaration | null = null) {
|
||||
super(program, internalName);
|
||||
if ((this.declaration = declaration) && this.declaration.modifiers) {
|
||||
for (let i: i32 = 0, k: i32 = this.declaration.modifiers.length; i < k; ++i) {
|
||||
for (let i = 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;
|
||||
@ -1052,7 +1114,7 @@ export class Enum extends Element {
|
||||
constructor(program: Program, internalName: string, declaration: EnumDeclaration | null = null) {
|
||||
super(program, internalName);
|
||||
if ((this.declaration = declaration) && this.declaration.modifiers) {
|
||||
for (let i: i32 = 0, k = this.declaration.modifiers.length; i < k; ++i) {
|
||||
for (let i = 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;
|
||||
@ -1102,7 +1164,7 @@ export class Global extends Element {
|
||||
super(program, internalName);
|
||||
if (this.declaration = declaration) {
|
||||
if (this.declaration.modifiers) {
|
||||
for (let i: i32 = 0, k = this.declaration.modifiers.length; i < k; ++i) {
|
||||
for (let i = 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;
|
||||
@ -1191,7 +1253,7 @@ export class FunctionPrototype extends Element {
|
||||
this.simpleName = simpleName;
|
||||
if (this.declaration = declaration) {
|
||||
if (this.declaration.modifiers)
|
||||
for (let i: i32 = 0, k: i32 = this.declaration.modifiers.length; i < k; ++i) {
|
||||
for (let i = 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;
|
||||
@ -1222,18 +1284,21 @@ export class FunctionPrototype extends Element {
|
||||
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, "", "");
|
||||
let instance: Function | null = <Function | null>this.instances.get(instanceKey);
|
||||
// Whether a getter/setter function or not.
|
||||
get isAccessor(): bool { return (this.flags & (ElementFlags.GETTER | ElementFlags.SETTER)) != 0; }
|
||||
|
||||
resolve(typeArguments: Type[] | null = null, contextualTypeArguments: Map<string,Type> | null = null): Function | null {
|
||||
const instanceKey = typeArguments ? typesToString(typeArguments, "", "") : "";
|
||||
let instance = this.instances.get(instanceKey);
|
||||
if (instance)
|
||||
return instance;
|
||||
const declaration: FunctionDeclaration | null = this.declaration;
|
||||
const declaration = this.declaration;
|
||||
if (!declaration)
|
||||
throw new Error("unexpected instantiation of internal function");
|
||||
throw new Error("declaration expected"); // cannot resolve built-ins
|
||||
|
||||
// override call specific contextual type arguments
|
||||
let i: i32, k: i32 = typeArguments.length;
|
||||
if (k) {
|
||||
let i: i32, k: i32;
|
||||
if (typeArguments && (k = typeArguments.length)) {
|
||||
const inheritedTypeArguments: Map<string,Type> | null = contextualTypeArguments;
|
||||
contextualTypeArguments = new Map();
|
||||
if (inheritedTypeArguments)
|
||||
@ -1245,15 +1310,15 @@ export class FunctionPrototype extends Element {
|
||||
|
||||
// resolve parameters
|
||||
k = declaration.parameters.length;
|
||||
const parameters: Parameter[] = new Array(k);
|
||||
const parameterTypes: Type[] = new Array(k);
|
||||
let typeNode: TypeNode | null ;
|
||||
const parameters = new Array<Parameter>(k);
|
||||
const parameterTypes = new Array<Type>(k);
|
||||
let typeNode: TypeNode | null;
|
||||
for (i = 0; i < k; ++i) {
|
||||
if (typeNode = declaration.parameters[i].type) {
|
||||
const type: Type | null = this.program.resolveType(<TypeNode>typeNode, contextualTypeArguments, true); // reports
|
||||
const type = this.program.resolveType(typeNode, contextualTypeArguments, true); // reports
|
||||
if (type) {
|
||||
parameters[i] = new Parameter(declaration.parameters[i].name.name, type);
|
||||
parameterTypes[i] = <Type>type;
|
||||
parameterTypes[i] = type;
|
||||
} else
|
||||
return null;
|
||||
} else
|
||||
@ -1262,16 +1327,20 @@ export class FunctionPrototype extends Element {
|
||||
|
||||
// resolve return type
|
||||
let returnType: Type;
|
||||
if (typeNode = declaration.returnType) {
|
||||
const type: Type | null = this.program.resolveType(<TypeNode>typeNode, contextualTypeArguments, true); // reports
|
||||
if (type)
|
||||
returnType = <Type>type;
|
||||
else
|
||||
if (this.isSetter) {
|
||||
returnType = Type.void; // not annotated
|
||||
} else {
|
||||
if (typeNode = declaration.returnType) {
|
||||
const type = this.program.resolveType(<TypeNode>typeNode, contextualTypeArguments, true); // reports
|
||||
if (type)
|
||||
returnType = type;
|
||||
else
|
||||
return null;
|
||||
} else
|
||||
return null;
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
let internalName: string = this.internalName;
|
||||
let internalName = this.internalName;
|
||||
if (instanceKey.length)
|
||||
internalName += "<" + instanceKey + ">";
|
||||
instance = new Function(this, internalName, typeArguments, parameters, returnType, null); // TODO: class
|
||||
@ -1284,7 +1353,7 @@ export class FunctionPrototype extends Element {
|
||||
if (this.isGeneric) {
|
||||
assert(typeArgumentNodes != null && typeArgumentNodes.length != 0);
|
||||
if (!this.declaration)
|
||||
throw new Error("missing declaration");
|
||||
throw new Error("declaration expected");
|
||||
resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode);
|
||||
if (!resolvedTypeArguments)
|
||||
return null;
|
||||
@ -1306,7 +1375,7 @@ export class Function extends Element {
|
||||
/** Prototype reference. */
|
||||
prototype: FunctionPrototype;
|
||||
/** Concrete type arguments. */
|
||||
typeArguments: Type[];
|
||||
typeArguments: Type[] | null;
|
||||
/** Concrete function parameters. Excluding `this` if an instance method. */
|
||||
parameters: Parameter[];
|
||||
/** Concrete return type. */
|
||||
@ -1326,7 +1395,7 @@ export class Function extends Element {
|
||||
private breakStack: i32[] | null = null;
|
||||
|
||||
/** Constructs a new concrete function. */
|
||||
constructor(prototype: FunctionPrototype, internalName: string, typeArguments: Type[], parameters: Parameter[], returnType: Type, instanceMethodOf: Class | null) {
|
||||
constructor(prototype: FunctionPrototype, internalName: string, typeArguments: Type[] | null, parameters: Parameter[], returnType: Type, instanceMethodOf: Class | null) {
|
||||
super(prototype.program, internalName);
|
||||
this.prototype = prototype;
|
||||
this.typeArguments = typeArguments;
|
||||
@ -1334,7 +1403,7 @@ export class Function extends Element {
|
||||
this.returnType = returnType;
|
||||
this.instanceMethodOf = instanceMethodOf;
|
||||
this.flags = prototype.flags;
|
||||
let localIndex: i32 = 0;
|
||||
let localIndex = 0;
|
||||
if (instanceMethodOf) {
|
||||
assert(this.isInstance);
|
||||
this.locals.set("this", new Local(prototype.program, "this", localIndex++, instanceMethodOf.type));
|
||||
@ -1345,8 +1414,8 @@ export class Function extends Element {
|
||||
}
|
||||
} else
|
||||
assert(!this.isInstance);
|
||||
for (let i: i32 = 0, k: i32 = parameters.length; i < k; ++i) {
|
||||
const parameter: Parameter = parameters[i];
|
||||
for (let i = 0, k = parameters.length; i < k; ++i) {
|
||||
const parameter = parameters[i];
|
||||
this.locals.set(parameter.name, new Local(prototype.program, parameter.name, localIndex++, parameter.type));
|
||||
}
|
||||
}
|
||||
@ -1356,11 +1425,11 @@ 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.prototype.program, name ? name : "anonymous$" + localIndex.toString(10), localIndex, type);
|
||||
const local = new Local(this.prototype.program, name ? name : "anonymous$" + localIndex.toString(10), localIndex, type);
|
||||
if (name) {
|
||||
if (this.locals.has(<string>name))
|
||||
if (this.locals.has(name))
|
||||
throw new Error("unexpected duplicate local name");
|
||||
this.locals.set(<string>name, local);
|
||||
this.locals.set(name, local);
|
||||
}
|
||||
this.additionalLocals.push(type);
|
||||
return local;
|
||||
@ -1418,7 +1487,7 @@ export class Function extends Element {
|
||||
|
||||
/** Enters a(nother) break context. */
|
||||
enterBreakContext(): string {
|
||||
const id: i32 = this.nextBreakId++;
|
||||
const id = this.nextBreakId++;
|
||||
if (!this.breakStack)
|
||||
this.breakStack = [ id ];
|
||||
else
|
||||
@ -1429,7 +1498,7 @@ export class Function extends Element {
|
||||
/** Leaves the current break context. */
|
||||
leaveBreakContext(): void {
|
||||
assert(this.breakStack != null);
|
||||
const length: i32 = (<i32[]>this.breakStack).length;
|
||||
const length = (<i32[]>this.breakStack).length;
|
||||
assert(length > 0);
|
||||
(<i32[]>this.breakStack).pop();
|
||||
if (length > 1) {
|
||||
@ -1470,7 +1539,7 @@ export class FieldPrototype extends Element {
|
||||
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) {
|
||||
for (let i = 0, k = this.declaration.modifiers.length; i < k; ++i) {
|
||||
switch (this.declaration.modifiers[i].modifierKind) {
|
||||
case ModifierKind.EXPORT: this.isExported = true; break;
|
||||
case ModifierKind.READONLY: this.isReadonly = true; break;
|
||||
@ -1511,73 +1580,25 @@ export class Field extends Element {
|
||||
}
|
||||
}
|
||||
|
||||
/** A yet unresolved property. */
|
||||
export class PropertyPrototype extends Element {
|
||||
|
||||
kind = ElementKind.PROPERTY_PROTOTYPE;
|
||||
|
||||
/** Simple name. */
|
||||
simpleName: string;
|
||||
/** Parent class prototype. */
|
||||
classPrototype: ClassPrototype;
|
||||
/** Getter declaration reference. */
|
||||
getterDeclaration: FunctionDeclaration | null;
|
||||
/** Setter declaration reference. */
|
||||
setterDeclaration: FunctionDeclaration | null;
|
||||
|
||||
/** Constructs a new propery prototype. */
|
||||
constructor(classPrototype: ClassPrototype, simpleName: string, internalName: string, getterDeclaration: FunctionDeclaration | null = null, setterDeclaration: FunctionDeclaration | null = null) {
|
||||
super(classPrototype.program, internalName);
|
||||
this.simpleName = simpleName;
|
||||
this.classPrototype = classPrototype;
|
||||
|
||||
let i: i32, k: i32;
|
||||
if ((this.getterDeclaration = getterDeclaration) && this.getterDeclaration.modifiers) {
|
||||
assert(this.getterDeclaration.typeParameters.length == 0);
|
||||
assert(this.getterDeclaration.parameters.length == 0);
|
||||
for (i = 0, k = this.getterDeclaration.modifiers.length; i < k; ++i) {
|
||||
switch (this.getterDeclaration.modifiers[i].modifierKind) {
|
||||
case ModifierKind.EXPORT: this.isExported = true; break;
|
||||
case ModifierKind.GET:
|
||||
case ModifierKind.STATIC: break; // already handled
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((this.setterDeclaration = setterDeclaration) && this.setterDeclaration.modifiers) {
|
||||
assert(this.setterDeclaration.typeParameters.length == 0);
|
||||
assert(this.setterDeclaration.parameters.length == 1);
|
||||
for (i = 0, k = this.setterDeclaration.modifiers.length; i < k; ++i) {
|
||||
switch (this.setterDeclaration.modifiers[i].modifierKind) {
|
||||
case ModifierKind.EXPORT: this.isExported = true; break;
|
||||
case ModifierKind.SET:
|
||||
case ModifierKind.STATIC: break; // already handled
|
||||
default: assert(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** A resolved property. */
|
||||
/** A property comprised of a getter and a setter function. */
|
||||
export class Property extends Element {
|
||||
|
||||
kind = ElementKind.PROPERTY;
|
||||
|
||||
/** Prototype reference. */
|
||||
prototype: PropertyPrototype;
|
||||
/** Property type. */
|
||||
type: Type;
|
||||
/** Getter function. */
|
||||
getter: Function | null = null;
|
||||
/** Setter function. */
|
||||
setter: Function | null = null;
|
||||
/** Simple name. */
|
||||
simpleName: string;
|
||||
/** Parent class prototype. */
|
||||
parent: ClassPrototype;
|
||||
/** Getter prototype. */
|
||||
getterPrototype: FunctionPrototype | null = null;
|
||||
/** Setter prototype. */
|
||||
setterPrototype: FunctionPrototype | null = null;
|
||||
|
||||
/** Constructs a new property. */
|
||||
constructor(prototype: PropertyPrototype, internalName: string, type: Type) {
|
||||
super(prototype.program, internalName);
|
||||
this.flags = prototype.flags;
|
||||
this.type = type;
|
||||
/** Constructs a new property prototype. */
|
||||
constructor(program: Program, simpleName: string, internalName: string, parent: ClassPrototype) {
|
||||
super(program, internalName);
|
||||
this.simpleName = simpleName;
|
||||
this.parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1600,7 +1621,7 @@ export class ClassPrototype extends Element {
|
||||
this.simpleName = simpleName;
|
||||
if (this.declaration = declaration) {
|
||||
if (this.declaration.modifiers) {
|
||||
for (let i: i32 = 0, k: i32 = this.declaration.modifiers.length; i < k; ++i) {
|
||||
for (let i = 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;
|
||||
@ -1615,16 +1636,16 @@ export class ClassPrototype extends Element {
|
||||
}
|
||||
|
||||
resolve(typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null): Class {
|
||||
const instanceKey: string = typesToString(typeArguments, "", "");
|
||||
let instance: Class | null = <Class | null>this.instances.get(instanceKey);
|
||||
const instanceKey = typesToString(typeArguments, "", "");
|
||||
let instance = this.instances.get(instanceKey);
|
||||
if (instance)
|
||||
return instance;
|
||||
const declaration: ClassDeclaration | null = this.declaration;
|
||||
const declaration = this.declaration;
|
||||
if (!declaration)
|
||||
throw new Error("unexpected instantiation of internal class");
|
||||
throw new Error("declaration expected"); // cannot resolve built-ins
|
||||
|
||||
// override call specific contextual type arguments
|
||||
let i: i32, k: i32 = typeArguments.length;
|
||||
let i: i32, k = typeArguments.length;
|
||||
if (k) {
|
||||
const inheritedTypeArguments: Map<string,Type> | null = contextualTypeArguments;
|
||||
contextualTypeArguments = new Map();
|
||||
@ -1645,7 +1666,7 @@ export class ClassPrototype extends Element {
|
||||
}
|
||||
}
|
||||
|
||||
let internalName: string = this.internalName;
|
||||
let internalName = this.internalName;
|
||||
if (instanceKey.length)
|
||||
internalName += "<" + instanceKey + ">";
|
||||
instance = new Class(this, internalName, typeArguments, null); // TODO: base class
|
||||
@ -1659,7 +1680,7 @@ export class ClassPrototype extends Element {
|
||||
if (this.isGeneric) {
|
||||
assert(typeArgumentNodes != null && typeArgumentNodes.length != 0);
|
||||
if (!this.declaration)
|
||||
throw new Error("missing declaration"); // generic built-in
|
||||
throw new Error("declaration expected"); // generic built-in
|
||||
resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode);
|
||||
if (!resolvedTypeArguments)
|
||||
return null;
|
||||
@ -1711,10 +1732,11 @@ export class Class extends Element {
|
||||
const typeParameters: TypeParameter[] = declaration.typeParameters;
|
||||
if (typeParameters.length != typeArguments.length)
|
||||
throw new Error("unexpected type argument count mismatch");
|
||||
const k: i32 = typeArguments.length;
|
||||
const k = typeArguments.length;
|
||||
if (k) {
|
||||
if (!this.contextualTypeArguments) this.contextualTypeArguments = new Map();
|
||||
for (let i: i32 = 0; i < k; ++i)
|
||||
if (!this.contextualTypeArguments)
|
||||
this.contextualTypeArguments = new Map();
|
||||
for (let i = 0; i < k; ++i)
|
||||
this.contextualTypeArguments.set(typeParameters[i].identifier.name, typeArguments[i]);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user