mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-25 07:02:13 +00:00
Progress
This commit is contained in:
parent
d1c1178f25
commit
d3d4938b68
6
package-lock.json
generated
6
package-lock.json
generated
@ -41,9 +41,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"binaryen": {
|
||||
"version": "37.0.0-nightly.20170912",
|
||||
"resolved": "https://registry.npmjs.org/binaryen/-/binaryen-37.0.0-nightly.20170912.tgz",
|
||||
"integrity": "sha512-yXLgHkUvTMqEV1vkixAaldnS4w6WOrqY+30Cx9k+JjBzmA6wJTQr0F32xFg/4MPr4NRZOdP/AnI8ais4nhfgIw=="
|
||||
"version": "39.0.0-nightly.20171116",
|
||||
"resolved": "https://registry.npmjs.org/binaryen/-/binaryen-39.0.0-nightly.20171116.tgz",
|
||||
"integrity": "sha512-ljl/qPne0+8hYtNWITRSAtxNM1EG5NnvTg+HRmSUdNAK2j9wcyAAg5uVj+TgipEqY82kmHt5C9+TSQNEwaxgrw=="
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.1.0",
|
||||
|
@ -12,6 +12,10 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": "^8.0.28",
|
||||
"binaryen": "37.0.0-nightly.20170912"
|
||||
"binaryen": "39.0.0-nightly.20171116"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc -P src",
|
||||
"test:compiler": "ts-node -P src tests/compiler"
|
||||
}
|
||||
}
|
||||
|
@ -1091,7 +1091,7 @@ export class Source extends Node {
|
||||
tokenizer: Tokenizer | null = null;
|
||||
isEntry: bool;
|
||||
|
||||
constructor(path: string, text: string, isEntry: bool) {
|
||||
constructor(path: string, text: string, isEntry: bool = false) {
|
||||
super();
|
||||
this.path = path;
|
||||
this.normalizedPath = normalizePath(path, true);
|
||||
@ -1392,6 +1392,7 @@ export class ExpressionStatement extends Statement {
|
||||
|
||||
serialize(sb: string[]): void {
|
||||
this.expression.serialize(sb);
|
||||
sb.push(";");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1773,6 +1774,7 @@ export class ThrowStatement extends Statement {
|
||||
serialize(sb: string[]): void {
|
||||
sb.push("throw ");
|
||||
this.expression.serialize(sb);
|
||||
sb.push(";");
|
||||
}
|
||||
}
|
||||
|
||||
@ -1895,10 +1897,11 @@ export function serialize(node: Node, indent: i32 = 0): string {
|
||||
}
|
||||
|
||||
export function mangleInternalPath(path: string): string {
|
||||
if (PATH_DELIMITER.charCodeAt(0) != CharCode.SLASH)
|
||||
// TODO: not necessary with current config
|
||||
/* if (PATH_DELIMITER.charCodeAt(0) != CharCode.SLASH)
|
||||
path = path.replace("/", PATH_DELIMITER);
|
||||
if (PARENT_SUBST != "..")
|
||||
path = path.replace("..", PARENT_SUBST);
|
||||
path = path.replace("..", PARENT_SUBST); */
|
||||
return path;
|
||||
}
|
||||
|
||||
|
74
src/binaryen.d.ts
vendored
74
src/binaryen.d.ts
vendored
@ -15,7 +15,7 @@ declare function _free(ptr: usize): void;
|
||||
|
||||
declare type BinaryenIndex = u32;
|
||||
|
||||
declare type BinaryenType = u32;
|
||||
declare type BinaryenType = i32;
|
||||
|
||||
declare function _BinaryenNone(): BinaryenType;
|
||||
declare function _BinaryenInt32(): BinaryenType;
|
||||
@ -24,6 +24,37 @@ declare function _BinaryenFloat32(): BinaryenType;
|
||||
declare function _BinaryenFloat64(): BinaryenType;
|
||||
declare function _BinaryenUndefined(): BinaryenType;
|
||||
|
||||
declare type BinaryenExpressionId = i32;
|
||||
|
||||
declare function _BinaryenInvalidId(): BinaryenExpressionId;
|
||||
declare function _BinaryenBlockId(): BinaryenExpressionId;
|
||||
declare function _BinaryenIfId(): BinaryenExpressionId;
|
||||
declare function _BinaryenLoopId(): BinaryenExpressionId;
|
||||
declare function _BinaryenBreakId(): BinaryenExpressionId;
|
||||
declare function _BinaryenSwitchId(): BinaryenExpressionId;
|
||||
declare function _BinaryenCallId(): BinaryenExpressionId;
|
||||
declare function _BinaryenCallImportId(): BinaryenExpressionId;
|
||||
declare function _BinaryenCallIndirectId(): BinaryenExpressionId;
|
||||
declare function _BinaryenGetLocalId(): BinaryenExpressionId;
|
||||
declare function _BinaryenSetLocalId(): BinaryenExpressionId;
|
||||
declare function _BinaryenGetGlobalId(): BinaryenExpressionId;
|
||||
declare function _BinaryenSetGlobalId(): BinaryenExpressionId;
|
||||
declare function _BinaryenLoadId(): BinaryenExpressionId;
|
||||
declare function _BinaryenStoreId(): BinaryenExpressionId;
|
||||
declare function _BinaryenConstId(): BinaryenExpressionId;
|
||||
declare function _BinaryenUnaryId(): BinaryenExpressionId;
|
||||
declare function _BinaryenBinaryId(): BinaryenExpressionId;
|
||||
declare function _BinaryenSelectId(): BinaryenExpressionId;
|
||||
declare function _BinaryenDropId(): BinaryenExpressionId;
|
||||
declare function _BinaryenReturnId(): BinaryenExpressionId;
|
||||
declare function _BinaryenHostId(): BinaryenExpressionId;
|
||||
declare function _BinaryenNopId(): BinaryenExpressionId;
|
||||
declare function _BinaryenUnreachableId(): BinaryenExpressionId;
|
||||
declare function _BinaryenAtomicCmpxchgId(): BinaryenExpressionId;
|
||||
declare function _BinaryenAtomicRMWId(): BinaryenExpressionId;
|
||||
declare function _BinaryenAtomicWaitId(): BinaryenExpressionId;
|
||||
declare function _BinaryenAtomicWakeId(): BinaryenExpressionId;
|
||||
|
||||
declare type BinaryenModuleRef = usize;
|
||||
|
||||
declare function _BinaryenModuleCreate(): BinaryenModuleRef;
|
||||
@ -34,10 +65,11 @@ declare type CString = usize;
|
||||
declare type CArray<T> = usize;
|
||||
|
||||
declare function _BinaryenAddFunctionType(module: BinaryenModuleRef, name: CString, result: BinaryenType, paramTypes: CArray<BinaryenType>, numParams: BinaryenIndex): BinaryenFunctionTypeRef;
|
||||
declare function _BinaryenGetFunctionTypeBySignature(module: BinaryenModuleRef, result: BinaryenType, paramTypes: CArray<BinaryenType>, numParams: BinaryenIndex): BinaryenFunctionTypeRef;
|
||||
|
||||
declare type BinaryenLiteral = CArray<u8>;
|
||||
|
||||
// LLVM C ABI with `out` being a buffer of 16 bytes receiving the BinaryenLiteral struct
|
||||
// LLVM C ABI with `out` being a buffer of 16 bytes receiving the BinaryenLiteral struct.
|
||||
// union value starts at offset 8 due to alignment (?)
|
||||
declare function _BinaryenLiteralInt32(out: BinaryenLiteral, x: i32): void;
|
||||
declare function _BinaryenLiteralInt64(out: BinaryenLiteral, x: i32, y: i32): void;
|
||||
@ -171,10 +203,22 @@ declare function _BinaryenLtFloat64(): BinaryenOp;
|
||||
declare function _BinaryenLeFloat64(): BinaryenOp;
|
||||
declare function _BinaryenGtFloat64(): BinaryenOp;
|
||||
declare function _BinaryenGeFloat64(): BinaryenOp;
|
||||
declare function _BinaryenPageSize(): BinaryenOp;
|
||||
declare function _BinaryenCurrentMemory(): BinaryenOp;
|
||||
declare function _BinaryenGrowMemory(): BinaryenOp;
|
||||
declare function _BinaryenHasFeature(): BinaryenOp;
|
||||
|
||||
declare type BinaryenHostOp = BinaryenOp;
|
||||
|
||||
declare function _BinaryenPageSize(): BinaryenHostOp;
|
||||
declare function _BinaryenCurrentMemory(): BinaryenHostOp;
|
||||
declare function _BinaryenGrowMemory(): BinaryenHostOp;
|
||||
declare function _BinaryenHasFeature(): BinaryenHostOp;
|
||||
|
||||
declare type BinaryenAtomicRMWOp = BinaryenOp;
|
||||
|
||||
declare function _BinaryenAtomicRMWAdd(): BinaryenAtomicRMWOp;
|
||||
declare function _BinaryenAtomicRMWSub(): BinaryenAtomicRMWOp;
|
||||
declare function _BinaryenAtomicRMWAnd(): BinaryenAtomicRMWOp;
|
||||
declare function _BinaryenAtomicRMWOr(): BinaryenAtomicRMWOp;
|
||||
declare function _BinaryenAtomicRMWXor(): BinaryenAtomicRMWOp;
|
||||
declare function _BinaryenAtomicRMWXchg(): BinaryenAtomicRMWOp;
|
||||
|
||||
declare type BinaryenExpressionRef = usize;
|
||||
|
||||
@ -202,8 +246,19 @@ declare function _BinaryenReturn(module: BinaryenModuleRef, value: BinaryenExpre
|
||||
declare function _BinaryenHost(module: BinaryenModuleRef, op: BinaryenOp, name: CString | 0, operands: CArray<BinaryenExpressionRef>, numOperands: BinaryenIndex): BinaryenExpressionRef;
|
||||
declare function _BinaryenNop(module: BinaryenModuleRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenUnreachable(module: BinaryenModuleRef): BinaryenExpressionRef;
|
||||
declare function _BinaryenAtomicRMW(module: BinaryenModuleRef, op: BinaryenAtomicRMWOp, bytes: i32, offset: i32, ptr: BinaryenExpressionRef, value: BinaryenExpressionRef, type: BinaryenType): BinaryenExpressionRef;
|
||||
declare function _BinaryenAtomicCmpxchg(module: BinaryenModuleRef, bytes: i32, offset: i32, ptr: BinaryenExpressionRef, expected: BinaryenExpressionRef, replacement: BinaryenExpressionRef, type: BinaryenType): BinaryenExpressionRef;
|
||||
declare function _BinaryenAtomicWait(module: BinaryenModuleRef, ptr: BinaryenExpressionRef, expected: BinaryenExpressionRef, timeout: BinaryenExpressionRef, expectedType: BinaryenType): BinaryenExpressionRef;
|
||||
declare function _BinaryenAtomicWake(module: BinaryenModuleRef, ptr: BinaryenExpressionRef, wakeCount: BinaryenExpressionRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenExpressionGetId(expr: BinaryenExpressionRef): BinaryenExpressionId;
|
||||
declare function _BinaryenExpressionGetType(expr: BinaryenExpressionRef): BinaryenType;
|
||||
declare function _BinaryenExpressionPrint(expr: BinaryenExpressionRef): void;
|
||||
declare function _BinaryenConstGetValueI32(expr: BinaryenExpressionRef): i32;
|
||||
declare function _BinaryenConstGetValueI64Low(expr: BinaryenExpressionRef): i32;
|
||||
declare function _BinaryenConstGetValueI64High(expr: BinaryenExpressionRef): i32;
|
||||
declare function _BinaryenConstGetValueF32(expr: BinaryenExpressionRef): f32;
|
||||
declare function _BinaryenConstGetValueF64(expr: BinaryenExpressionRef): f64;
|
||||
|
||||
declare type BinaryenFunctionRef = usize;
|
||||
|
||||
@ -219,7 +274,9 @@ declare type BinaryenExportRef = usize;
|
||||
declare function _BinaryenAddExport(module: BinaryenModuleRef, internalName: CString, externalName: CString): BinaryenExportRef;
|
||||
declare function _BinaryenRemoveExport(module: BinaryenModuleRef, externalName: CString): void;
|
||||
|
||||
declare function _BinaryenAddGlobal(module: BinaryenModuleRef, name: CString, type: BinaryenType, mutable: i8, init: BinaryenExpressionRef): BinaryenImportRef; // sic
|
||||
declare type BinaryenGlobalRef = usize;
|
||||
|
||||
declare function _BinaryenAddGlobal(module: BinaryenModuleRef, name: CString, type: BinaryenType, mutable: i8, init: BinaryenExpressionRef): BinaryenGlobalRef;
|
||||
|
||||
declare function _BinaryenSetFunctionTable(module: BinaryenModuleRef, funcs: CArray<BinaryenFunctionRef>, numFuncs: BinaryenIndex): void;
|
||||
|
||||
@ -232,6 +289,7 @@ declare function _BinaryenModulePrint(module: BinaryenModuleRef): void;
|
||||
declare function _BinaryenModulePrintAsmjs(module: BinaryenModuleRef): void;
|
||||
declare function _BinaryenModuleValidate(module: BinaryenModuleRef): i32;
|
||||
declare function _BinaryenModuleOptimize(module: BinaryenModuleRef): void;
|
||||
declare function _BinaryenModuleRunPasses(module: BinaryenModuleRef, passes: string[]): void;
|
||||
declare function _BinaryenModuleAutoDrop(module: BinaryenModuleRef): void;
|
||||
declare function _BinaryenModuleWrite(module: BinaryenModuleRef, output: CString, outputSize: usize): usize;
|
||||
declare function _BinaryenModuleRead(input: CString, inputSize: usize): BinaryenModuleRef;
|
||||
@ -248,5 +306,3 @@ declare function _RelooperAddBranchForSwitch(from: RelooperBlockRef, to: Reloope
|
||||
declare function _RelooperRenderAndDispose(relooper: RelooperRef, entry: RelooperBlockRef, labelHelper: BinaryenIndex, module: BinaryenModuleRef): BinaryenExpressionRef;
|
||||
|
||||
declare function _BinaryenSetAPITracing(on: i32): void;
|
||||
|
||||
declare function _BinaryenGetFunctionTypeBySignature(module: BinaryenModuleRef, result: BinaryenType, paramTypes: CArray<BinaryenType>, numParams: BinaryenIndex): BinaryenFunctionTypeRef;
|
||||
|
136
src/binaryen.ts
136
src/binaryen.ts
@ -1,4 +1,4 @@
|
||||
import { U64 } from "./util";
|
||||
import { I64, U64 } from "./util";
|
||||
import { Target } from "./compiler";
|
||||
|
||||
export enum Type {
|
||||
@ -10,6 +10,37 @@ export enum Type {
|
||||
Undefined = _BinaryenUndefined()
|
||||
}
|
||||
|
||||
export enum ExpressionId {
|
||||
Invalid = _BinaryenInvalidId(),
|
||||
Block = _BinaryenBlockId(),
|
||||
If = _BinaryenIfId(),
|
||||
Loop = _BinaryenLoopId(),
|
||||
Break = _BinaryenBreakId(),
|
||||
Switch = _BinaryenSwitchId(),
|
||||
Call = _BinaryenCallId(),
|
||||
CallImport = _BinaryenCallImportId(),
|
||||
CallIndirect = _BinaryenCallIndirectId(),
|
||||
GetLocal = _BinaryenGetLocalId(),
|
||||
SetLocal = _BinaryenSetLocalId(),
|
||||
GetGlobal = _BinaryenGetGlobalId(),
|
||||
SetGlobal = _BinaryenSetGlobalId(),
|
||||
Load = _BinaryenLoadId(),
|
||||
Store = _BinaryenStoreId(),
|
||||
Const = _BinaryenConstId(),
|
||||
Unary = _BinaryenUnaryId(),
|
||||
Binary = _BinaryenBinaryId(),
|
||||
Select = _BinaryenSelectId(),
|
||||
Drop = _BinaryenDropId(),
|
||||
Return = _BinaryenReturnId(),
|
||||
Host = _BinaryenHostId(),
|
||||
Nop = _BinaryenNopId(),
|
||||
Unreachable = _BinaryenUnreachableId(),
|
||||
AtomicCmpxchg = _BinaryenAtomicCmpxchgId(),
|
||||
AtomicRMW = _BinaryenAtomicRMWId(),
|
||||
AtomicWait = _BinaryenAtomicWaitId(),
|
||||
AtomicWake = _BinaryenAtomicWakeId()
|
||||
}
|
||||
|
||||
export enum UnaryOp {
|
||||
ClzI32 = _BinaryenClzInt32(),
|
||||
CtzI32 = _BinaryenCtzInt32(),
|
||||
@ -146,13 +177,13 @@ export enum HostOp {
|
||||
HasFeature = _BinaryenHasFeature()
|
||||
}
|
||||
|
||||
export enum AtomicRMWOp { // TODO: not yet part of the C-API
|
||||
Add,
|
||||
Sub,
|
||||
And,
|
||||
Or,
|
||||
Xor,
|
||||
Xchg
|
||||
export enum AtomicRMWOp {
|
||||
Add = _BinaryenAtomicRMWAdd(),
|
||||
Sub = _BinaryenAtomicRMWSub(),
|
||||
And = _BinaryenAtomicRMWAnd(),
|
||||
Or = _BinaryenAtomicRMWOr(),
|
||||
Xor = _BinaryenAtomicRMWXor(),
|
||||
Xchg = _BinaryenAtomicRMWXchg()
|
||||
}
|
||||
|
||||
export class MemorySegment {
|
||||
@ -216,8 +247,8 @@ export class Module {
|
||||
try {
|
||||
return _BinaryenAddFunctionType(this.ref, cStr, result, cArr, paramTypes.length);
|
||||
} finally {
|
||||
_free(cStr);
|
||||
_free(cArr);
|
||||
_free(cStr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,8 +305,8 @@ export class Module {
|
||||
try {
|
||||
return _BinaryenHost(this.ref, op, cStr, cArr, operands ? (<BinaryenExpressionRef[]>operands).length : 0);
|
||||
} finally {
|
||||
_free(cStr);
|
||||
_free(cArr);
|
||||
_free(cStr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -299,6 +330,26 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
createAtomicRMW(op: AtomicRMWOp, bytes: i32, offset: i32, ptr: BinaryenExpressionRef, value: BinaryenExpressionRef, type: Type): BinaryenExpressionRef {
|
||||
if (this.noEmit) return 0;
|
||||
return _BinaryenAtomicRMW(this.ref, op, bytes, offset, ptr, value, type);
|
||||
}
|
||||
|
||||
createAtomicCmpxchg(bytes: i32, offset: i32, ptr: BinaryenExpressionRef, expected: BinaryenExpressionRef, replacement: BinaryenExpressionRef, type: Type): BinaryenExpressionRef {
|
||||
if (this.noEmit) return 0;
|
||||
return _BinaryenAtomicCmpxchg(this.ref, bytes, offset, ptr, expected, replacement, type);
|
||||
}
|
||||
|
||||
createAtomicWait(ptr: BinaryenExpressionRef, expected: BinaryenExpressionRef, timeout: BinaryenExpressionRef, expectedType: BinaryenType): BinaryenExpressionRef {
|
||||
if (this.noEmit) return 0;
|
||||
return _BinaryenAtomicWait(this.ref, ptr, expected, timeout, expectedType);
|
||||
}
|
||||
|
||||
createAtomicWake(ptr: BinaryenExpressionRef, wakeCount: BinaryenExpressionRef): BinaryenExpressionRef {
|
||||
if (this.noEmit) return 0;
|
||||
return _BinaryenAtomicWake(this.ref, ptr, wakeCount);
|
||||
}
|
||||
|
||||
// statements
|
||||
|
||||
createSetLocal(index: i32, value: BinaryenExpressionRef): BinaryenExpressionRef {
|
||||
@ -323,8 +374,8 @@ export class Module {
|
||||
try {
|
||||
return _BinaryenBlock(this.ref, cStr, cArr, children.length, type);
|
||||
} finally {
|
||||
_free(cStr);
|
||||
_free(cArr);
|
||||
_free(cStr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -383,9 +434,9 @@ export class Module {
|
||||
try {
|
||||
return _BinaryenSwitch(this.ref, cArr, k, cStr, condition, value);
|
||||
} finally {
|
||||
for (i = 0; i < k; ++i) _free(strs[i]);
|
||||
_free(cArr);
|
||||
_free(cStr);
|
||||
_free(cArr);
|
||||
for (i = k - 1; i >= 0; --i) _free(strs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -416,7 +467,7 @@ export class Module {
|
||||
|
||||
// meta
|
||||
|
||||
addGlobal(name: string, type: Type, mutable: bool, initializer: BinaryenExpressionRef): BinaryenImportRef {
|
||||
addGlobal(name: string, type: Type, mutable: bool, initializer: BinaryenExpressionRef): BinaryenGlobalRef {
|
||||
if (this.noEmit) return 0;
|
||||
const cStr: CString = allocString(name);
|
||||
try {
|
||||
@ -433,8 +484,8 @@ export class Module {
|
||||
try {
|
||||
return _BinaryenAddFunction(this.ref, cStr, type, cArr, varTypes.length, body);
|
||||
} finally {
|
||||
_free(cStr);
|
||||
_free(cArr);
|
||||
_free(cStr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -445,8 +496,8 @@ export class Module {
|
||||
try {
|
||||
return _BinaryenAddExport(this.ref, cStr1, cStr2);
|
||||
} finally {
|
||||
_free(cStr1);
|
||||
_free(cStr2);
|
||||
_free(cStr1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -468,9 +519,9 @@ export class Module {
|
||||
try {
|
||||
return _BinaryenAddImport(this.ref, cStr1, cStr2, cStr3, type);
|
||||
} finally {
|
||||
_free(cStr1);
|
||||
_free(cStr2);
|
||||
_free(cStr3);
|
||||
_free(cStr2);
|
||||
_free(cStr1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -506,11 +557,11 @@ export class Module {
|
||||
try {
|
||||
_BinaryenSetMemory(this.ref, initial, maximum, cStr, cArr1, cArr2, cArr3, k);
|
||||
} finally {
|
||||
_free(cStr);
|
||||
for (i = 0; i < k; ++i) _free(segs[i]);
|
||||
_free(cArr1);
|
||||
_free(cArr2);
|
||||
_free(cArr3);
|
||||
_free(cArr2);
|
||||
_free(cArr1);
|
||||
for (i = k - 1; i >= 0; --i) _free(segs[i]);
|
||||
_free(cStr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -540,6 +591,45 @@ export class Module {
|
||||
}
|
||||
}
|
||||
|
||||
export function getExpressionId(expr: BinaryenExpressionRef): ExpressionId {
|
||||
return _BinaryenExpressionGetId(expr);
|
||||
}
|
||||
|
||||
export function getExpressionType(expr: BinaryenExpressionRef): Type {
|
||||
return _BinaryenExpressionGetType(expr);
|
||||
}
|
||||
|
||||
export function printExpression(expr: BinaryenExpressionRef): void {
|
||||
return _BinaryenExpressionPrint(expr);
|
||||
}
|
||||
|
||||
export function getConstValueI32(expr: BinaryenExpressionRef): i32 {
|
||||
return _BinaryenConstGetValueI32(expr);
|
||||
}
|
||||
|
||||
export function getConstValueI64Low(expr: BinaryenExpressionRef): i32 {
|
||||
return _BinaryenConstGetValueI64Low(expr);
|
||||
}
|
||||
|
||||
export function getConstValueI64High(expr: BinaryenExpressionRef): i32 {
|
||||
return _BinaryenConstGetValueI64High(expr);
|
||||
}
|
||||
|
||||
export function getConstValueI64(expr: BinaryenExpressionRef): I64 {
|
||||
return new I64(
|
||||
_BinaryenConstGetValueI64Low(expr),
|
||||
_BinaryenConstGetValueI64High(expr)
|
||||
);
|
||||
}
|
||||
|
||||
export function getConstValueF32(expr: BinaryenExpressionRef): f32 {
|
||||
return _BinaryenConstGetValueF32(expr);
|
||||
}
|
||||
|
||||
export function getConstValueF64(expr: BinaryenExpressionRef): f64 {
|
||||
return _BinaryenConstGetValueF64(expr);
|
||||
}
|
||||
|
||||
export class Relooper {
|
||||
|
||||
module: Module;
|
||||
@ -596,7 +686,7 @@ export class Relooper {
|
||||
}
|
||||
|
||||
// helpers
|
||||
// TODO: investigate stack allocation?
|
||||
// can't do stack allocation here: STACKTOP is a global in WASM but a hidden variable in asm.js
|
||||
|
||||
function allocU8Array(u8s: Uint8Array | null): CArray<u8> {
|
||||
if (!u8s) return 0;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { Module, MemorySegment, UnaryOp, BinaryOp, HostOp, Type as BinaryenType, Relooper } from "./binaryen";
|
||||
import { PATH_DELIMITER } from "./constants";
|
||||
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
|
||||
import { Program, ClassTemplate, Element, ElementKind, Enum, FunctionTemplate, FunctionInstance, Global, Local, Namespace, Parameter } from "./program";
|
||||
import { Program, ClassPrototype, Element, ElementKind, Enum, FunctionPrototype, Function, Global, Local, Namespace, Parameter } from "./program";
|
||||
import { CharCode, I64, U64, normalizePath, sb } from "./util";
|
||||
import { Token } from "./tokenizer";
|
||||
import {
|
||||
@ -96,11 +96,11 @@ export class Compiler extends DiagnosticEmitter {
|
||||
options: Options;
|
||||
module: Module;
|
||||
|
||||
startFunction: FunctionInstance;
|
||||
startFunction: Function;
|
||||
startFunctionBody: BinaryenExpressionRef[] = new Array();
|
||||
|
||||
currentType: Type = Type.void;
|
||||
currentFunction: FunctionInstance;
|
||||
currentFunction: Function;
|
||||
disallowContinue: bool = true;
|
||||
|
||||
memoryOffset: U64 = new U64(8, 0); // leave space for (any size of) NULL
|
||||
@ -118,8 +118,8 @@ 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: FunctionTemplate = new FunctionTemplate(program, "start", null);
|
||||
const startFunctionInstance: FunctionInstance = new FunctionInstance(startFunctionTemplate, startFunctionTemplate.internalName, [], [], Type.void, null);
|
||||
const startFunctionTemplate: FunctionPrototype = new FunctionPrototype(program, "start", null);
|
||||
const startFunctionInstance: Function = new Function(startFunctionTemplate, startFunctionTemplate.internalName, [], [], Type.void, null);
|
||||
this.currentFunction = this.startFunction = startFunctionInstance;
|
||||
this.memoryOffset = new U64(2 * (this.options.target == Target.WASM64 ? 8 : 4), 0); // leave space for `null` and heapStart (both of usize type)
|
||||
}
|
||||
@ -251,7 +251,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
|
||||
// otherwise a top-level statement that is part of the start function's body
|
||||
default: {
|
||||
const previousFunction: FunctionInstance = this.currentFunction;
|
||||
const previousFunction: Function = this.currentFunction;
|
||||
this.currentFunction = this.startFunction;
|
||||
this.startFunctionBody.push(this.compileStatement(statement));
|
||||
this.currentFunction = previousFunction;
|
||||
@ -290,7 +290,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
let initializeInStart: bool;
|
||||
if (element.hasConstantValue) {
|
||||
if (type.isLongInteger)
|
||||
initializer = this.module.createI64(element.constantIntegerValue.lo, element.constantIntegerValue.hi);
|
||||
initializer = element.constantIntegerValue ? this.module.createI64(element.constantIntegerValue.lo, element.constantIntegerValue.hi) : this.module.createI64(0, 0);
|
||||
else if (type.kind == TypeKind.F32)
|
||||
initializer = this.module.createF32(element.constantFloatValue);
|
||||
else if (type.kind == TypeKind.F64)
|
||||
@ -298,11 +298,11 @@ export class Compiler extends DiagnosticEmitter {
|
||||
else if (type.isSmallInteger) {
|
||||
if (type.isSignedInteger) {
|
||||
const shift: i32 = type.smallIntegerShift;
|
||||
initializer = this.module.createI32(element.constantIntegerValue.toI32() << shift >> shift);
|
||||
initializer = this.module.createI32(element.constantIntegerValue ? element.constantIntegerValue.toI32() << shift >> shift : 0);
|
||||
} else
|
||||
initializer = this.module.createI32(element.constantIntegerValue.toI32() & type.smallIntegerMask);
|
||||
initializer = this.module.createI32(element.constantIntegerValue ? element.constantIntegerValue.toI32() & type.smallIntegerMask: 0);
|
||||
} else
|
||||
initializer = this.module.createI32(element.constantIntegerValue.toI32());
|
||||
initializer = this.module.createI32(element.constantIntegerValue ? element.constantIntegerValue.toI32() : 0);
|
||||
initializeInStart = false;
|
||||
this.module.addGlobal(element.internalName, binaryenType, element.isMutable, initializer);
|
||||
} else if (declaration) {
|
||||
@ -374,16 +374,16 @@ export class Compiler extends DiagnosticEmitter {
|
||||
compileFunctionDeclaration(declaration: FunctionDeclaration, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const element: Element | null = <Element | null>this.program.elements.get(internalName);
|
||||
if (!element || element.kind != ElementKind.FUNCTION)
|
||||
if (!element || element.kind != ElementKind.FUNCTION_PROTOTYPE)
|
||||
throw new Error("unexpected missing function");
|
||||
const resolvedTypeArguments: Type[] | null = this.program.resolveTypeArguments(declaration.typeParameters, typeArguments, contextualTypeArguments, alternativeReportNode); // reports
|
||||
if (!resolvedTypeArguments)
|
||||
return;
|
||||
this.compileFunction(<FunctionTemplate>element, resolvedTypeArguments, contextualTypeArguments);
|
||||
this.compileFunction(<FunctionPrototype>element, resolvedTypeArguments, contextualTypeArguments);
|
||||
}
|
||||
|
||||
compileFunction(template: FunctionTemplate, typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null = null): void {
|
||||
const instance: FunctionInstance | null = template.instantiate(typeArguments, contextualTypeArguments);
|
||||
compileFunction(template: FunctionPrototype, typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null = null): void {
|
||||
const instance: Function | null = template.resolve(typeArguments, contextualTypeArguments);
|
||||
if (!instance || instance.compiled)
|
||||
return;
|
||||
|
||||
@ -398,7 +398,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
instance.compiled = true;
|
||||
|
||||
// compile statements
|
||||
const previousFunction: FunctionInstance = this.currentFunction;
|
||||
const previousFunction: Function = this.currentFunction;
|
||||
this.currentFunction = instance;
|
||||
const stmts: BinaryenExpressionRef[] = this.compileStatements(<Statement[]>declaration.statements);
|
||||
this.currentFunction = previousFunction;
|
||||
@ -468,18 +468,18 @@ export class Compiler extends DiagnosticEmitter {
|
||||
for (let [name, element] of ns.members) {
|
||||
switch (element.kind) {
|
||||
|
||||
case ElementKind.CLASS:
|
||||
if ((noTreeShaking || (<ClassTemplate>element).isExport) && !(<ClassTemplate>element).isGeneric)
|
||||
this.compileClass(<ClassTemplate>element, []);
|
||||
case ElementKind.CLASS_PROTOTYPE:
|
||||
if ((noTreeShaking || (<ClassPrototype>element).isExport) && !(<ClassPrototype>element).isGeneric)
|
||||
this.compileClass(<ClassPrototype>element, []);
|
||||
break;
|
||||
|
||||
case ElementKind.ENUM:
|
||||
this.compileEnum(<Enum>element);
|
||||
break;
|
||||
|
||||
case ElementKind.FUNCTION:
|
||||
if ((noTreeShaking || (<FunctionTemplate>element).isExport) && !(<FunctionTemplate>element).isGeneric)
|
||||
this.compileFunction(<FunctionTemplate>element, []);
|
||||
case ElementKind.FUNCTION_PROTOTYPE:
|
||||
if ((noTreeShaking || (<FunctionPrototype>element).isExport) && !(<FunctionPrototype>element).isGeneric)
|
||||
this.compileFunction(<FunctionPrototype>element, []);
|
||||
break;
|
||||
|
||||
case ElementKind.GLOBAL:
|
||||
@ -506,18 +506,18 @@ export class Compiler extends DiagnosticEmitter {
|
||||
throw new Error("unexpected missing element");
|
||||
switch (element.kind) {
|
||||
|
||||
case ElementKind.CLASS:
|
||||
if (!(<ClassTemplate>element).isGeneric)
|
||||
this.compileClass(<ClassTemplate>element, []);
|
||||
case ElementKind.CLASS_PROTOTYPE:
|
||||
if (!(<ClassPrototype>element).isGeneric)
|
||||
this.compileClass(<ClassPrototype>element, []);
|
||||
break;
|
||||
|
||||
case ElementKind.ENUM:
|
||||
this.compileEnum(<Enum>element);
|
||||
break;
|
||||
|
||||
case ElementKind.FUNCTION:
|
||||
if (!(<FunctionTemplate>element).isGeneric)
|
||||
this.compileFunction(<FunctionTemplate>element, []);
|
||||
case ElementKind.FUNCTION_PROTOTYPE:
|
||||
if (!(<FunctionPrototype>element).isGeneric)
|
||||
this.compileFunction(<FunctionPrototype>element, []);
|
||||
break;
|
||||
|
||||
case ElementKind.GLOBAL:
|
||||
@ -536,15 +536,15 @@ export class Compiler extends DiagnosticEmitter {
|
||||
compileClassDeclaration(declaration: ClassDeclaration, typeArguments: TypeNode[], contextualTypeArguments: Map<string,Type> | null = null, alternativeReportNode: Node | null = null): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const element: Element | null = <Element | null>this.program.elements.get(internalName);
|
||||
if (!element || element.kind != ElementKind.CLASS)
|
||||
if (!element || element.kind != ElementKind.CLASS_PROTOTYPE)
|
||||
throw new Error("unexpected missing class");
|
||||
const resolvedTypeArguments: Type[] | null = this.program.resolveTypeArguments(declaration.typeParameters, typeArguments, contextualTypeArguments, alternativeReportNode); // reports
|
||||
if (!resolvedTypeArguments)
|
||||
return;
|
||||
this.compileClass(<ClassTemplate>element, resolvedTypeArguments, contextualTypeArguments);
|
||||
this.compileClass(<ClassPrototype>element, resolvedTypeArguments, contextualTypeArguments);
|
||||
}
|
||||
|
||||
compileClass(cls: ClassTemplate, typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null = null) {
|
||||
compileClass(cls: ClassPrototype, typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null = null) {
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
@ -1053,9 +1053,9 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
compileAssertionExpression(expression: AssertionExpression, contextualType: Type): BinaryenExpressionRef {
|
||||
const toType: Type | null = this.program.resolveType(expression.toType, this.currentFunction.contextualTypeArguments, true); // reports
|
||||
const toType: Type | null = this.program.resolveType(expression.toType, this.currentFunction.contextualTypeArguments); // reports
|
||||
if (toType && toType != contextualType) {
|
||||
const expr: BinaryenExpressionRef = this.compileExpression(expression.expression, <Type>toType);
|
||||
const expr: BinaryenExpressionRef = this.compileExpression(expression.expression, <Type>toType, false);
|
||||
return this.convertExpression(expr, this.currentType, <Type>toType);
|
||||
}
|
||||
return this.compileExpression(expression.expression, contextualType);
|
||||
@ -1316,9 +1316,13 @@ export class Compiler extends DiagnosticEmitter {
|
||||
}
|
||||
|
||||
compileCallExpression(expression: CallExpression, contextualType: Type): BinaryenExpressionRef {
|
||||
const element: Element | null = this.program.resolveElement(expression, this.currentFunction);
|
||||
if (!element || element.kind != ElementKind.FUNCTION)
|
||||
const element: Element | null = this.program.resolveElement(expression.expression, this.currentFunction); // reports
|
||||
if (!element)
|
||||
return this.module.createUnreachable();
|
||||
if (element.kind != ElementKind.FUNCTION_PROTOTYPE) {
|
||||
// TODO: report 'Cannot invoke an expression whose type lacks a call signature.'
|
||||
return this.module.createUnreachable();
|
||||
}
|
||||
throw new Error("not implemented");
|
||||
}
|
||||
|
||||
@ -1401,7 +1405,7 @@ export class Compiler extends DiagnosticEmitter {
|
||||
// throw new Error("not implemented");
|
||||
|
||||
// getter
|
||||
if (element.kind == ElementKind.FUNCTION && (<FunctionTemplate>element).isGetter)
|
||||
if (element.kind == ElementKind.FUNCTION_PROTOTYPE && (<FunctionPrototype>element).isGetter)
|
||||
throw new Error("not implemented");
|
||||
|
||||
this.error(DiagnosticCode.Operation_not_supported, expression.range);
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
export const PATH_DELIMITER: string = "/";
|
||||
export const PARENT_SUBST: string = "..";
|
||||
export const GETTER_PREFIX: string = "get:";
|
||||
export const SETTER_PREFIX: string = "set:";
|
||||
export const GETTER_PREFIX: string = "get ";
|
||||
export const SETTER_PREFIX: string = "set ";
|
||||
export const INSTANCE_DELIMITER: string = "#";
|
||||
export const STATIC_DELIMITER: string = ".";
|
||||
|
@ -51,10 +51,12 @@ export enum DiagnosticCode {
|
||||
Type_0_is_not_generic = 2315,
|
||||
Type_0_is_not_assignable_to_type_1 = 2322,
|
||||
_this_cannot_be_referenced_in_current_location = 2332,
|
||||
Property_0_does_not_exist_on_type_1 = 2339,
|
||||
The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access = 2357,
|
||||
The_left_hand_side_of_an_assignment_expression_must_be_a_variable_or_a_property_access = 2364,
|
||||
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391,
|
||||
Duplicate_function_implementation = 2393,
|
||||
Export_declaration_conflicts_with_exported_declaration_of_0 = 2484,
|
||||
The_target_of_an_assignment_must_be_a_variable_or_a_property_access = 2541,
|
||||
Expected_0_type_arguments_but_got_1 = 2558,
|
||||
File_0_not_found = 6054
|
||||
@ -112,10 +114,12 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
||||
case 2315: return "Type '{0}' is not generic.";
|
||||
case 2322: return "Type '{0}' is not assignable to type '{1}'.";
|
||||
case 2332: return "'this' cannot be referenced in current location.";
|
||||
case 2339: return "Property '{0}' does not exist on type '{1}'.";
|
||||
case 2357: return "The operand of an increment or decrement operator must be a variable or a property access.";
|
||||
case 2364: return "The left-hand side of an assignment expression must be a variable or a property access.";
|
||||
case 2391: return "Function implementation is missing or not immediately following the declaration.";
|
||||
case 2393: return "Duplicate function implementation.";
|
||||
case 2484: return "Export declaration conflicts with exported declaration of '{0}'.";
|
||||
case 2541: return "The target of an assignment must be a variable or a property access.";
|
||||
case 2558: return "Expected {0} type arguments, but got {1}.";
|
||||
case 6054: return "File '{0}' not found.";
|
||||
|
@ -51,10 +51,12 @@
|
||||
"Type '{0}' is not generic.": 2315,
|
||||
"Type '{0}' is not assignable to type '{1}'.": 2322,
|
||||
"'this' cannot be referenced in current location.": 2332,
|
||||
"Property '{0}' does not exist on type '{1}'.": 2339,
|
||||
"The operand of an increment or decrement operator must be a variable or a property access.": 2357,
|
||||
"The left-hand side of an assignment expression must be a variable or a property access.": 2364,
|
||||
"Function implementation is missing or not immediately following the declaration.": 2391,
|
||||
"Duplicate function implementation.": 2393,
|
||||
"Export declaration conflicts with exported declaration of '{0}'.": 2484,
|
||||
"The target of an assignment must be a variable or a property access.": 2541,
|
||||
"Expected {0} type arguments, but got {1}.": 2558,
|
||||
|
||||
|
@ -11,10 +11,12 @@ export enum DiagnosticCategory {
|
||||
}
|
||||
|
||||
export function diagnosticCategoryToString(category: DiagnosticCategory): string {
|
||||
if (category == DiagnosticCategory.INFO) return "INFO";
|
||||
if (category == DiagnosticCategory.WARNING) return "WARNING";
|
||||
if (category == DiagnosticCategory.ERROR) return "ERROR";
|
||||
return "";
|
||||
switch (category) {
|
||||
case DiagnosticCategory.INFO: return "INFO";
|
||||
case DiagnosticCategory.WARNING: return "WARNING";
|
||||
case DiagnosticCategory.ERROR: return "ERROR";
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
const colorBlue: string = "\u001b[93m";
|
||||
@ -23,10 +25,12 @@ const colorRed: string = "\u001b[91m";
|
||||
const colorReset: string = "\u001b[0m";
|
||||
|
||||
export function diagnosticCategoryToColor(category: DiagnosticCategory): string {
|
||||
if (category == DiagnosticCategory.INFO) return colorBlue;
|
||||
if (category == DiagnosticCategory.WARNING) return colorYellow;
|
||||
if (category == DiagnosticCategory.ERROR) return colorRed;
|
||||
return "";
|
||||
switch (category) {
|
||||
case DiagnosticCategory.INFO: return colorBlue;
|
||||
case DiagnosticCategory.WARNING: return colorYellow;
|
||||
case DiagnosticCategory.ERROR: return colorRed;
|
||||
default: return "";
|
||||
}
|
||||
}
|
||||
|
||||
export class DiagnosticMessage {
|
||||
|
68
src/evaluator.ts
Normal file
68
src/evaluator.ts
Normal file
@ -0,0 +1,68 @@
|
||||
// TODO: not yet decided whether we'll need this
|
||||
// https://github.com/WebAssembly/binaryen/pull/1294
|
||||
// https://github.com/WebAssembly/binaryen/pull/1295
|
||||
|
||||
import { Type } from "./types";
|
||||
import { I64 } from "./util";
|
||||
import {
|
||||
|
||||
NodeKind,
|
||||
|
||||
Expression,
|
||||
BinaryExpression,
|
||||
LiteralExpression,
|
||||
UnaryExpression,
|
||||
UnaryPostfixExpression,
|
||||
UnaryPrefixExpression
|
||||
|
||||
} from "./ast";
|
||||
|
||||
export class Evaluator {
|
||||
|
||||
success: bool = false;
|
||||
type: Type;
|
||||
integerValue: I64;
|
||||
floatValue: f64;
|
||||
stringValue: string;
|
||||
|
||||
constructor(initialType: Type) {
|
||||
this.type = initialType;
|
||||
}
|
||||
|
||||
evaluate(expression: Expression): this {
|
||||
switch (expression.kind) {
|
||||
|
||||
case NodeKind.BINARY:
|
||||
this.evaluateBinary(<BinaryExpression>expression);
|
||||
break;
|
||||
|
||||
case NodeKind.LITERAL:
|
||||
this.evaluateLiteral(<LiteralExpression>expression);
|
||||
break;
|
||||
|
||||
case NodeKind.UNARYPREFIX:
|
||||
this.evaluateUnaryPrefix(<UnaryPrefixExpression>expression);
|
||||
break;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private evaluateBinary(expression: BinaryExpression): this {
|
||||
// TODO
|
||||
return this;
|
||||
}
|
||||
|
||||
private evaluateLiteral(expression: LiteralExpression): this {
|
||||
// TODO
|
||||
return this;
|
||||
}
|
||||
|
||||
private evaluateUnaryPrefix(expression: UnaryPrefixExpression): this {
|
||||
// TODO
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
export function evaluate(expression: Expression, contextualType: Type): Evaluator {
|
||||
return new Evaluator(contextualType).evaluate(expression);
|
||||
}
|
463
src/program.ts
463
src/program.ts
@ -201,113 +201,98 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
private initializeClass(declaration: ClassDeclaration): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const template: ClassTemplate = new ClassTemplate(this, internalName, declaration);
|
||||
if (this.elements.has(internalName))
|
||||
if (this.elements.has(internalName)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
else
|
||||
this.elements.set(internalName, template);
|
||||
return;
|
||||
}
|
||||
const prototype: ClassPrototype = new ClassPrototype(this, internalName, declaration);
|
||||
this.elements.set(internalName, prototype);
|
||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||
if (this.exports.has(internalName))
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.identifier.range, internalName);
|
||||
else
|
||||
this.exports.set(internalName, template);
|
||||
this.exports.set(internalName, prototype);
|
||||
}
|
||||
const memberDeclarations: DeclarationStatement[] = declaration.members;
|
||||
for (let j: i32 = 0, l: i32 = memberDeclarations.length; j < l; ++j) {
|
||||
const memberDeclaration: DeclarationStatement = memberDeclarations[j];
|
||||
switch (memberDeclaration.kind) {
|
||||
|
||||
case NodeKind.FIELD:
|
||||
this.initializeField(<FieldDeclaration>memberDeclaration, template);
|
||||
break;
|
||||
|
||||
case NodeKind.METHOD:
|
||||
this.initializeMethod(<MethodDeclaration>memberDeclaration, template);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("unexpected class member");
|
||||
}
|
||||
if (memberDeclaration.kind == NodeKind.FIELD)
|
||||
this.initializeField(<FieldDeclaration>memberDeclaration, prototype);
|
||||
else if (memberDeclaration.kind == NodeKind.METHOD)
|
||||
this.initializeMethod(<MethodDeclaration>memberDeclaration, prototype);
|
||||
else
|
||||
throw new Error("unexpected class member");
|
||||
}
|
||||
}
|
||||
|
||||
private initializeField(declaration: FieldDeclaration, template: ClassTemplate): void {
|
||||
private initializeField(declaration: FieldDeclaration, classPrototype: ClassPrototype): void {
|
||||
const name: string = declaration.identifier.name;
|
||||
if (hasModifier(ModifierKind.STATIC, declaration.modifiers)) {
|
||||
const internalName: string = declaration.internalName;
|
||||
if (template.members.has(name))
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
else {
|
||||
const global: Global = new Global(this, internalName, declaration, null);
|
||||
template.members.set(name, global);
|
||||
}
|
||||
if (classPrototype.members.has(name)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, declaration.internalName);
|
||||
return;
|
||||
}
|
||||
const internalName: string = declaration.internalName;
|
||||
if (hasModifier(ModifierKind.STATIC, declaration.modifiers)) { // static fields become globals
|
||||
const global: Global = new Global(this, internalName, declaration, null);
|
||||
classPrototype.members.set(name, global);
|
||||
} else {
|
||||
if (template.fieldDeclarations.has(name))
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, name);
|
||||
else
|
||||
template.fieldDeclarations.set(name, declaration);
|
||||
const field: FieldPrototype = new FieldPrototype(classPrototype, internalName, declaration);
|
||||
classPrototype.members.set(name, field);
|
||||
}
|
||||
}
|
||||
|
||||
private initializeMethod(declaration: MethodDeclaration, template: ClassTemplate): void {
|
||||
private initializeMethod(declaration: MethodDeclaration, classPrototype: ClassPrototype): void {
|
||||
let name: string = declaration.identifier.name;
|
||||
if (hasModifier(ModifierKind.STATIC, declaration.modifiers)) {
|
||||
const internalName: string = declaration.internalName;
|
||||
if (template.members.has(name))
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
else {
|
||||
const func: FunctionTemplate = new FunctionTemplate(this, internalName, declaration);
|
||||
let modifiers: Modifier[] | null;
|
||||
if (modifiers = declaration.modifiers) {
|
||||
for (let i: i32 = 0, k: i32 = modifiers.length; i < k; ++i) {
|
||||
const modifier: Modifier = modifiers[i];
|
||||
if (modifier.modifierKind == ModifierKind.GET) {
|
||||
name = GETTER_PREFIX + name;
|
||||
break;
|
||||
} else if (modifier.modifierKind == ModifierKind.SET) {
|
||||
name = SETTER_PREFIX + name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
template.members.set(name, func);
|
||||
}
|
||||
} else {
|
||||
if (template.methodDeclarations.has(name))
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, name);
|
||||
else
|
||||
template.methodDeclarations.set(name, declaration);
|
||||
const internalName: string = declaration.internalName;
|
||||
if (classPrototype.members.has(name)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
return;
|
||||
}
|
||||
const func: FunctionPrototype = new FunctionPrototype(this, internalName, declaration, hasModifier(ModifierKind.STATIC, declaration.modifiers) ? null : classPrototype);
|
||||
let modifiers: Modifier[] | null;
|
||||
if (modifiers = declaration.modifiers) {
|
||||
for (let i: i32 = 0, k: i32 = modifiers.length; i < k; ++i) {
|
||||
const modifier: Modifier = modifiers[i];
|
||||
if (modifier.modifierKind == ModifierKind.GET) {
|
||||
name = GETTER_PREFIX + name;
|
||||
break;
|
||||
} else if (modifier.modifierKind == ModifierKind.SET) {
|
||||
name = SETTER_PREFIX + name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
classPrototype.members.set(name, func);
|
||||
}
|
||||
|
||||
private initializeEnum(declaration: EnumDeclaration): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const enm: Enum = new Enum(this, internalName, declaration);
|
||||
if (this.elements.has(internalName))
|
||||
if (this.elements.has(internalName)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
else {
|
||||
this.elements.set(internalName, enm);
|
||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||
if (this.exports.has(internalName))
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
else
|
||||
this.exports.set(internalName, enm);
|
||||
}
|
||||
const members: EnumValueDeclaration[] = declaration.members;
|
||||
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i)
|
||||
this.initializeEnumValue(members[i], enm);
|
||||
return;
|
||||
}
|
||||
const enm: Enum = new Enum(this, internalName, declaration);
|
||||
this.elements.set(internalName, enm);
|
||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||
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, enm);
|
||||
}
|
||||
const values: EnumValueDeclaration[] = declaration.members;
|
||||
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.identifier.name;
|
||||
const internalName: string = declaration.internalName;
|
||||
if (enm.members.has(name))
|
||||
if (enm.members.has(name)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
else {
|
||||
const value: EnumValue = new EnumValue(enm, this, internalName, declaration);
|
||||
enm.members.set(name, value);
|
||||
return;
|
||||
}
|
||||
const value: EnumValue = new EnumValue(enm, this, internalName, declaration);
|
||||
enm.members.set(name, value);
|
||||
}
|
||||
|
||||
private initializeExports(statement: ExportStatement, queuedExports: Map<string,QueuedExport>): void {
|
||||
@ -318,35 +303,35 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
private initializeExport(member: ExportMember, internalPath: string | null, queuedExports: Map<string,QueuedExport>): void {
|
||||
const exportName: string = member.range.source.internalPath + PATH_DELIMITER + member.externalIdentifier.name;
|
||||
if (queuedExports.has(exportName))
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, member.externalIdentifier.range, exportName);
|
||||
else {
|
||||
const queuedExport: QueuedExport = new QueuedExport();
|
||||
if (internalPath == null) {
|
||||
queuedExport.isForeign = false;
|
||||
queuedExport.referencedName = member.range.source.internalPath + PATH_DELIMITER + member.identifier.name;
|
||||
} else {
|
||||
queuedExport.isForeign = true;
|
||||
queuedExport.referencedName = (<string>internalPath) + PATH_DELIMITER + member.identifier.name;
|
||||
}
|
||||
queuedExport.member = member;
|
||||
queuedExports.set(exportName, queuedExport);
|
||||
if (queuedExports.has(exportName)) {
|
||||
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, member.externalIdentifier.range, exportName);
|
||||
return;
|
||||
}
|
||||
const queuedExport: QueuedExport = new QueuedExport();
|
||||
if (internalPath == null) {
|
||||
queuedExport.isForeign = false;
|
||||
queuedExport.referencedName = member.range.source.internalPath + PATH_DELIMITER + member.identifier.name;
|
||||
} else {
|
||||
queuedExport.isForeign = true;
|
||||
queuedExport.referencedName = (<string>internalPath) + PATH_DELIMITER + member.identifier.name;
|
||||
}
|
||||
queuedExport.member = member;
|
||||
queuedExports.set(exportName, queuedExport);
|
||||
}
|
||||
|
||||
private initializeFunction(declaration: FunctionDeclaration): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const template: FunctionTemplate = new FunctionTemplate(this, internalName, declaration);
|
||||
if (this.elements.has(internalName))
|
||||
const prototype: FunctionPrototype = new FunctionPrototype(this, internalName, declaration, null);
|
||||
if (this.elements.has(internalName)) {
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
else {
|
||||
this.elements.set(internalName, template);
|
||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||
if (this.exports.has(internalName))
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
else
|
||||
this.exports.set(internalName, template);
|
||||
}
|
||||
return;
|
||||
}
|
||||
this.elements.set(internalName, prototype);
|
||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -386,16 +371,16 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
private initializeInterface(declaration: InterfaceDeclaration): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const template: InterfaceTemplate = new InterfaceTemplate(this, internalName, declaration);
|
||||
const interfacePrototype: 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, template);
|
||||
this.elements.set(internalName, interfacePrototype);
|
||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||
if (this.exports.has(internalName))
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.identifier.range, internalName);
|
||||
else
|
||||
this.exports.set(internalName, template);
|
||||
this.exports.set(internalName, interfacePrototype);
|
||||
}
|
||||
const memberDeclarations: DeclarationStatement[] = declaration.members;
|
||||
for (let j: i32 = 0, l: i32 = memberDeclarations.length; j < l; ++j) {
|
||||
@ -403,11 +388,11 @@ export class Program extends DiagnosticEmitter {
|
||||
switch (memberDeclaration.kind) {
|
||||
|
||||
case NodeKind.FIELD:
|
||||
this.initializeField(<FieldDeclaration>memberDeclaration, template);
|
||||
this.initializeField(<FieldDeclaration>memberDeclaration, interfacePrototype);
|
||||
break;
|
||||
|
||||
case NodeKind.METHOD:
|
||||
this.initializeMethod(<MethodDeclaration>memberDeclaration, template);
|
||||
this.initializeMethod(<MethodDeclaration>memberDeclaration, interfacePrototype);
|
||||
break;
|
||||
|
||||
default:
|
||||
@ -418,16 +403,16 @@ export class Program extends DiagnosticEmitter {
|
||||
|
||||
private initializeNamespace(declaration: NamespaceDeclaration): void {
|
||||
const internalName: string = declaration.internalName;
|
||||
const ns: Namespace = new Namespace(this, internalName, declaration);
|
||||
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, ns);
|
||||
this.elements.set(internalName, namespace);
|
||||
if (hasModifier(ModifierKind.EXPORT, declaration.modifiers)) {
|
||||
if (this.exports.has(internalName))
|
||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, internalName);
|
||||
this.error(DiagnosticCode.Export_declaration_conflicts_with_exported_declaration_of_0, declaration.identifier.range, internalName);
|
||||
else
|
||||
this.exports.set(internalName, ns);
|
||||
this.exports.set(internalName, namespace);
|
||||
}
|
||||
}
|
||||
const members: Statement[] = declaration.members;
|
||||
@ -544,12 +529,12 @@ export class Program extends DiagnosticEmitter {
|
||||
return typeArguments;
|
||||
}
|
||||
|
||||
resolveElement(expression: Expression, contextualFunction: FunctionInstance): Element | null {
|
||||
resolveElement(expression: Expression, contextualFunction: Function): Element | null {
|
||||
|
||||
// this
|
||||
if (expression.kind == NodeKind.THIS) {
|
||||
if (contextualFunction.instanceMethodOf)
|
||||
return contextualFunction.instanceMethodOf.template;
|
||||
return contextualFunction.instanceMethodOf;
|
||||
this.error(DiagnosticCode._this_cannot_be_referenced_in_current_location, expression.range);
|
||||
return null;
|
||||
}
|
||||
@ -566,22 +551,31 @@ export class Program extends DiagnosticEmitter {
|
||||
const programGlobalElement: Element | null = <Element | null>this.elements.get(name);
|
||||
if (programGlobalElement)
|
||||
return programGlobalElement;
|
||||
this.error(DiagnosticCode.Cannot_find_name_0, expression.range, name);
|
||||
return null;
|
||||
|
||||
// static or instance property (incl. enum values) or method
|
||||
} else if (expression.kind == NodeKind.PROPERTYACCESS) {
|
||||
const target: Element | null = this.resolveElement((<PropertyAccessExpression>expression).expression, contextualFunction);
|
||||
const target: Element | null = this.resolveElement((<PropertyAccessExpression>expression).expression, contextualFunction); // reports
|
||||
let member: Element | null = null;
|
||||
if (!target)
|
||||
return null;
|
||||
switch (target.kind) {
|
||||
case ElementKind.CLASS:
|
||||
case ElementKind.ENUM:
|
||||
case ElementKind.NAMESPACE:
|
||||
}
|
||||
// TODO
|
||||
const propertyName: string = (<PropertyAccessExpression>expression).property.name;
|
||||
if (target.kind == ElementKind.ENUM)
|
||||
member = <EnumValue | null>(<Enum>target).members.get(propertyName);
|
||||
else if (target.kind == ElementKind.CLASS_PROTOTYPE)
|
||||
member = <Element | null>(<ClassPrototype>target).members.get(propertyName);
|
||||
else if (target.kind == ElementKind.CLASS)
|
||||
member = <Element | null>(<Class>target).members.get(propertyName);
|
||||
else if (target.kind == ElementKind.NAMESPACE)
|
||||
member = <Element | null>(<Namespace>target).members.get(propertyName);
|
||||
if (member)
|
||||
return member;
|
||||
this.error(DiagnosticCode.Property_0_does_not_exist_on_type_1, expression.range, (<PropertyAccessExpression>expression).property.name, target.internalName);
|
||||
return null;
|
||||
}
|
||||
|
||||
return null;
|
||||
throw new Error("not implemented: " + expression.kind);
|
||||
}
|
||||
}
|
||||
|
||||
@ -603,25 +597,29 @@ function checkGlobalDecorator(decorators: DecoratorStatement[]): string | null {
|
||||
}
|
||||
|
||||
export enum ElementKind {
|
||||
CLASS_PROTOTYPE,
|
||||
CLASS,
|
||||
CLASSINSTANCE,
|
||||
ENUM,
|
||||
ENUMVALUE,
|
||||
FIELD_PROTOTYPE,
|
||||
FIELD,
|
||||
FUNCTION_PROTOTYPE,
|
||||
FUNCTION,
|
||||
FUNCTIONINSTANCE,
|
||||
GLOBAL,
|
||||
INTERFACE_PROTOTYPE,
|
||||
INTERFACE,
|
||||
INTERFACEINSTANCE,
|
||||
LOCAL,
|
||||
NAMESPACE
|
||||
}
|
||||
|
||||
/** Base class of all program elements. */
|
||||
export abstract class Element {
|
||||
|
||||
kind: ElementKind;
|
||||
program: Program;
|
||||
internalName: string;
|
||||
globalExportName: string | null = null;
|
||||
compiled: bool = false;
|
||||
|
||||
constructor(program: Program, internalName: string) {
|
||||
this.program = program;
|
||||
@ -629,59 +627,7 @@ export abstract class Element {
|
||||
}
|
||||
}
|
||||
|
||||
export class Enum extends Element {
|
||||
|
||||
kind = ElementKind.ENUM;
|
||||
declaration: EnumDeclaration | null;
|
||||
members: Map<string,EnumValue> = new Map();
|
||||
compiled: bool = false;
|
||||
|
||||
constructor(program: Program, internalName: string, declaration: EnumDeclaration | null = null) {
|
||||
super(program, internalName);
|
||||
this.declaration = declaration;
|
||||
}
|
||||
|
||||
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't exports */ false; }
|
||||
get isGlobalExport(): bool { return this.globalExportName != null; }
|
||||
get isConstant(): bool { return this.declaration ? hasModifier(ModifierKind.CONST, this.declaration.modifiers) : /* internals are const */ true; }
|
||||
}
|
||||
|
||||
export class EnumValue extends Element {
|
||||
|
||||
kind = ElementKind.ENUMVALUE;
|
||||
declaration: EnumValueDeclaration | null;
|
||||
enum: Enum;
|
||||
hasConstantValue: bool = false;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
export class Global extends Element {
|
||||
|
||||
kind = ElementKind.GLOBAL;
|
||||
declaration: VariableLikeDeclarationStatement | null;
|
||||
type: Type | null;
|
||||
hasConstantValue: bool = false;
|
||||
constantIntegerValue: I64 = new I64(0, 0);
|
||||
constantFloatValue: f64 = 0;
|
||||
compiled: bool = false;
|
||||
|
||||
constructor(program: Program, internalName: string, declaration: VariableLikeDeclarationStatement | null, type: Type | null) {
|
||||
super(program, internalName);
|
||||
if (!(this.declaration = declaration)) this.hasConstantValue = true;
|
||||
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 isGlobalExport(): bool { return this.globalExportName != null; }
|
||||
get isMutable(): bool { return this.declaration ? hasModifier(ModifierKind.CONST, this.declaration.modifiers) : /* internals are immutable */ false; }
|
||||
}
|
||||
|
||||
/** A namespace. Also the base class of other namespace-like program elements. */
|
||||
export class Namespace extends Element {
|
||||
|
||||
kind = ElementKind.NAMESPACE;
|
||||
@ -697,6 +643,61 @@ export class Namespace extends Element {
|
||||
get isGlobalExport(): bool { return this.declaration ? this.globalExportName != null : /* internals aren't exports */ false; }
|
||||
}
|
||||
|
||||
/** An enum. */
|
||||
export class Enum extends Namespace {
|
||||
|
||||
kind = ElementKind.ENUM;
|
||||
declaration: EnumDeclaration | null;
|
||||
members: Map<string,EnumValue> = new Map(); // more specific
|
||||
|
||||
constructor(program: Program, internalName: string, declaration: EnumDeclaration | null = null) {
|
||||
super(program, internalName, null);
|
||||
this.declaration = declaration;
|
||||
}
|
||||
|
||||
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't exports */ false; }
|
||||
get isGlobalExport(): bool { return this.globalExportName != null; }
|
||||
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: EnumValueDeclaration | null;
|
||||
enum: Enum;
|
||||
hasConstantValue: bool;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
/** A global variable. */
|
||||
export class Global extends Element {
|
||||
|
||||
kind = ElementKind.GLOBAL;
|
||||
declaration: VariableLikeDeclarationStatement | null;
|
||||
type: Type | null;
|
||||
hasConstantValue: bool = false;
|
||||
constantIntegerValue: I64 | null = null;
|
||||
constantFloatValue: f64 = 0;
|
||||
|
||||
constructor(program: Program, internalName: string, declaration: VariableLikeDeclarationStatement | null, type: Type | null) {
|
||||
super(program, internalName);
|
||||
if (!(this.declaration = declaration)) this.hasConstantValue = true;
|
||||
this.type = type; // resolved later if `null`, also updates constantKind
|
||||
}
|
||||
|
||||
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't exports */ false; }
|
||||
get isGlobalExport(): bool { return this.globalExportName != null; }
|
||||
get isMutable(): bool { return this.declaration ? hasModifier(ModifierKind.CONST, this.declaration.modifiers) : /* internals are immutable */ false; }
|
||||
}
|
||||
|
||||
/** A function parameter. */
|
||||
export class Parameter {
|
||||
|
||||
name: string;
|
||||
@ -708,6 +709,7 @@ export class Parameter {
|
||||
}
|
||||
}
|
||||
|
||||
/** A function local. */
|
||||
export class Local extends Element {
|
||||
|
||||
kind = ElementKind.LOCAL;
|
||||
@ -721,28 +723,31 @@ export class Local extends Element {
|
||||
}
|
||||
}
|
||||
|
||||
export class FunctionTemplate extends Element {
|
||||
/** A yet unresolved function prototype. */
|
||||
export class FunctionPrototype extends Element {
|
||||
|
||||
kind = ElementKind.FUNCTION;
|
||||
kind = ElementKind.FUNCTION_PROTOTYPE;
|
||||
declaration: FunctionDeclaration | null;
|
||||
instances: Map<string,FunctionInstance>;
|
||||
classPrototype: ClassPrototype | null;
|
||||
instances: Map<string,Function> = new Map();
|
||||
isGeneric: bool;
|
||||
|
||||
constructor(program: Program, internalName: string, declaration: FunctionDeclaration | null) {
|
||||
constructor(program: Program, internalName: string, declaration: FunctionDeclaration | null, classPrototype: ClassPrototype | null = null) {
|
||||
super(program, internalName);
|
||||
this.declaration = declaration;
|
||||
this.instances = new Map();
|
||||
this.classPrototype = classPrototype;
|
||||
this.isGeneric = declaration ? declaration.typeParameters.length > 0 : false; // builtins set this
|
||||
}
|
||||
|
||||
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't file-level exports */ false; }
|
||||
get isGlobalExport(): bool { return this.declaration ? this.globalExportName != null : /* internals aren't global 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; }
|
||||
|
||||
instantiate(typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null): FunctionInstance | null {
|
||||
resolve(typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null): Function | null {
|
||||
const instanceKey: string = typesToString(typeArguments, "", "");
|
||||
let instance: FunctionInstance | null = <FunctionInstance | null>this.instances.get(instanceKey);
|
||||
let instance: Function | null = <Function | null>this.instances.get(instanceKey);
|
||||
if (instance)
|
||||
return instance;
|
||||
const declaration: FunctionDeclaration | null = this.declaration;
|
||||
@ -793,31 +798,31 @@ export class FunctionTemplate extends Element {
|
||||
let internalName: string = this.internalName;
|
||||
if (instanceKey.length)
|
||||
internalName += "<" + instanceKey + ">";
|
||||
instance = new FunctionInstance(this, internalName, typeArguments, parameters, returnType, null); // TODO: class
|
||||
instance = new Function(this, internalName, typeArguments, parameters, returnType, null); // TODO: class
|
||||
this.instances.set(instanceKey, instance);
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
export class FunctionInstance extends Element {
|
||||
/** A resolved function. */
|
||||
export class Function extends Element {
|
||||
|
||||
kind = ElementKind.FUNCTIONINSTANCE;
|
||||
template: FunctionTemplate;
|
||||
kind = ElementKind.FUNCTION;
|
||||
template: FunctionPrototype;
|
||||
typeArguments: Type[];
|
||||
parameters: Parameter[];
|
||||
returnType: Type;
|
||||
instanceMethodOf: ClassInstance | null;
|
||||
instanceMethodOf: Class | null;
|
||||
locals: Map<string,Local> = new Map();
|
||||
additionalLocals: Type[] = [];
|
||||
additionalLocals: Type[] = []; // without parameters
|
||||
breakContext: string | null = null;
|
||||
compiled: bool = false;
|
||||
|
||||
contextualTypeArguments: Map<string,Type> = new Map();
|
||||
|
||||
private breakMajor: i32 = 0;
|
||||
private breakMinor: i32 = 0;
|
||||
|
||||
constructor(template: FunctionTemplate, internalName: string, typeArguments: Type[], parameters: Parameter[], returnType: Type, instanceMethodOf: ClassInstance | null) {
|
||||
constructor(template: FunctionPrototype, internalName: string, typeArguments: Type[], parameters: Parameter[], returnType: Type, instanceMethodOf: Class | null) {
|
||||
super(template.program, internalName);
|
||||
this.template = template;
|
||||
this.typeArguments = typeArguments;
|
||||
@ -866,20 +871,50 @@ export class FunctionInstance extends Element {
|
||||
}
|
||||
}
|
||||
|
||||
export class ClassTemplate extends Namespace {
|
||||
/** A yet unresolved instance field prototype. */
|
||||
export class FieldPrototype extends Element {
|
||||
|
||||
kind = ElementKind.CLASS;
|
||||
kind = ElementKind.FIELD_PROTOTYPE;
|
||||
declaration: FieldDeclaration | null;
|
||||
classPrototype: ClassPrototype;
|
||||
|
||||
constructor(classPrototype: ClassPrototype, internalName: string, declaration: FieldDeclaration | null) {
|
||||
super(classPrototype.program, internalName);
|
||||
this.classPrototype = classPrototype;
|
||||
}
|
||||
|
||||
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't file-level exports */ false; }
|
||||
get isGlobalExport(): bool { return this.declaration ? this.globalExportName != null : /* internals aren't global exports */ false; }
|
||||
}
|
||||
|
||||
/** A resolved instance field. */
|
||||
export class Field extends Element {
|
||||
|
||||
kind = ElementKind.FIELD;
|
||||
template: FieldPrototype;
|
||||
type: Type;
|
||||
hasConstantValue: bool = false;
|
||||
constantIntegerValue: I64 | null = null;
|
||||
constantFloatValue: f64 = 0;
|
||||
|
||||
constructor(template: FieldPrototype, internalName: string, type: Type) {
|
||||
super(template.program, internalName);
|
||||
if (!this.template.declaration) this.hasConstantValue = true;
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
/** A yet unresolved class prototype. */
|
||||
export class ClassPrototype extends Namespace {
|
||||
|
||||
kind = ElementKind.CLASS_PROTOTYPE;
|
||||
declaration: ClassDeclaration | null;
|
||||
fieldDeclarations: Map<string,FieldDeclaration>;
|
||||
methodDeclarations: Map<string,MethodDeclaration>;
|
||||
instances: Map<string,ClassInstance>;
|
||||
instances: Map<string,Class>;
|
||||
isGeneric: bool;
|
||||
|
||||
constructor(program: Program, internalName: string, declaration: ClassDeclaration | null = null) {
|
||||
super(program, internalName, null);
|
||||
this.declaration = declaration;
|
||||
this.fieldDeclarations = new Map();
|
||||
this.methodDeclarations = new Map();
|
||||
this.instances = new Map();
|
||||
this.isGeneric = declaration ? declaration.typeParameters.length > 0 : false; // builtins can set this
|
||||
}
|
||||
@ -887,9 +922,9 @@ export class ClassTemplate extends Namespace {
|
||||
get isExport(): bool { return this.declaration ? hasModifier(ModifierKind.EXPORT, this.declaration.modifiers) : /* internals aren't file-level exports */ false; }
|
||||
get isGlobalExport(): bool { return this.declaration ? this.globalExportName != null : /* internals aren't global exports */ false; }
|
||||
|
||||
instantiate(typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null): ClassInstance {
|
||||
resolve(typeArguments: Type[], contextualTypeArguments: Map<string,Type> | null): Class {
|
||||
const key: string = typesToString(typeArguments, "", "");
|
||||
let instance: ClassInstance | null = <ClassInstance | null>this.instances.get(key);
|
||||
let instance: Class | null = <Class | null>this.instances.get(key);
|
||||
if (instance)
|
||||
return instance;
|
||||
if (!this.declaration)
|
||||
@ -898,19 +933,20 @@ export class ClassTemplate extends Namespace {
|
||||
}
|
||||
}
|
||||
|
||||
export class ClassInstance extends Element {
|
||||
/** A resolved class. */
|
||||
export class Class extends Namespace {
|
||||
|
||||
kind = ElementKind.CLASSINSTANCE;
|
||||
template: ClassTemplate;
|
||||
kind = ElementKind.CLASS;
|
||||
declaration: ClassDeclaration | null;
|
||||
template: ClassPrototype;
|
||||
typeArguments: Type[];
|
||||
base: ClassInstance | null;
|
||||
base: Class | null;
|
||||
type: Type;
|
||||
compiled: bool = false;
|
||||
|
||||
contextualTypeArguments: Map<string,Type> = new Map();
|
||||
|
||||
constructor(template: ClassTemplate, internalName: string, typeArguments: Type[], base: ClassInstance | null) {
|
||||
super(template.program, internalName);
|
||||
constructor(template: ClassPrototype, internalName: string, typeArguments: Type[], base: Class | null) {
|
||||
super(template.program, internalName, template.declaration);
|
||||
this.template = template;
|
||||
this.typeArguments = typeArguments;
|
||||
this.base = base;
|
||||
@ -933,9 +969,10 @@ export class ClassInstance extends Element {
|
||||
}
|
||||
}
|
||||
|
||||
export class InterfaceTemplate extends ClassTemplate {
|
||||
/** A yet unresvoled interface. */
|
||||
export class InterfacePrototype extends ClassPrototype {
|
||||
|
||||
kind = ElementKind.INTERFACE;
|
||||
kind = ElementKind.INTERFACE_PROTOTYPE;
|
||||
declaration: InterfaceDeclaration | null;
|
||||
|
||||
constructor(program: Program, internalName: string, declaration: InterfaceDeclaration | null) {
|
||||
@ -943,12 +980,14 @@ export class InterfaceTemplate extends ClassTemplate {
|
||||
}
|
||||
}
|
||||
|
||||
export class InterfaceInstance extends ClassInstance {
|
||||
/** A resolved interface. */
|
||||
export class Interface extends Class {
|
||||
|
||||
kind = ElementKind.INTERFACEINSTANCE;
|
||||
base: InterfaceInstance | null;
|
||||
kind = ElementKind.INTERFACE;
|
||||
template: InterfacePrototype;
|
||||
base: Interface | null;
|
||||
|
||||
constructor(template: InterfaceTemplate, internalName: string, typeArguments: Type[], base: InterfaceInstance | null) {
|
||||
constructor(template: InterfacePrototype, internalName: string, typeArguments: Type[], base: Interface | null) {
|
||||
super(template, internalName, typeArguments, base);
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
"compiler.ts",
|
||||
"diagnosticMessages.generated.ts",
|
||||
"diagnostics.ts",
|
||||
"evaluator.ts",
|
||||
"glue/js.d.ts",
|
||||
"glue/js.ts",
|
||||
"index.ts",
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { ClassInstance } from "./program";
|
||||
import { Class } from "./program";
|
||||
import { sb } from "./util";
|
||||
|
||||
export const enum TypeKind {
|
||||
@ -29,7 +29,7 @@ export class Type {
|
||||
|
||||
kind: TypeKind;
|
||||
size: i32;
|
||||
classType: ClassInstance | null;
|
||||
classType: Class | null;
|
||||
nullable: bool = false;
|
||||
nullableType: Type | null = null; // cached, of this type
|
||||
|
||||
@ -50,7 +50,7 @@ export class Type {
|
||||
get isAnySize(): bool { return this.kind == TypeKind.ISIZE || this.kind == TypeKind.USIZE; }
|
||||
get isAnyFloat(): bool { return this.kind == TypeKind.F32 || this.kind == TypeKind.F64; }
|
||||
|
||||
asClass(classType: ClassInstance): Type {
|
||||
asClass(classType: Class): Type {
|
||||
const ret: Type = new Type(this.kind, this.size);
|
||||
ret.classType = classType;
|
||||
return ret;
|
||||
|
@ -1,7 +1,4 @@
|
||||
export { CharCode, isLineBreak} from "./util/charcode";
|
||||
|
||||
export { I64, U64 } from "./util/i64";
|
||||
|
||||
export { normalize as normalizePath, resolve as resolvePath, dirname } from "./util/path";
|
||||
|
||||
export const sb: string[] = new Array(256); // shared string builder. 64-bit without growing: (4+4+8) + 8*256 = 16b + 2kb
|
||||
|
@ -30,6 +30,10 @@ const files: Map<string,string> = new Map([
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
import { sub } from "../other";
|
||||
export function what(): void {
|
||||
sub(1,2);
|
||||
}
|
||||
`],
|
||||
|
||||
["../other",
|
||||
@ -54,6 +58,7 @@ do {
|
||||
const program = parser.finish();
|
||||
const compiler = new Compiler(program);
|
||||
const module = compiler.compile();
|
||||
console.log(program.elements.keys());
|
||||
|
||||
// module.optimize();
|
||||
module.validate();
|
||||
|
@ -1,6 +1,6 @@
|
||||
import "../src/glue/js";
|
||||
import { Tokenizer, Token } from "../src/tokenizer";
|
||||
import { Source } from "../src/reflection";
|
||||
import { Source } from "../src/ast";
|
||||
import * as fs from "fs";
|
||||
|
||||
const text = fs.readFileSync(__dirname + "/../src/tokenizer.ts").toString();
|
||||
|
Loading…
x
Reference in New Issue
Block a user