mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-06-19 01:41:30 +00:00
Type limits
This commit is contained in:
@ -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, ElementFlags, FunctionPrototype, Local } from "./program";
|
||||
import { Program, ElementFlags, Element, Global, FunctionPrototype, Local } from "./program";
|
||||
|
||||
/** Initializes the specified program with built-in functions. */
|
||||
export function initialize(program: Program): void {
|
||||
@ -35,14 +35,67 @@ export function initialize(program: Program): void {
|
||||
addFunction(program, "assert");
|
||||
addFunction(program, "parseInt");
|
||||
addFunction(program, "parseFloat");
|
||||
|
||||
addFunction(program, "i8").members = new Map([
|
||||
[ "MIN_VALUE", new Global(program, "i8.MIN_VALUE", null, Type.i8).withConstantIntegerValue(-128, -1) ],
|
||||
[ "MAX_VALUE", new Global(program, "i8.MAX_VALUE", null, Type.i8).withConstantIntegerValue(127, 0) ]
|
||||
]);
|
||||
addFunction(program, "i16").members = new Map([
|
||||
[ "MIN_VALUE", new Global(program, "i16.MIN_VALUE", null, Type.i16).withConstantIntegerValue(-32768, -1) ],
|
||||
[ "MAX_VALUE", new Global(program, "i16.MAX_VALUE", null, Type.i16).withConstantIntegerValue(32767, 0) ]
|
||||
]);
|
||||
addFunction(program, "i32").members = new Map([
|
||||
[ "MIN_VALUE", new Global(program, "i32.MIN_VALUE", null, Type.i32).withConstantIntegerValue(-2147483648, -1) ],
|
||||
[ "MAX_VALUE", new Global(program, "i32.MAX_VALUE", null, Type.i32).withConstantIntegerValue(2147483647, 0) ]
|
||||
]);
|
||||
addFunction(program, "i64").members = new Map([
|
||||
[ "MIN_VALUE", new Global(program, "i64.MIN_VALUE", null, Type.i64).withConstantIntegerValue(0, -2147483648) ],
|
||||
[ "MAX_VALUE", new Global(program, "i64.MAX_VALUE", null, Type.i64).withConstantIntegerValue(-1, 2147483647) ]
|
||||
]);
|
||||
addFunction(program, "u8").members = new Map([
|
||||
[ "MIN_VALUE", new Global(program, "u8.MIN_VALUE", null, Type.u8).withConstantIntegerValue(0, 0) ],
|
||||
[ "MAX_VALUE", new Global(program, "u8.MAX_VALUE", null, Type.u8).withConstantIntegerValue(255, 0) ]
|
||||
]);
|
||||
addFunction(program, "u16").members = new Map([
|
||||
[ "MIN_VALUE", new Global(program, "u16.MIN_VALUE", null, Type.u16).withConstantIntegerValue(0, 0) ],
|
||||
[ "MAX_VALUE", new Global(program, "u16.MAX_VALUE", null, Type.u16).withConstantIntegerValue(65535, 0) ]
|
||||
]);
|
||||
addFunction(program, "u32").members = new Map([
|
||||
[ "MIN_VALUE", new Global(program, "u32.MIN_VALUE", null, Type.u32).withConstantIntegerValue(0, 0) ],
|
||||
[ "MAX_VALUE", new Global(program, "u32.MAX_VALUE", null, Type.u32).withConstantIntegerValue(-1, 0) ]
|
||||
]);
|
||||
addFunction(program, "u64").members = new Map([
|
||||
[ "MIN_VALUE", new Global(program, "u64.MIN_VALUE", null, Type.u64).withConstantIntegerValue(0, 0) ],
|
||||
[ "MAX_VALUE", new Global(program, "u64.MAX_VALUE", null, Type.i64).withConstantIntegerValue(-1, -1) ]
|
||||
]);
|
||||
addFunction(program, "bool").members = new Map([
|
||||
[ "MIN_VALUE", new Global(program, "bool.MIN_VALUE", null, Type.bool).withConstantIntegerValue(0, 0) ],
|
||||
[ "MAX_VALUE", new Global(program, "bool.MAX_VALUE", null, Type.bool).withConstantIntegerValue(1, 0) ]
|
||||
]);
|
||||
addFunction(program, "f32").members = new Map([
|
||||
[ "MIN_SAFE_INTEGER", new Global(program, "f32.MIN_SAFE_INTEGER", null, Type.f32).withConstantFloatValue(-16777215) ],
|
||||
[ "MAX_SAFE_INTEGER", new Global(program, "f32.MAX_SAFE_INTEGER", null, Type.f32).withConstantFloatValue(16777215) ]
|
||||
]);
|
||||
addFunction(program, "f64").members = new Map([
|
||||
[ "MIN_SAFE_INTEGER", new Global(program, "f64.MIN_SAFE_INTEGER", null, Type.f64).withConstantFloatValue(-9007199254740991) ],
|
||||
[ "MAX_SAFE_INTEGER", new Global(program, "f64.MAX_SAFE_INTEGER", null, Type.f64).withConstantFloatValue(9007199254740991) ]
|
||||
]);
|
||||
if (program.target == Target.WASM64) {
|
||||
program.elements.set("isize", <Element>program.elements.get("i64"));
|
||||
program.elements.set("usize", <Element>program.elements.get("u64"));
|
||||
} else {
|
||||
program.elements.set("isize", <Element>program.elements.get("i32"));
|
||||
program.elements.set("usize", <Element>program.elements.get("u32"));
|
||||
}
|
||||
}
|
||||
|
||||
/** Adds a built-in function to the specified program. */
|
||||
function addFunction(program: Program, name: string, isGeneric: bool = false): void {
|
||||
let prototype: FunctionPrototype = new FunctionPrototype(program, name, null, null);
|
||||
function addFunction(program: Program, name: string, isGeneric: bool = false): FunctionPrototype {
|
||||
let prototype: FunctionPrototype = new FunctionPrototype(program, name, name, null, null);
|
||||
prototype.isBuiltIn = true;
|
||||
if (isGeneric) prototype.isGeneric = true;
|
||||
program.elements.set(name, prototype);
|
||||
return prototype;
|
||||
}
|
||||
|
||||
/** Compiles a call to a built-in function. */
|
||||
|
@ -93,7 +93,8 @@ import {
|
||||
UnaryPrefixExpression,
|
||||
|
||||
// utility
|
||||
hasModifier
|
||||
hasModifier,
|
||||
InterfaceDeclaration
|
||||
|
||||
} from "./ast";
|
||||
import {
|
||||
@ -179,7 +180,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
this.program = program;
|
||||
this.options = options ? options : new Options();
|
||||
this.module = this.options.noEmit ? Module.createStub() : Module.create();
|
||||
const startFunctionTemplate: FunctionPrototype = new FunctionPrototype(program, "start", null);
|
||||
const startFunctionTemplate: FunctionPrototype = new FunctionPrototype(program, "start", "start", null);
|
||||
const startFunctionInstance: Function = new Function(startFunctionTemplate, startFunctionTemplate.internalName, [], [], Type.void, null);
|
||||
this.currentFunction = this.startFunction = startFunctionInstance;
|
||||
this.memoryOffset = new U64(this.options.target == Target.WASM64 ? 8 : 4, 0); // leave space for `null`
|
||||
@ -544,6 +545,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
} else {
|
||||
this.module.addFunction(internalName, typeRef, typesToNativeTypes(instance.additionalLocals), this.module.createBlock(null, <ExpressionRef[]>stmts, NativeType.None));
|
||||
}
|
||||
instance.finalize();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -561,6 +563,11 @@ export class Compiler extends DiagnosticEmitter {
|
||||
this.compileClassDeclaration(<ClassDeclaration>member, []);
|
||||
break;
|
||||
|
||||
case NodeKind.INTERFACE:
|
||||
if ((noTreeShaking || hasModifier(ModifierKind.EXPORT, (<InterfaceDeclaration>member).modifiers)) && !(<InterfaceDeclaration>member).typeParameters.length)
|
||||
this.compileInterfaceDeclaration(<InterfaceDeclaration>member, []);
|
||||
break;
|
||||
|
||||
case NodeKind.ENUM:
|
||||
if (noTreeShaking || hasModifier(ModifierKind.EXPORT, (<EnumDeclaration>member).modifiers))
|
||||
this.compileEnumDeclaration(<EnumDeclaration>member);
|
||||
@ -684,6 +691,10 @@ export class Compiler extends DiagnosticEmitter {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
compileInterfaceDeclaration(declaration: InterfaceDeclaration, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): void {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
// memory
|
||||
|
||||
/** Adds a static memory segment with the specified data. */
|
||||
@ -1896,30 +1907,6 @@ export class Compiler extends DiagnosticEmitter {
|
||||
let expr: ExpressionRef;
|
||||
switch (target.kind) {
|
||||
|
||||
case ElementKind.ENUM:
|
||||
case ElementKind.CLASS_PROTOTYPE:
|
||||
case ElementKind.CLASS:
|
||||
case ElementKind.NAMESPACE:
|
||||
if (target.members) {
|
||||
element = target.members.get(propertyName);
|
||||
if (!element) {
|
||||
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName);
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
|
||||
// handle enum values right away
|
||||
if (element.kind == ElementKind.ENUMVALUE) {
|
||||
this.currentType = Type.i32;
|
||||
return (<EnumValue>element).hasConstantValue
|
||||
? this.module.createI32((<EnumValue>element).constantValue)
|
||||
: this.module.createGetGlobal((<EnumValue>element).internalName, NativeType.I32);
|
||||
}
|
||||
} else {
|
||||
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName);
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
break;
|
||||
|
||||
case ElementKind.LOCAL:
|
||||
element = (<Local>target).type.classType;
|
||||
if (!element) {
|
||||
@ -1941,7 +1928,25 @@ export class Compiler extends DiagnosticEmitter {
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("unexpected target kind");
|
||||
if (target.members) {
|
||||
element = target.members.get(propertyName);
|
||||
if (!element) {
|
||||
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName);
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
|
||||
// handle enum values right away
|
||||
if (element.kind == ElementKind.ENUMVALUE) {
|
||||
this.currentType = Type.i32;
|
||||
return (<EnumValue>element).hasConstantValue
|
||||
? this.module.createI32((<EnumValue>element).constantValue)
|
||||
: this.module.createGetGlobal((<EnumValue>element).internalName, NativeType.I32);
|
||||
}
|
||||
} else {
|
||||
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, propertyAccess.property.range, propertyName);
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// handle the element
|
||||
@ -1951,8 +1956,18 @@ export class Compiler extends DiagnosticEmitter {
|
||||
return this.module.createGetLocal((<Local>element).index, typeToNativeType(this.currentType = (<Local>element).type));
|
||||
|
||||
case ElementKind.GLOBAL:
|
||||
this.compileGlobal(<Global>element);
|
||||
return this.module.createGetGlobal((<Global>element).internalName, typeToNativeType(this.currentType = <Type>(<Global>element).type));
|
||||
if (!this.compileGlobal(<Global>element))
|
||||
return this.module.createUnreachable();
|
||||
this.currentType = <Type>(<Global>element).type;
|
||||
if ((<Global>element).hasConstantValue)
|
||||
return this.currentType== Type.f32
|
||||
? this.module.createF32((<Global>element).constantFloatValue)
|
||||
: this.currentType == Type.f64
|
||||
? this.module.createF64((<Global>element).constantFloatValue)
|
||||
: this.currentType.isLongInteger
|
||||
? this.module.createI64((<I64>(<Global>element).constantIntegerValue).lo, (<I64>(<Global>element).constantIntegerValue).hi)
|
||||
: this.module.createI32((<I64>(<Global>element).constantIntegerValue).lo);
|
||||
return this.module.createGetGlobal((<Global>element).internalName, typeToNativeType(this.currentType));
|
||||
|
||||
case ElementKind.FUNCTION: // getter
|
||||
if (!(<Function>element).prototype.isGetter) {
|
||||
|
@ -47,7 +47,6 @@ export class Decompiler {
|
||||
this.push("(");
|
||||
let k: Index = _BinaryenFunctionGetNumParams(func);
|
||||
for (let i: Index = 0; i < k; ++i) {
|
||||
console.log("rat");
|
||||
if (i > 0)
|
||||
this.push(", ");
|
||||
this.push("$");
|
||||
|
148
src/program.ts
148
src/program.ts
@ -216,7 +216,7 @@ export class Program extends DiagnosticEmitter {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
return;
|
||||
}
|
||||
const prototype: ClassPrototype = new ClassPrototype(this, internalName, declaration);
|
||||
const prototype: ClassPrototype = new ClassPrototype(this, declaration.identifier.name, internalName, declaration);
|
||||
this.elements.set(internalName, prototype);
|
||||
|
||||
if (namespace) {
|
||||
@ -306,7 +306,7 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
} else
|
||||
classPrototype.members = new Map();
|
||||
const staticPrototype: FunctionPrototype = new FunctionPrototype(this, internalName, declaration, null);
|
||||
const staticPrototype: FunctionPrototype = new FunctionPrototype(this, name, internalName, declaration, null);
|
||||
classPrototype.members.set(name, staticPrototype);
|
||||
this.elements.set(internalName, staticPrototype);
|
||||
|
||||
@ -319,7 +319,7 @@ export class Program extends DiagnosticEmitter {
|
||||
}
|
||||
} else
|
||||
classPrototype.instanceMembers = new Map();
|
||||
const instancePrototype: FunctionPrototype = new FunctionPrototype(this, internalName, declaration, classPrototype);
|
||||
const instancePrototype: FunctionPrototype = new FunctionPrototype(this, name, internalName, declaration, classPrototype);
|
||||
classPrototype.instanceMembers.set(name, instancePrototype);
|
||||
}
|
||||
}
|
||||
@ -455,7 +455,7 @@ export class Program extends DiagnosticEmitter {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
return;
|
||||
}
|
||||
const prototype: FunctionPrototype = new FunctionPrototype(this, internalName, declaration, null);
|
||||
const prototype: FunctionPrototype = new FunctionPrototype(this, declaration.identifier.name, internalName, declaration, null);
|
||||
this.elements.set(internalName, prototype);
|
||||
|
||||
if (namespace) {
|
||||
@ -531,7 +531,7 @@ 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, internalName, declaration);
|
||||
const prototype: InterfacePrototype = new InterfacePrototype(this, declaration.identifier.name, internalName, declaration);
|
||||
|
||||
if (this.elements.has(internalName)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
@ -1024,6 +1024,18 @@ export class Global extends Element {
|
||||
}
|
||||
this.type = type; // resolved later if `null`
|
||||
}
|
||||
|
||||
withConstantIntegerValue(lo: i32, hi: i32): this {
|
||||
this.constantIntegerValue = new I64(lo, hi);
|
||||
this.hasConstantValue = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
withConstantFloatValue(value: f64): this {
|
||||
this.constantFloatValue = value;
|
||||
this.hasConstantValue = true;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
/** A function parameter. */
|
||||
@ -1070,14 +1082,17 @@ export class FunctionPrototype extends Element {
|
||||
|
||||
/** Declaration reference. */
|
||||
declaration: FunctionDeclaration | null;
|
||||
/** Class prototype reference. */
|
||||
/** If an instance method, the class prototype reference. */
|
||||
classPrototype: ClassPrototype | null;
|
||||
/** Resolved instances. */
|
||||
instances: Map<string,Function> = new Map();
|
||||
/** Simple name. */
|
||||
simpleName: string;
|
||||
|
||||
/** Constructs a new function prototype. */
|
||||
constructor(program: Program, internalName: string, declaration: FunctionDeclaration | null, classPrototype: ClassPrototype | null = null) {
|
||||
constructor(program: Program, simpleName: string, internalName: string, declaration: FunctionDeclaration | null, classPrototype: ClassPrototype | null = null) {
|
||||
super(program, internalName);
|
||||
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) {
|
||||
@ -1142,7 +1157,7 @@ export class FunctionPrototype extends Element {
|
||||
} else
|
||||
return null;
|
||||
} else
|
||||
return null; // TODO: infer type? (currently reported by parser)
|
||||
return null;
|
||||
}
|
||||
|
||||
// resolve return type
|
||||
@ -1155,7 +1170,7 @@ export class FunctionPrototype extends Element {
|
||||
else
|
||||
return null;
|
||||
} else
|
||||
return null; // TODO: infer type? (currently reported by parser)
|
||||
return null;
|
||||
|
||||
let internalName: string = this.internalName;
|
||||
if (instanceKey.length)
|
||||
@ -1168,17 +1183,20 @@ export class FunctionPrototype extends Element {
|
||||
resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null, alternativeReportNode: Node | null): Function | null {
|
||||
let resolvedTypeArguments: Type[] | null;
|
||||
if (this.isGeneric) {
|
||||
assert(typeArgumentNodes != null && typeArgumentNodes.length != 0);
|
||||
if (!this.declaration)
|
||||
throw new Error("missing declaration");
|
||||
resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode);
|
||||
if (!resolvedTypeArguments)
|
||||
return null;
|
||||
} else {
|
||||
// TODO: check typeArgumentNodes being empty
|
||||
assert(typeArgumentNodes == null || typeArgumentNodes.length == 0);
|
||||
resolvedTypeArguments = [];
|
||||
}
|
||||
return this.resolve(resolvedTypeArguments, contextualTypeArguments);
|
||||
}
|
||||
|
||||
toString(): string { return this.simpleName; }
|
||||
}
|
||||
|
||||
/** A resolved function. */
|
||||
@ -1194,7 +1212,7 @@ export class Function extends Element {
|
||||
parameters: Parameter[];
|
||||
/** Concrete return type. */
|
||||
returnType: Type;
|
||||
/** If a method, the concrete class it is a member of. */
|
||||
/** If an instance method, the concrete class it is a member of. */
|
||||
instanceMethodOf: Class | null;
|
||||
/** Map of locals by name. */
|
||||
locals: Map<string,Local> = new Map();
|
||||
@ -1203,7 +1221,7 @@ export class Function extends Element {
|
||||
/** Current break context label. */
|
||||
breakContext: string | null = null;
|
||||
/** Contextual type arguments. */
|
||||
contextualTypeArguments: Map<string,Type> = new Map();
|
||||
contextualTypeArguments: Map<string,Type> | null;
|
||||
|
||||
private nextBreakId: i32 = 0;
|
||||
private breakStack: i32[] | null = null;
|
||||
@ -1219,19 +1237,21 @@ export class Function extends Element {
|
||||
this.flags = prototype.flags;
|
||||
let localIndex: i32 = 0;
|
||||
if (instanceMethodOf) {
|
||||
assert(this.isInstance);
|
||||
this.locals.set("this", new Local(prototype.program, "this", localIndex++, instanceMethodOf.type));
|
||||
for (let [name, type] of instanceMethodOf.contextualTypeArguments)
|
||||
this.contextualTypeArguments.set(name, type);
|
||||
}
|
||||
if (instanceMethodOf.contextualTypeArguments) {
|
||||
if (!this.contextualTypeArguments) this.contextualTypeArguments = new Map();
|
||||
for (let [name, type] of instanceMethodOf.contextualTypeArguments)
|
||||
this.contextualTypeArguments.set(name, type);
|
||||
}
|
||||
} else
|
||||
assert(!this.isInstance);
|
||||
for (let i: i32 = 0, k: i32 = parameters.length; i < k; ++i) {
|
||||
const parameter: Parameter = parameters[i];
|
||||
this.locals.set(parameter.name, new Local(prototype.program, parameter.name, localIndex++, parameter.type));
|
||||
}
|
||||
}
|
||||
|
||||
/** Tests if this function is an instance method. */
|
||||
get isInstance(): bool { return this.instanceMethodOf != null; }
|
||||
|
||||
/** Adds a local of the specified type, with an optional name. */
|
||||
addLocal(type: Type, name: string | null = null): Local {
|
||||
// if it has a name, check previously as this method will throw otherwise
|
||||
@ -1320,6 +1340,16 @@ export class Function extends Element {
|
||||
this.breakStack = null;
|
||||
}
|
||||
}
|
||||
|
||||
/** Finalizes the function once compiled, releasing no longer needed resources. */
|
||||
finalize(): void {
|
||||
assert(!this.breakStack || !this.breakStack.length, "break stack is not empty");
|
||||
this.breakStack = null;
|
||||
this.breakContext = null;
|
||||
this.tempI32s = this.tempI64s = this.tempF32s = this.tempF64s = null;
|
||||
}
|
||||
|
||||
toString(): string { return this.prototype.simpleName; }
|
||||
}
|
||||
|
||||
/** A yet unresolved instance field prototype. */
|
||||
@ -1380,9 +1410,12 @@ export class ClassPrototype extends Element {
|
||||
instances: Map<string,Class> = new Map();
|
||||
/** Instance member prototypes. */
|
||||
instanceMembers: Map<string,Element> | null = null;
|
||||
/** Simple name. */
|
||||
simpleName: string;
|
||||
|
||||
constructor(program: Program, internalName: string, declaration: ClassDeclaration | null = null) {
|
||||
constructor(program: Program, simpleName: string, internalName: string, declaration: ClassDeclaration | null = null) {
|
||||
super(program, internalName);
|
||||
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) {
|
||||
@ -1400,29 +1433,62 @@ export class ClassPrototype extends Element {
|
||||
}
|
||||
|
||||
resolve(typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null): Class {
|
||||
const key: string = typesToString(typeArguments, "", "");
|
||||
let instance: Class | null = <Class | null>this.instances.get(key);
|
||||
const instanceKey: string = typesToString(typeArguments, "", "");
|
||||
let instance: Class | null = <Class | null>this.instances.get(instanceKey);
|
||||
if (instance)
|
||||
return instance;
|
||||
if (!this.declaration)
|
||||
const declaration: ClassDeclaration | null = this.declaration;
|
||||
if (!declaration)
|
||||
throw new Error("unexpected instantiation of internal class");
|
||||
throw new Error("not implemented");
|
||||
|
||||
// override call specific contextual type arguments
|
||||
let i: i32, k: i32 = typeArguments.length;
|
||||
if (k) {
|
||||
const inheritedTypeArguments: Map<string,Type> | null = contextualTypeArguments;
|
||||
contextualTypeArguments = new Map();
|
||||
if (inheritedTypeArguments)
|
||||
for (let [name, type] of inheritedTypeArguments)
|
||||
contextualTypeArguments.set(name, type);
|
||||
for (i = 0; i < k; ++i)
|
||||
contextualTypeArguments.set(declaration.typeParameters[i].identifier.name, typeArguments[i]);
|
||||
}
|
||||
|
||||
// TODO: set up instance fields and methods
|
||||
if (this.instanceMembers)
|
||||
for (let [key, member] of this.instanceMembers) {
|
||||
switch (member.kind) {
|
||||
case ElementKind.FIELD_PROTOTYPE: break;
|
||||
case ElementKind.FUNCTION_PROTOTYPE: break;
|
||||
default: throw new Error("unexpected instance member");
|
||||
}
|
||||
}
|
||||
|
||||
let internalName: string = this.internalName;
|
||||
if (instanceKey.length)
|
||||
internalName += "<" + instanceKey + ">";
|
||||
instance = new Class(this, internalName, typeArguments, null); // TODO: base class
|
||||
instance.contextualTypeArguments = contextualTypeArguments;
|
||||
this.instances.set(instanceKey, instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null, alternativeReportNode: Node | null): Class | null {
|
||||
let resolvedTypeArguments: Type[] | null;
|
||||
if (this.isGeneric) {
|
||||
assert(typeArgumentNodes != null && typeArgumentNodes.length != 0);
|
||||
if (!this.declaration)
|
||||
throw new Error("not implemented"); // generic built-in
|
||||
throw new Error("missing declaration"); // generic built-in
|
||||
resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode);
|
||||
if (!resolvedTypeArguments)
|
||||
return null;
|
||||
} else {
|
||||
// TODO: check typeArgumentNodes being empty
|
||||
assert(typeArgumentNodes == null || !typeArgumentNodes.length);
|
||||
resolvedTypeArguments = [];
|
||||
}
|
||||
return this.resolve(resolvedTypeArguments, contextualTypeArguments);
|
||||
}
|
||||
|
||||
toString(): string { return this.simpleName; }
|
||||
}
|
||||
|
||||
/** A resolved class. */
|
||||
@ -1438,16 +1504,8 @@ export class Class extends Element {
|
||||
type: Type;
|
||||
/** Base class, if applicable. */
|
||||
base: Class | null;
|
||||
/** Contextual type argumentsfor fields and methods. */
|
||||
contextualTypeArguments: Map<string,Type> = new Map();
|
||||
/** Instance fields. */
|
||||
instanceFields: Map<string,Field> | null = null;
|
||||
/** Instance methods. */
|
||||
instanceMethods: Map<string,Function> | null = null;
|
||||
/** Instance getters. */
|
||||
instanceGetters: Map<string,Function> | null = null;
|
||||
/** Instance setters. */
|
||||
instanceSetters: Map<string,Function> | null = null;
|
||||
/** Contextual type arguments for fields and methods. */
|
||||
contextualTypeArguments: Map<string,Type> | null = null;
|
||||
|
||||
/** Constructs a new class. */
|
||||
constructor(prototype: ClassPrototype, internalName: string, typeArguments: Type[] = [], base: Class | null = null) {
|
||||
@ -1459,9 +1517,11 @@ export class Class extends Element {
|
||||
this.base = base;
|
||||
|
||||
// inherit contextual type arguments from base class
|
||||
if (base)
|
||||
if (base && base.contextualTypeArguments) {
|
||||
if (!this.contextualTypeArguments) this.contextualTypeArguments = new Map();
|
||||
for (let [name, type] of base.contextualTypeArguments)
|
||||
this.contextualTypeArguments.set(name, type);
|
||||
}
|
||||
|
||||
// apply instance-specific contextual type arguments
|
||||
const declaration: ClassDeclaration | null = this.prototype.declaration;
|
||||
@ -1469,14 +1529,16 @@ export class Class extends Element {
|
||||
const typeParameters: TypeParameter[] = declaration.typeParameters;
|
||||
if (typeParameters.length != typeArguments.length)
|
||||
throw new Error("unexpected type argument count mismatch");
|
||||
for (let i: i32 = 0, k: i32 = typeArguments.length; i < k; ++i)
|
||||
this.contextualTypeArguments.set(typeParameters[i].identifier.name, typeArguments[i]);
|
||||
const k: i32 = typeArguments.length;
|
||||
if (k) {
|
||||
if (!this.contextualTypeArguments) this.contextualTypeArguments = new Map();
|
||||
for (let i: i32 = 0; i < k; ++i)
|
||||
this.contextualTypeArguments.set(typeParameters[i].identifier.name, typeArguments[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toString(): string {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
toString(): string { return this.prototype.simpleName; }
|
||||
}
|
||||
|
||||
/** A yet unresolved interface. */
|
||||
@ -1488,8 +1550,8 @@ export class InterfacePrototype extends ClassPrototype {
|
||||
declaration: InterfaceDeclaration | null; // more specific
|
||||
|
||||
/** Constructs a new interface prototype. */
|
||||
constructor(program: Program, internalName: string, declaration: InterfaceDeclaration | null = null) {
|
||||
super(program, internalName, declaration);
|
||||
constructor(program: Program, simpleName: string, internalName: string, declaration: InterfaceDeclaration | null = null) {
|
||||
super(program, simpleName, internalName, declaration);
|
||||
}
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user