This commit is contained in:
dcodeIO 2017-11-26 04:03:28 +01:00
parent dc74dd118d
commit df637164a6
10 changed files with 279 additions and 520 deletions

View File

@ -351,8 +351,6 @@ export abstract class Expression extends Node {
(expr.expression = expression).parent = expr; (expr.expression = expression).parent = expr;
return expr; return expr;
} }
abstract serializeAsTree(sb: string[], indent: i32): void;
} }
export const enum LiteralKind { export const enum LiteralKind {
@ -384,20 +382,6 @@ export class ArrayLiteralExpression extends LiteralExpression {
} }
sb.push("]"); sb.push("]");
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
pushIndent(sb, indent++);
sb.push("[\n");
for (let i: i32 = 0, k: i32 = this.elementExpressions.length; i < k; ++i) {
pushIndent(sb, indent);
if (i > 0)
sb.push(",\n");
if (this.elementExpressions[i])
(<Expression>this.elementExpressions[i]).serialize(sb);
}
pushIndent(sb, --indent);
sb.push("]");
}
} }
export const enum AssertionKind { export const enum AssertionKind {
@ -424,24 +408,6 @@ export class AssertionExpression extends Expression {
this.toType.serialize(sb); this.toType.serialize(sb);
} }
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
if (this.assertionKind == AssertionKind.PREFIX) {
pushIndent(sb, indent);
sb.push("<");
this.toType.serialize(sb);
sb.push(">\n");
this.expression.serializeAsTree(sb, indent + 1);
} else {
this.expression.serializeAsTree(sb, indent + 1);
sb.push("\n");
pushIndent(sb, indent);
sb.push("as\n");
pushIndent(sb, indent + 1);
this.toType.serialize(sb);
}
sb.push("\n");
}
} }
export class BinaryExpression extends Expression { export class BinaryExpression extends Expression {
@ -458,14 +424,6 @@ export class BinaryExpression extends Expression {
sb.push(" "); sb.push(" ");
this.right.serialize(sb); this.right.serialize(sb);
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
this.left.serializeAsTree(sb, indent + 1);
pushIndent(sb, indent);
sb.push(operatorTokenToString(this.operator));
sb.push("\n");
this.right.serializeAsTree(sb, indent + 1);
}
} }
export class CallExpression extends Expression { export class CallExpression extends Expression {
@ -495,12 +453,6 @@ export class CallExpression extends Expression {
} }
sb.push(")"); sb.push(")");
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
pushIndent(sb, indent);
this.serialize(sb); // not interested in a tree here
sb.push("\n");
}
} }
export class ElementAccessExpression extends Expression { export class ElementAccessExpression extends Expression {
@ -515,15 +467,6 @@ export class ElementAccessExpression extends Expression {
this.elementExpression.serialize(sb); this.elementExpression.serialize(sb);
sb.push("]"); sb.push("]");
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
this.expression.serializeAsTree(sb, indent);
pushIndent(sb, indent);
sb.push("[\n");
this.elementExpression.serializeAsTree(sb, indent + 1);
pushIndent(sb, indent);
sb.push("]\n");
}
} }
export class FloatLiteralExpression extends LiteralExpression { export class FloatLiteralExpression extends LiteralExpression {
@ -534,12 +477,6 @@ export class FloatLiteralExpression extends LiteralExpression {
serialize(sb: string[]): void { serialize(sb: string[]): void {
sb.push(this.value.toString()); sb.push(this.value.toString());
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
pushIndent(sb, indent);
this.serialize(sb);
sb.push("\n");
}
} }
export class IdentifierExpression extends Expression { export class IdentifierExpression extends Expression {
@ -550,12 +487,6 @@ export class IdentifierExpression extends Expression {
serialize(sb: string[]): void { serialize(sb: string[]): void {
sb.push(this.name); sb.push(this.name);
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
pushIndent(sb, indent);
this.serialize(sb);
sb.push("\n");
}
} }
export class IntegerLiteralExpression extends LiteralExpression { export class IntegerLiteralExpression extends LiteralExpression {
@ -566,12 +497,6 @@ export class IntegerLiteralExpression extends LiteralExpression {
serialize(sb: string[]): void { serialize(sb: string[]): void {
sb.push(this.value.toString()); sb.push(this.value.toString());
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
pushIndent(sb, indent);
this.serialize(sb);
sb.push("\n");
}
} }
export class NewExpression extends CallExpression { export class NewExpression extends CallExpression {
@ -582,12 +507,6 @@ export class NewExpression extends CallExpression {
sb.push("new "); sb.push("new ");
super.serialize(sb); super.serialize(sb);
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
pushIndent(sb, indent);
this.serialize(sb); // not interested in a tree here
sb.push("\n");
}
} }
export class NullExpression extends IdentifierExpression { export class NullExpression extends IdentifierExpression {
@ -605,14 +524,6 @@ export class ParenthesizedExpression extends Expression {
this.expression.serialize(sb); this.expression.serialize(sb);
sb.push(")"); sb.push(")");
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
pushIndent(sb, indent);
sb.push("(\n");
this.expression.serializeAsTree(sb, indent + 1);
pushIndent(sb, indent);
sb.push(")\n");
}
} }
export class PropertyAccessExpression extends Expression { export class PropertyAccessExpression extends Expression {
@ -626,12 +537,6 @@ export class PropertyAccessExpression extends Expression {
sb.push("."); sb.push(".");
this.property.serialize(sb); this.property.serialize(sb);
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
pushIndent(sb, indent);
this.serialize(sb); // not interested in a tree here
sb.push("\n");
}
} }
export class RegexpLiteralExpression extends LiteralExpression { export class RegexpLiteralExpression extends LiteralExpression {
@ -642,12 +547,6 @@ export class RegexpLiteralExpression extends LiteralExpression {
serialize(sb: string[]): void { serialize(sb: string[]): void {
sb.push(this.value); sb.push(this.value);
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
pushIndent(sb, indent);
this.serialize(sb);
sb.push("\n");
}
} }
export class SelectExpression extends Expression { export class SelectExpression extends Expression {
@ -664,16 +563,6 @@ export class SelectExpression extends Expression {
sb.push(" : "); sb.push(" : ");
this.ifElse.serialize(sb); this.ifElse.serialize(sb);
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
this.condition.serializeAsTree(sb, indent + 1);
pushIndent(sb, indent);
sb.push("?\n");
this.ifThen.serializeAsTree(sb, indent + 1);
pushIndent(sb, indent);
sb.push(":\n");
this.ifElse.serializeAsTree(sb, indent + 1);
}
} }
export class StringLiteralExpression extends LiteralExpression { export class StringLiteralExpression extends LiteralExpression {
@ -684,12 +573,6 @@ export class StringLiteralExpression extends LiteralExpression {
serialize(sb: string[]): void { serialize(sb: string[]): void {
sb.push(JSON.stringify(this.value)); sb.push(JSON.stringify(this.value));
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
pushIndent(sb, indent);
this.serialize(sb);
sb.push("\n");
}
} }
export class SuperExpression extends IdentifierExpression { export class SuperExpression extends IdentifierExpression {
@ -729,17 +612,6 @@ export class UnaryPostfixExpression extends UnaryExpression {
default: sb.push("INVALID"); break; default: sb.push("INVALID"); break;
} }
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
this.expression.serializeAsTree(sb, indent + 1);
pushIndent(sb, indent);
switch (this.operator) {
case Token.PLUS_PLUS: sb.push("++"); break;
case Token.MINUS_MINUS: sb.push("--"); break;
default: sb.push("INVALID"); break;
}
sb.push("\n");
}
} }
export class UnaryPrefixExpression extends UnaryExpression { export class UnaryPrefixExpression extends UnaryExpression {
@ -750,13 +622,6 @@ export class UnaryPrefixExpression extends UnaryExpression {
sb.push(operatorTokenToString(this.operator)); sb.push(operatorTokenToString(this.operator));
this.expression.serialize(sb); this.expression.serialize(sb);
} }
serializeAsTree(sb: string[], indent: i32 = 0): void {
pushIndent(sb, indent);
sb.push(operatorTokenToString(this.operator));
sb.push("\n");
this.expression.serializeAsTree(sb, indent + 1);
}
} }
// statements // statements
@ -1937,8 +1802,3 @@ function builderEndsWith(sb: string[], code: CharCode): bool {
} }
return false; return false;
} }
function pushIndent(sb: string[], indent: i32): void {
for (let i: i32 = 0; i < indent; ++i)
sb.push(" ");
}

View File

@ -1,6 +1,6 @@
import { Module, MemorySegment, UnaryOp, BinaryOp, HostOp, Type as BinaryenType, Relooper } from "./binaryen";
import { PATH_DELIMITER } from "./constants"; import { PATH_DELIMITER } from "./constants";
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics"; import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
import { Module, ModuleRef, MemorySegment, ExpressionRef, UnaryOp, BinaryOp, HostOp, NativeType, FunctionTypeRef, FunctionRef, ImportRef, ExportRef, GlobalRef, Relooper } from "./module";
import { Program, ClassPrototype, Class, Element, ElementKind, Enum, FunctionPrototype, Function, Global, Local, Namespace, Parameter } from "./program"; import { Program, ClassPrototype, Class, Element, ElementKind, Enum, FunctionPrototype, Function, Global, Local, Namespace, Parameter } from "./program";
import { CharCode, I64, U64, normalizePath, sb } from "./util"; import { CharCode, I64, U64, normalizePath, sb } from "./util";
import { Token, Range } from "./tokenizer"; import { Token, Range } from "./tokenizer";
@ -77,14 +77,14 @@ import {
export enum Target { export enum Target {
/** WebAssembly with 32-bit pointers. */ /** WebAssembly with 32-bit pointers. */
WASM32, WASM32,
/** WebAssembly with 64-bit pointers. Experimental / not supported by any runtime yet. */ /** WebAssembly with 64-bit pointers. Experimental and not supported by any runtime yet. */
WASM64 WASM64
} }
export class Options { export class Options {
/** WebAssembly target. Defaults to {@link Target.WASM32}. */ /** WebAssembly target. Defaults to {@link Target.WASM32}. */
target: Target = Target.WASM32; target: Target = Target.WASM32;
/** If true, performs compilation as usual but doesn't produce any output (all calls to Binaryen become nops). */ /** If true, performs compilation as usual but doesn't produce any output (all calls to module become nops). */
noEmit: bool = false; noEmit: bool = false;
/** If true, compiles everything instead of just reachable code. */ /** If true, compiles everything instead of just reachable code. */
noTreeShaking: bool = false; noTreeShaking: bool = false;
@ -92,27 +92,40 @@ export class Options {
export class Compiler extends DiagnosticEmitter { export class Compiler extends DiagnosticEmitter {
/** Program reference. */
program: Program; program: Program;
/** Provided options. */
options: Options; options: Options;
/** Module instance being compiled. */
module: Module; module: Module;
/** Start function being compiled. */
startFunction: Function; startFunction: Function;
startFunctionBody: BinaryenExpressionRef[] = new Array(); /** Start function expressions. */
startFunctionBody: ExpressionRef[] = new Array();
/** Current type in compilation. */
currentType: Type = Type.void; currentType: Type = Type.void;
/** Current function in compilation. */
currentFunction: Function; currentFunction: Function;
/** Marker indicating whether continue statements are allowed in the current break context. */
disallowContinue: bool = true; disallowContinue: bool = true;
/** Counting memory offset. */
memoryOffset: U64 = new U64(8, 0); // leave space for (any size of) NULL memoryOffset: U64 = new U64(8, 0); // leave space for (any size of) NULL
/** Memory segments being compiled. */
memorySegments: MemorySegment[] = new Array(); memorySegments: MemorySegment[] = new Array();
/** Already processed file names. */
files: Set<string> = new Set(); files: Set<string> = new Set();
/** Compiles a {@link Program} to a {@link Module} using the specified options. */
static compile(program: Program, options: Options | null = null): Module { static compile(program: Program, options: Options | null = null): Module {
const compiler: Compiler = new Compiler(program, options); const compiler: Compiler = new Compiler(program, options);
return compiler.compile(); return compiler.compile();
} }
/** Constructs a new compiler for a {@link Program} using the specified options. */
constructor(program: Program, options: Options | null = null) { constructor(program: Program, options: Options | null = null) {
super(program.diagnostics); super(program.diagnostics);
this.program = program; this.program = program;
@ -124,6 +137,7 @@ export class Compiler extends DiagnosticEmitter {
this.memoryOffset = new U64(2 * (this.options.target == Target.WASM64 ? 8 : 4), 0); // leave space for `null` and heapStart (both of usize type) this.memoryOffset = new U64(2 * (this.options.target == Target.WASM64 ? 8 : 4), 0); // leave space for `null` and heapStart (both of usize type)
} }
/** Performs compilation of the underlying {@link Program} to a {@link Module}. */
compile(): Module { compile(): Module {
const program: Program = this.program; const program: Program = this.program;
@ -141,11 +155,11 @@ export class Compiler extends DiagnosticEmitter {
// make start function if not empty // make start function if not empty
if (this.startFunctionBody.length) { if (this.startFunctionBody.length) {
let typeRef: BinaryenFunctionTypeRef = this.module.getFunctionTypeBySignature(BinaryenType.None, []); let typeRef: FunctionTypeRef = this.module.getFunctionTypeBySignature(NativeType.None, []);
if (!typeRef) if (!typeRef)
typeRef = this.module.addFunctionType("v", BinaryenType.None, []); typeRef = this.module.addFunctionType("v", NativeType.None, []);
this.module.setStart( this.module.setStart(
this.module.addFunction(this.startFunction.template.internalName, typeRef, typesToBinaryenTypes(this.startFunction.additionalLocals), this.module.createBlock(null, this.startFunctionBody)) this.module.addFunction(this.startFunction.template.internalName, typeRef, typesToNativeTypes(this.startFunction.additionalLocals), this.module.createBlock(null, this.startFunctionBody))
); );
} }
@ -285,8 +299,8 @@ export class Compiler extends DiagnosticEmitter {
return false; return false;
element.type = type; element.type = type;
} }
const binaryenType: BinaryenType = typeToBinaryenType(<Type>type); const nativeType: NativeType = typeToNativeType(<Type>type);
let initializer: BinaryenExpressionRef; let initializer: ExpressionRef;
let initializeInStart: bool; let initializeInStart: bool;
if (element.hasConstantValue) { if (element.hasConstantValue) {
if (type.isLongInteger) if (type.isLongInteger)
@ -304,23 +318,23 @@ export class Compiler extends DiagnosticEmitter {
} else } else
initializer = this.module.createI32(element.constantIntegerValue ? element.constantIntegerValue.toI32() : 0); initializer = this.module.createI32(element.constantIntegerValue ? element.constantIntegerValue.toI32() : 0);
initializeInStart = false; initializeInStart = false;
this.module.addGlobal(element.internalName, binaryenType, element.isMutable, initializer); this.module.addGlobal(element.internalName, nativeType, element.isMutable, initializer);
} else if (declaration) { } else if (declaration) {
if (declaration.initializer) { if (declaration.initializer) {
initializer = this.compileExpression(declaration.initializer, type); initializer = this.compileExpression(declaration.initializer, type);
initializeInStart = declaration.initializer.kind != NodeKind.LITERAL; // MVP doesn't support complex initializers initializeInStart = declaration.initializer.kind != NodeKind.LITERAL; // MVP doesn't support complex initializers
} else { } else {
initializer = typeToBinaryenZero(this.module, type); initializer = typeToNativeZero(this.module, type);
initializeInStart = false; initializeInStart = false;
} }
} else } else
throw new Error("unexpected missing declaration or constant value"); throw new Error("unexpected missing declaration or constant value");
const internalName: string = element.internalName; const internalName: string = element.internalName;
if (initializeInStart) { if (initializeInStart) {
this.module.addGlobal(internalName, BinaryenType.I32, true, this.module.createI32(-1)); this.module.addGlobal(internalName, NativeType.I32, true, this.module.createI32(-1));
this.startFunctionBody.push(this.module.createSetGlobal(internalName, initializer)); this.startFunctionBody.push(this.module.createSetGlobal(internalName, initializer));
} else } else
this.module.addGlobal(internalName, BinaryenType.I32, element.isMutable, initializer); this.module.addGlobal(internalName, NativeType.I32, element.isMutable, initializer);
return element.compiled = true; return element.compiled = true;
} }
@ -340,10 +354,10 @@ export class Compiler extends DiagnosticEmitter {
let previousInternalName: string | null = null; let previousInternalName: string | null = null;
for (let [key, val] of element.members) { for (let [key, val] of element.members) {
if (val.hasConstantValue) { if (val.hasConstantValue) {
this.module.addGlobal(val.internalName, BinaryenType.I32, false, this.module.createI32(val.constantValue)); this.module.addGlobal(val.internalName, NativeType.I32, false, this.module.createI32(val.constantValue));
} else if (val.declaration) { } else if (val.declaration) {
const declaration: EnumValueDeclaration = val.declaration; const declaration: EnumValueDeclaration = val.declaration;
let initializer: BinaryenExpressionRef; let initializer: ExpressionRef;
let initializeInStart: bool = false; let initializeInStart: bool = false;
if (declaration.value) { if (declaration.value) {
initializer = this.compileExpression(<Expression>declaration.value, Type.i32); initializer = this.compileExpression(<Expression>declaration.value, Type.i32);
@ -353,16 +367,16 @@ export class Compiler extends DiagnosticEmitter {
initializeInStart = false; initializeInStart = false;
} else { } else {
initializer = this.module.createBinary(BinaryOp.AddI32, initializer = this.module.createBinary(BinaryOp.AddI32,
this.module.createGetGlobal(previousInternalName, BinaryenType.I32), this.module.createGetGlobal(previousInternalName, NativeType.I32),
this.module.createI32(1) this.module.createI32(1)
); );
initializeInStart = true; initializeInStart = true;
} }
if (initializeInStart) { if (initializeInStart) {
this.module.addGlobal(val.internalName, BinaryenType.I32, true, this.module.createI32(-1)); this.module.addGlobal(val.internalName, NativeType.I32, true, this.module.createI32(-1));
this.startFunctionBody.push(this.module.createSetGlobal(val.internalName, initializer)); this.startFunctionBody.push(this.module.createSetGlobal(val.internalName, initializer));
} else } else
this.module.addGlobal(val.internalName, BinaryenType.I32, false, initializer); this.module.addGlobal(val.internalName, NativeType.I32, false, initializer);
} else } else
throw new Error("unexpected missing declaration or constant value"); throw new Error("unexpected missing declaration or constant value");
previousInternalName = val.internalName; previousInternalName = val.internalName;
@ -403,24 +417,24 @@ export class Compiler extends DiagnosticEmitter {
// compile statements // compile statements
const previousFunction: Function = this.currentFunction; const previousFunction: Function = this.currentFunction;
this.currentFunction = instance; this.currentFunction = instance;
const stmts: BinaryenExpressionRef[] = this.compileStatements(<Statement[]>declaration.statements); const stmts: ExpressionRef[] = this.compileStatements(<Statement[]>declaration.statements);
this.currentFunction = previousFunction; this.currentFunction = previousFunction;
// create the function // create the function
let k: i32 = instance.parameters.length; let k: i32 = instance.parameters.length;
const binaryenResultType: BinaryenType = typeToBinaryenType(instance.returnType); const binaryenResultType: NativeType = typeToNativeType(instance.returnType);
const binaryenParamTypes: BinaryenType[] = new Array(k); const binaryenParamTypes: NativeType[] = new Array(k);
const signatureNameParts: string[] = new Array(k + 1); const signatureNameParts: string[] = new Array(k + 1);
for (let i: i32 = 0; i < k; ++i) { for (let i: i32 = 0; i < k; ++i) {
binaryenParamTypes[i] = typeToBinaryenType(instance.parameters[i].type); binaryenParamTypes[i] = typeToNativeType(instance.parameters[i].type);
signatureNameParts[i] = typeToSignatureNamePart(instance.parameters[i].type); signatureNameParts[i] = typeToSignatureNamePart(instance.parameters[i].type);
} }
signatureNameParts[k] = typeToSignatureNamePart(instance.returnType); signatureNameParts[k] = typeToSignatureNamePart(instance.returnType);
let binaryenTypeRef: BinaryenFunctionTypeRef = this.module.getFunctionTypeBySignature(binaryenResultType, binaryenParamTypes); let typeRef: FunctionTypeRef = this.module.getFunctionTypeBySignature(binaryenResultType, binaryenParamTypes);
if (!binaryenTypeRef) if (!typeRef)
binaryenTypeRef = this.module.addFunctionType(signatureNameParts.join(""), binaryenResultType, binaryenParamTypes); typeRef = this.module.addFunctionType(signatureNameParts.join(""), binaryenResultType, binaryenParamTypes);
const internalName: string = instance.internalName; const internalName: string = instance.internalName;
this.module.addFunction(internalName, binaryenTypeRef, typesToBinaryenTypes(instance.additionalLocals), this.module.createBlock(null, stmts, BinaryenType.None)); this.module.addFunction(internalName, typeRef, typesToNativeTypes(instance.additionalLocals), this.module.createBlock(null, stmts, NativeType.None));
if (instance.globalExportName != null) if (instance.globalExportName != null)
this.module.addExport(internalName, <string>instance.globalExportName); this.module.addExport(internalName, <string>instance.globalExportName);
} }
@ -583,7 +597,7 @@ export class Compiler extends DiagnosticEmitter {
// statements // statements
compileStatement(statement: Statement): BinaryenExpressionRef { compileStatement(statement: Statement): ExpressionRef {
switch (statement.kind) { switch (statement.kind) {
case NodeKind.BLOCK: case NodeKind.BLOCK:
@ -631,19 +645,19 @@ export class Compiler extends DiagnosticEmitter {
throw new Error("unexpected statement kind"); throw new Error("unexpected statement kind");
} }
compileStatements(statements: Statement[]): BinaryenExpressionRef[] { compileStatements(statements: Statement[]): ExpressionRef[] {
const k: i32 = statements.length; const k: i32 = statements.length;
const stmts: BinaryenExpressionRef[] = new Array(k); const stmts: ExpressionRef[] = new Array(k);
for (let i: i32 = 0; i < k; ++i) for (let i: i32 = 0; i < k; ++i)
stmts[i] = this.compileStatement(statements[i]); stmts[i] = this.compileStatement(statements[i]);
return stmts; return stmts;
} }
compileBlockStatement(statement: BlockStatement): BinaryenExpressionRef { compileBlockStatement(statement: BlockStatement): ExpressionRef {
return this.module.createBlock(null, this.compileStatements(statement.statements), BinaryenType.None); return this.module.createBlock(null, this.compileStatements(statement.statements), NativeType.None);
} }
compileBreakStatement(statement: BreakStatement): BinaryenExpressionRef { compileBreakStatement(statement: BreakStatement): ExpressionRef {
if (statement.label) if (statement.label)
throw new Error("not implemented"); throw new Error("not implemented");
const context: string | null = this.currentFunction.breakContext; const context: string | null = this.currentFunction.breakContext;
@ -653,7 +667,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
compileContinueStatement(statement: ContinueStatement): BinaryenExpressionRef { compileContinueStatement(statement: ContinueStatement): ExpressionRef {
if (statement.label) if (statement.label)
throw new Error("not implemented"); throw new Error("not implemented");
const context: string | null = this.currentFunction.breakContext; const context: string | null = this.currentFunction.breakContext;
@ -663,10 +677,10 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
compileDoStatement(statement: DoStatement): BinaryenExpressionRef { compileDoStatement(statement: DoStatement): ExpressionRef {
const label: string = this.currentFunction.enterBreakContext(); const label: string = this.currentFunction.enterBreakContext();
const condition: BinaryenExpressionRef = this.compileExpression(statement.condition, Type.i32); const condition: ExpressionRef = this.compileExpression(statement.condition, Type.i32);
const body: BinaryenExpressionRef = this.compileStatement(statement.statement); const body: ExpressionRef = this.compileStatement(statement.statement);
this.currentFunction.leaveBreakContext(); this.currentFunction.leaveBreakContext();
const breakLabel: string = "break$" + label; const breakLabel: string = "break$" + label;
const continueLabel: string = "continue$" + label; const continueLabel: string = "continue$" + label;
@ -675,24 +689,24 @@ export class Compiler extends DiagnosticEmitter {
this.module.createBlock(null, [ this.module.createBlock(null, [
body, body,
this.module.createBreak(continueLabel, condition) this.module.createBreak(continueLabel, condition)
], BinaryenType.None)) ], NativeType.None))
], BinaryenType.None); ], NativeType.None);
} }
compileEmptyStatement(statement: EmptyStatement): BinaryenExpressionRef { compileEmptyStatement(statement: EmptyStatement): ExpressionRef {
return this.module.createNop(); return this.module.createNop();
} }
compileExpressionStatement(statement: ExpressionStatement): BinaryenExpressionRef { compileExpressionStatement(statement: ExpressionStatement): ExpressionRef {
return this.compileExpression(statement.expression, Type.void); return this.compileExpression(statement.expression, Type.void);
} }
compileForStatement(statement: ForStatement): BinaryenExpressionRef { compileForStatement(statement: ForStatement): ExpressionRef {
const context: string = this.currentFunction.enterBreakContext(); const context: string = this.currentFunction.enterBreakContext();
const initializer: BinaryenExpressionRef = statement.initializer ? this.compileStatement(<Statement>statement.initializer) : this.module.createNop(); const initializer: ExpressionRef = statement.initializer ? this.compileStatement(<Statement>statement.initializer) : this.module.createNop();
const condition: BinaryenExpressionRef = statement.condition ? this.compileExpression(<Expression>statement.condition, Type.i32) : this.module.createI32(1); const condition: ExpressionRef = statement.condition ? this.compileExpression(<Expression>statement.condition, Type.i32) : this.module.createI32(1);
const incrementor: BinaryenExpressionRef = statement.incrementor ? this.compileExpression(<Expression>statement.incrementor, Type.void) : this.module.createNop(); const incrementor: ExpressionRef = statement.incrementor ? this.compileExpression(<Expression>statement.incrementor, Type.void) : this.module.createNop();
const body: BinaryenExpressionRef = this.compileStatement(statement.statement); const body: ExpressionRef = this.compileStatement(statement.statement);
this.currentFunction.leaveBreakContext(); this.currentFunction.leaveBreakContext();
const continueLabel: string = "continue$" + context; const continueLabel: string = "continue$" + context;
const breakLabel: string = "break$" + context; const breakLabel: string = "break$" + context;
@ -703,27 +717,27 @@ export class Compiler extends DiagnosticEmitter {
body, body,
incrementor, incrementor,
this.module.createBreak(continueLabel) this.module.createBreak(continueLabel)
], BinaryenType.None)) ], NativeType.None))
], BinaryenType.None)) ], NativeType.None))
], BinaryenType.None); ], NativeType.None);
} }
compileIfStatement(statement: IfStatement): BinaryenExpressionRef { compileIfStatement(statement: IfStatement): ExpressionRef {
const condition: BinaryenExpressionRef = this.compileExpression(statement.condition, Type.i32); const condition: ExpressionRef = this.compileExpression(statement.condition, Type.i32);
const ifTrue: BinaryenExpressionRef = this.compileStatement(statement.statement); const ifTrue: ExpressionRef = this.compileStatement(statement.statement);
const ifFalse: BinaryenExpressionRef = statement.elseStatement ? this.compileStatement(<Statement>statement.elseStatement) : 0; const ifFalse: ExpressionRef = statement.elseStatement ? this.compileStatement(<Statement>statement.elseStatement) : 0;
return this.module.createIf(condition, ifTrue, ifFalse); return this.module.createIf(condition, ifTrue, ifFalse);
} }
compileReturnStatement(statement: ReturnStatement): BinaryenExpressionRef { compileReturnStatement(statement: ReturnStatement): ExpressionRef {
if (this.currentFunction) { if (this.currentFunction) {
const expression: BinaryenExpressionRef = statement.expression ? this.compileExpression(<Expression>statement.expression, this.currentFunction.returnType) : 0; const expression: ExpressionRef = statement.expression ? this.compileExpression(<Expression>statement.expression, this.currentFunction.returnType) : 0;
return this.module.createReturn(expression); return this.module.createReturn(expression);
} }
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
compileSwitchStatement(statement: SwitchStatement): BinaryenExpressionRef { compileSwitchStatement(statement: SwitchStatement): ExpressionRef {
const context: string = this.currentFunction.enterBreakContext(); const context: string = this.currentFunction.enterBreakContext();
const previousDisallowContinue: bool = this.disallowContinue; const previousDisallowContinue: bool = this.disallowContinue;
this.disallowContinue = true; this.disallowContinue = true;
@ -733,18 +747,18 @@ export class Compiler extends DiagnosticEmitter {
let i: i32, k: i32 = statement.cases.length; let i: i32, k: i32 = statement.cases.length;
// prepend initializer to inner block // prepend initializer to inner block
const breaks: BinaryenExpressionRef[] = new Array(1 + k); const breaks: ExpressionRef[] = new Array(1 + k);
breaks[0] = this.module.createSetLocal(local.index, this.compileExpression(statement.expression, Type.i32)); // initializer breaks[0] = this.module.createSetLocal(local.index, this.compileExpression(statement.expression, Type.i32)); // initializer
// make one br_if per (possibly dynamic) labeled case // make one br_if per (possibly dynamic) labeled case
// TODO: take advantage of br_table where labels are known to be (sequential) constant (ideally Binaryen's optimizer would) // TODO: take advantage of br_table where labels are known to be (sequential) constant (ideally the optimizer would)
let breakIndex: i32 = 1; let breakIndex: i32 = 1;
let defaultIndex: i32 = -1; let defaultIndex: i32 = -1;
for (i = 0; i < k; ++i) { for (i = 0; i < k; ++i) {
const case_: SwitchCase = statement.cases[i]; const case_: SwitchCase = statement.cases[i];
if (case_.label) { if (case_.label) {
breaks[breakIndex++] = this.module.createBreak("case" + i.toString(10) + "$" + context, this.module.createBinary(BinaryOp.EqI32, breaks[breakIndex++] = this.module.createBreak("case" + i.toString(10) + "$" + context, this.module.createBinary(BinaryOp.EqI32,
this.module.createGetLocal(local.index, BinaryenType.I32), this.module.createGetLocal(local.index, NativeType.I32),
this.compileExpression(case_.label, Type.i32) this.compileExpression(case_.label, Type.i32)
)); ));
} else } else
@ -758,18 +772,18 @@ export class Compiler extends DiagnosticEmitter {
) + "$" + context); ) + "$" + context);
// nest blocks in order // nest blocks in order
let currentBlock: BinaryenExpressionRef = this.module.createBlock("case0$" + context, breaks, BinaryenType.None); let currentBlock: ExpressionRef = this.module.createBlock("case0$" + context, breaks, NativeType.None);
for (i = 0; i < k; ++i) { for (i = 0; i < k; ++i) {
const case_: SwitchCase = statement.cases[i]; const case_: SwitchCase = statement.cases[i];
const nextLabel: string = i == k - 1 const nextLabel: string = i == k - 1
? "break$" + context ? "break$" + context
: "case" + (i + 1).toString(10) + "$" + context; : "case" + (i + 1).toString(10) + "$" + context;
const l: i32 = case_.statements.length; const l: i32 = case_.statements.length;
const body: BinaryenExpressionRef[] = new Array(1 + l); const body: ExpressionRef[] = new Array(1 + l);
body[0] = currentBlock; body[0] = currentBlock;
for (let j: i32 = 0; j < l; ++j) for (let j: i32 = 0; j < l; ++j)
body[j + 1] = this.compileStatement(case_.statements[j]); body[j + 1] = this.compileStatement(case_.statements[j]);
currentBlock = this.module.createBlock(nextLabel, body, BinaryenType.None); currentBlock = this.module.createBlock(nextLabel, body, NativeType.None);
} }
this.currentFunction.leaveBreakContext(); this.currentFunction.leaveBreakContext();
this.disallowContinue = previousDisallowContinue; this.disallowContinue = previousDisallowContinue;
@ -777,17 +791,17 @@ export class Compiler extends DiagnosticEmitter {
return currentBlock; return currentBlock;
} }
compileThrowStatement(statement: ThrowStatement): BinaryenExpressionRef { compileThrowStatement(statement: ThrowStatement): ExpressionRef {
return this.module.createUnreachable(); // TODO: waiting for exception-handling spec return this.module.createUnreachable(); // TODO: waiting for exception-handling spec
} }
compileTryStatement(statement: TryStatement): BinaryenExpressionRef { compileTryStatement(statement: TryStatement): ExpressionRef {
throw new Error("not implemented"); throw new Error("not implemented");
// can't yet support something like: try { return ... } finally { ... } // can't yet support something like: try { return ... } finally { ... }
// worthwhile to investigate lowering returns to block results (here)? // worthwhile to investigate lowering returns to block results (here)?
} }
compileVariableStatement(statement: VariableStatement): BinaryenExpressionRef { compileVariableStatement(statement: VariableStatement): ExpressionRef {
const declarations: VariableDeclaration[] = statement.declarations; const declarations: VariableDeclaration[] = statement.declarations;
// top-level variables become globals // top-level variables become globals
@ -798,7 +812,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createNop(); return this.module.createNop();
} }
// other variables become locals // other variables become locals
const initializers: BinaryenExpressionRef[] = new Array(); const initializers: ExpressionRef[] = new Array();
for (let i: i32 = 0, k = declarations.length; i < k; ++i) { for (let i: i32 = 0, k = declarations.length; i < k; ++i) {
const declaration: VariableDeclaration = declarations[i]; const declaration: VariableDeclaration = declarations[i];
if (declaration.type) { if (declaration.type) {
@ -814,32 +828,32 @@ export class Compiler extends DiagnosticEmitter {
} }
} }
} }
return initializers.length ? this.module.createBlock(null, initializers, BinaryenType.None) : this.module.createNop(); return initializers.length ? this.module.createBlock(null, initializers, NativeType.None) : this.module.createNop();
} }
compileWhileStatement(statement: WhileStatement): BinaryenExpressionRef { compileWhileStatement(statement: WhileStatement): ExpressionRef {
const label: string = this.currentFunction.enterBreakContext(); const label: string = this.currentFunction.enterBreakContext();
const condition: BinaryenExpressionRef = this.compileExpression(statement.condition, Type.i32); const condition: ExpressionRef = this.compileExpression(statement.condition, Type.i32);
const breakLabel: string = "break$" + label; const breakLabel: string = "break$" + label;
const continueLabel: string = "continue$" + label; const continueLabel: string = "continue$" + label;
const body: BinaryenExpressionRef = this.compileStatement(statement.statement); const body: ExpressionRef = this.compileStatement(statement.statement);
this.currentFunction.leaveBreakContext(); this.currentFunction.leaveBreakContext();
return this.module.createBlock(breakLabel, [ return this.module.createBlock(breakLabel, [
this.module.createLoop(continueLabel, this.module.createLoop(continueLabel,
this.module.createIf(condition, this.module.createBlock(null, [ this.module.createIf(condition, this.module.createBlock(null, [
body, body,
this.module.createBreak(continueLabel) this.module.createBreak(continueLabel)
], BinaryenType.None)) ], NativeType.None))
) )
], BinaryenType.None); ], NativeType.None);
} }
// expressions // expressions
compileExpression(expression: Expression, contextualType: Type, convert: bool = true): BinaryenExpressionRef { compileExpression(expression: Expression, contextualType: Type, convert: bool = true): ExpressionRef {
this.currentType = contextualType; this.currentType = contextualType;
let expr: BinaryenExpressionRef; let expr: ExpressionRef;
switch (expression.kind) { switch (expression.kind) {
case NodeKind.ASSERTION: case NodeKind.ASSERTION:
@ -906,7 +920,7 @@ export class Compiler extends DiagnosticEmitter {
return expr; return expr;
} }
convertExpression(expr: BinaryenExpressionRef, fromType: Type, toType: Type): BinaryenExpressionRef { convertExpression(expr: ExpressionRef, fromType: Type, toType: Type): ExpressionRef {
// void to any // void to any
if (fromType.kind == TypeKind.VOID) if (fromType.kind == TypeKind.VOID)
@ -1059,19 +1073,19 @@ export class Compiler extends DiagnosticEmitter {
return expr; return expr;
} }
compileAssertionExpression(expression: AssertionExpression, contextualType: Type): BinaryenExpressionRef { compileAssertionExpression(expression: AssertionExpression, contextualType: Type): ExpressionRef {
const toType: Type | null = this.program.resolveType(expression.toType, this.currentFunction.contextualTypeArguments); // reports const toType: Type | null = this.program.resolveType(expression.toType, this.currentFunction.contextualTypeArguments); // reports
if (toType && toType != contextualType) { if (toType && toType != contextualType) {
const expr: BinaryenExpressionRef = this.compileExpression(expression.expression, <Type>toType, false); const expr: ExpressionRef = this.compileExpression(expression.expression, <Type>toType, false);
return this.convertExpression(expr, this.currentType, <Type>toType); return this.convertExpression(expr, this.currentType, <Type>toType);
} }
return this.compileExpression(expression.expression, contextualType); return this.compileExpression(expression.expression, contextualType);
} }
compileBinaryExpression(expression: BinaryExpression, contextualType: Type): BinaryenExpressionRef { compileBinaryExpression(expression: BinaryExpression, contextualType: Type): ExpressionRef {
let op: BinaryOp; let op: BinaryOp;
let left: BinaryenExpressionRef; let left: ExpressionRef;
let right: BinaryenExpressionRef; let right: ExpressionRef;
let compound: Token = 0; let compound: Token = 0;
switch (expression.operator) { switch (expression.operator) {
@ -1287,12 +1301,12 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createBinary(op, left, right); return this.module.createBinary(op, left, right);
} }
compileAssignment(expression: Expression, valueExpression: Expression, contextualType: Type): BinaryenExpressionRef { compileAssignment(expression: Expression, valueExpression: Expression, contextualType: Type): ExpressionRef {
this.currentType = this.determineExpressionType(expression, contextualType); this.currentType = this.determineExpressionType(expression, contextualType);
return this.compileAssignmentWithValue(expression, this.compileExpression(valueExpression, this.currentType), contextualType != Type.void); return this.compileAssignmentWithValue(expression, this.compileExpression(valueExpression, this.currentType), contextualType != Type.void);
} }
compileAssignmentWithValue(expression: Expression, valueWithCorrectType: BinaryenExpressionRef, tee: bool = false): BinaryenExpressionRef { compileAssignmentWithValue(expression: Expression, valueWithCorrectType: ExpressionRef, tee: bool = false): ExpressionRef {
const element: Element | null = this.program.resolveElement(expression, this.currentFunction); const element: Element | null = this.program.resolveElement(expression, this.currentFunction);
if (!element) if (!element)
return this.module.createUnreachable(); return this.module.createUnreachable();
@ -1307,12 +1321,12 @@ export class Compiler extends DiagnosticEmitter {
if (element.kind == ElementKind.GLOBAL && (<Global>element).type) { if (element.kind == ElementKind.GLOBAL && (<Global>element).type) {
if (tee) { if (tee) {
const globalBinaryenType: BinaryenType = typeToBinaryenType(<Type>(<Global>element).type); const globalNativeType: NativeType = typeToNativeType(<Type>(<Global>element).type);
this.currentType = <Type>(<Global>element).type; this.currentType = <Type>(<Global>element).type;
return this.module.createBlock(null, [ // teeGlobal return this.module.createBlock(null, [ // teeGlobal
this.module.createSetGlobal((<Global>element).internalName, valueWithCorrectType), this.module.createSetGlobal((<Global>element).internalName, valueWithCorrectType),
this.module.createGetGlobal((<Global>element).internalName, globalBinaryenType) this.module.createGetGlobal((<Global>element).internalName, globalNativeType)
], globalBinaryenType); ], globalNativeType);
} }
return this.module.createSetGlobal((<Global>element).internalName, valueWithCorrectType); return this.module.createSetGlobal((<Global>element).internalName, valueWithCorrectType);
} }
@ -1322,7 +1336,17 @@ export class Compiler extends DiagnosticEmitter {
throw new Error("not implemented"); throw new Error("not implemented");
} }
compileCallExpression(expression: CallExpression, contextualType: Type): BinaryenExpressionRef { compileCallExpression(expression: CallExpression, contextualType: Type): ExpressionRef {
// TODO
/* const callee: Expression = expression.expression;
switch (callee.kind) {
case NodeKind.THIS:
// use current class
case NodeKind.PROPERTYACCESS:
// compile, use class in currentType?
case NodeKind.IDENTIFIER:
// lookup identifier?
} */
const element: Element | null = this.program.resolveElement(expression.expression, this.currentFunction); // reports const element: Element | null = this.program.resolveElement(expression.expression, this.currentFunction); // reports
if (!element) if (!element)
return this.module.createUnreachable(); return this.module.createUnreachable();
@ -1336,40 +1360,57 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
compileCall(functionInstance: Function, argumentExpressions: Expression[], reportNode: Node): BinaryenExpressionRef { /** Compiles a call to a function. If an instance method, `this` is the first element in `argumentExpressions`. */
compileCall(functionInstance: Function, argumentExpressions: Expression[], reportNode: Node): ExpressionRef {
// when called, the function is considered reachable -> compile
if (!functionInstance.compiled) if (!functionInstance.compiled)
this.compileFunction(functionInstance); this.compileFunction(functionInstance);
// validate and compile arguments
const parameters: Parameter[] = functionInstance.parameters; const parameters: Parameter[] = functionInstance.parameters;
let k: i32 = parameters.length; const parameterCount: i32 = parameters.length;
if (argumentExpressions.length > k) { const argumentCount: i32 = argumentExpressions.length;
this.error(DiagnosticCode.Expected_0_arguments_but_got_1, reportNode.range, k.toString(10), argumentExpressions.length.toString(10)); if (argumentExpressions.length > parameterCount) { // too many arguments
this.error(DiagnosticCode.Expected_0_arguments_but_got_1, reportNode.range,
(functionInstance.isInstance ? parameterCount - 1 : parameterCount).toString(10),
(functionInstance.isInstance ? argumentCount - 1 : argumentCount).toString(10)
);
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
const operands: BinaryenExpressionRef[] = new Array(k); const operands: ExpressionRef[] = new Array(parameterCount);
for (let i: i32 = 0; i < k; ++i) { for (let i: i32 = 0; i < parameterCount; ++i) {
if (argumentExpressions.length > i) { if (argumentExpressions.length > i) {
operands[i] = this.compileExpression(argumentExpressions[i], parameters[i].type); operands[i] = this.compileExpression(argumentExpressions[i], parameters[i].type, true);
} else { } else {
const initializer: Expression | null = parameters[i].initializer; const initializer: Expression | null = parameters[i].initializer;
if (initializer) { if (initializer) { // omitted, uses initializer
// FIXME: here, the initializer is compiled in the caller's scope.
// a solution could be to use a stub for each possible overload, calling the
// full function with optional arguments being part of the stub's body.
operands[i] = this.compileExpression(initializer, parameters[i].type); operands[i] = this.compileExpression(initializer, parameters[i].type);
} else { } else { // too few arguments
this.error(DiagnosticCode.Expected_at_least_0_arguments_but_got_1, reportNode.range, (i + 1).toString(10), argumentExpressions.length.toString(10)); this.error(DiagnosticCode.Expected_at_least_0_arguments_but_got_1, reportNode.range,
(functionInstance.isInstance ? i : i + 1).toString(10),
(functionInstance.isInstance ? argumentCount - 1 : argumentCount).toString(10)
);
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
} }
} }
return this.module.createCall(functionInstance.internalName, operands, typeToBinaryenType(functionInstance.returnType));
// finally compile the call
this.currentType = functionInstance.returnType;
return this.module.createCall(functionInstance.internalName, operands, typeToNativeType(functionInstance.returnType));
} }
compileElementAccessExpression(expression: ElementAccessExpression, contextualType: Type): BinaryenExpressionRef { compileElementAccessExpression(expression: ElementAccessExpression, contextualType: Type): ExpressionRef {
const element: Element | null = this.program.resolveElement(expression.expression, this.currentFunction); // reports const element: Element | null = this.program.resolveElement(expression.expression, this.currentFunction); // reports
if (!element) if (!element)
return this.module.createUnreachable(); return this.module.createUnreachable();
throw new Error("not implemented"); throw new Error("not implemented");
} }
compileIdentifierExpression(expression: IdentifierExpression, contextualType: Type): BinaryenExpressionRef { compileIdentifierExpression(expression: IdentifierExpression, contextualType: Type): ExpressionRef {
// null // null
if (expression.kind == NodeKind.NULL) { if (expression.kind == NodeKind.NULL) {
@ -1397,7 +1438,7 @@ export class Compiler extends DiagnosticEmitter {
} else if (expression.kind == NodeKind.THIS) { } else if (expression.kind == NodeKind.THIS) {
if (this.currentFunction.instanceMethodOf) { if (this.currentFunction.instanceMethodOf) {
this.currentType = this.currentFunction.instanceMethodOf.type; this.currentType = this.currentFunction.instanceMethodOf.type;
return this.module.createGetLocal(0, typeToBinaryenType(this.currentType)); return this.module.createGetLocal(0, typeToNativeType(this.currentType));
} }
this.error(DiagnosticCode._this_cannot_be_referenced_in_current_location, expression.range); this.error(DiagnosticCode._this_cannot_be_referenced_in_current_location, expression.range);
this.currentType = this.options.target == Target.WASM64 ? Type.u64 : Type.u32; this.currentType = this.options.target == Target.WASM64 ? Type.u64 : Type.u32;
@ -1431,12 +1472,12 @@ export class Compiler extends DiagnosticEmitter {
// local // local
if (element.kind == ElementKind.LOCAL) if (element.kind == ElementKind.LOCAL)
return this.module.createGetLocal((<Local>element).index, typeToBinaryenType(this.currentType = (<Local>element).type)); return this.module.createGetLocal((<Local>element).index, typeToNativeType(this.currentType = (<Local>element).type));
// global // global
if (element.kind == ElementKind.GLOBAL) if (element.kind == ElementKind.GLOBAL)
return this.compileGlobal(<Global>element) // reports return this.compileGlobal(<Global>element) // reports
? this.module.createGetGlobal((<Global>element).internalName, typeToBinaryenType(this.currentType = <Type>(<Global>element).type)) ? this.module.createGetGlobal((<Global>element).internalName, typeToNativeType(this.currentType = <Type>(<Global>element).type))
: this.module.createUnreachable(); : this.module.createUnreachable();
// field // field
@ -1451,7 +1492,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
compileLiteralExpression(expression: LiteralExpression, contextualType: Type): BinaryenExpressionRef { compileLiteralExpression(expression: LiteralExpression, contextualType: Type): ExpressionRef {
switch (expression.literalKind) { switch (expression.literalKind) {
// case LiteralKind.ARRAY: // case LiteralKind.ARRAY:
@ -1484,62 +1525,62 @@ export class Compiler extends DiagnosticEmitter {
throw new Error("not implemented"); throw new Error("not implemented");
} }
compileNewExpression(expression: NewExpression, contextualType: Type): BinaryenExpressionRef { compileNewExpression(expression: NewExpression, contextualType: Type): ExpressionRef {
throw new Error("not implemented"); throw new Error("not implemented");
} }
compileParenthesizedExpression(expression: ParenthesizedExpression, contextualType: Type): BinaryenExpressionRef { compileParenthesizedExpression(expression: ParenthesizedExpression, contextualType: Type): ExpressionRef {
return this.compileExpression(expression.expression, contextualType); return this.compileExpression(expression.expression, contextualType);
} }
compilePropertyAccessExpression(expression: PropertyAccessExpression, contextualType: Type): BinaryenExpressionRef { compilePropertyAccessExpression(expression: PropertyAccessExpression, contextualType: Type): ExpressionRef {
throw new Error("not implemented"); throw new Error("not implemented");
} }
compileSelectExpression(expression: SelectExpression, contextualType: Type): BinaryenExpressionRef { compileSelectExpression(expression: SelectExpression, contextualType: Type): ExpressionRef {
const condition: BinaryenExpressionRef = this.compileExpression(expression.condition, Type.i32); const condition: ExpressionRef = this.compileExpression(expression.condition, Type.i32);
const ifThen: BinaryenExpressionRef = this.compileExpression(expression.ifThen, contextualType); const ifThen: ExpressionRef = this.compileExpression(expression.ifThen, contextualType);
const ifElse: BinaryenExpressionRef = this.compileExpression(expression.ifElse, contextualType); const ifElse: ExpressionRef = this.compileExpression(expression.ifElse, contextualType);
return this.module.createSelect(condition, ifThen, ifElse); return this.module.createSelect(condition, ifThen, ifElse);
} }
compileUnaryPostfixExpression(expression: UnaryPostfixExpression, contextualType: Type): BinaryenExpressionRef { compileUnaryPostfixExpression(expression: UnaryPostfixExpression, contextualType: Type): ExpressionRef {
const operator: Token = expression.operator; const operator: Token = expression.operator;
let op: BinaryOp; let op: BinaryOp;
let binaryenType: BinaryenType; let nativeType: NativeType;
let binaryenOne: BinaryenExpressionRef; let nativeOne: ExpressionRef;
if (contextualType == Type.f32) { if (contextualType == Type.f32) {
op = operator == Token.PLUS_PLUS ? BinaryOp.AddF32 : BinaryOp.SubF32; op = operator == Token.PLUS_PLUS ? BinaryOp.AddF32 : BinaryOp.SubF32;
binaryenType = BinaryenType.F32; nativeType = NativeType.F32;
binaryenOne = this.module.createF32(1); nativeOne = this.module.createF32(1);
} else if (contextualType == Type.f64) { } else if (contextualType == Type.f64) {
op = operator == Token.PLUS_PLUS ? BinaryOp.AddF64 : BinaryOp.SubF64; op = operator == Token.PLUS_PLUS ? BinaryOp.AddF64 : BinaryOp.SubF64;
binaryenType = BinaryenType.F64; nativeType = NativeType.F64;
binaryenOne = this.module.createF64(1); nativeOne = this.module.createF64(1);
} else if (contextualType.isLongInteger) { } else if (contextualType.isLongInteger) {
op = operator == Token.PLUS_PLUS ? BinaryOp.AddI64 : BinaryOp.SubI64; op = operator == Token.PLUS_PLUS ? BinaryOp.AddI64 : BinaryOp.SubI64;
binaryenType = BinaryenType.I64; nativeType = NativeType.I64;
binaryenOne = this.module.createI64(1, 0); nativeOne = this.module.createI64(1, 0);
} else { } else {
op = operator == Token.PLUS_PLUS ? BinaryOp.AddI32 : BinaryOp.SubI32; op = operator == Token.PLUS_PLUS ? BinaryOp.AddI32 : BinaryOp.SubI32;
binaryenType = BinaryenType.I32; nativeType = NativeType.I32;
binaryenOne = this.module.createI32(1); nativeOne = this.module.createI32(1);
} }
const getValue: BinaryenExpressionRef = this.compileExpression(expression.expression, contextualType); const getValue: ExpressionRef = this.compileExpression(expression.expression, contextualType);
const setValue: BinaryenExpressionRef = this.compileAssignmentWithValue(expression.expression, this.module.createBinary(op, getValue, binaryenOne), false); // reports const setValue: ExpressionRef = this.compileAssignmentWithValue(expression.expression, this.module.createBinary(op, getValue, nativeOne), false); // reports
return this.module.createBlock(null, [ return this.module.createBlock(null, [
getValue, getValue,
setValue setValue
], binaryenType); ], nativeType);
} }
compileUnaryPrefixExpression(expression: UnaryPrefixExpression, contextualType: Type): BinaryenExpressionRef { compileUnaryPrefixExpression(expression: UnaryPrefixExpression, contextualType: Type): ExpressionRef {
const operandExpression: Expression = expression.expression; const operandExpression: Expression = expression.expression;
let operand: BinaryenExpressionRef; let operand: ExpressionRef;
let op: UnaryOp; let op: UnaryOp;
switch (expression.operator) { switch (expression.operator) {
@ -1610,27 +1651,27 @@ export class Compiler extends DiagnosticEmitter {
// helpers // helpers
function typeToBinaryenType(type: Type): BinaryenType { function typeToNativeType(type: Type): NativeType {
return type.kind == TypeKind.F32 return type.kind == TypeKind.F32
? BinaryenType.F32 ? NativeType.F32
: type.kind == TypeKind.F64 : type.kind == TypeKind.F64
? BinaryenType.F64 ? NativeType.F64
: type.isLongInteger : type.isLongInteger
? BinaryenType.I64 ? NativeType.I64
: type.isAnyInteger || type.kind == TypeKind.BOOL : type.isAnyInteger || type.kind == TypeKind.BOOL
? BinaryenType.I32 ? NativeType.I32
: BinaryenType.None; : NativeType.None;
} }
function typesToBinaryenTypes(types: Type[]): BinaryenType[] { function typesToNativeTypes(types: Type[]): NativeType[] {
const k: i32 = types.length; const k: i32 = types.length;
const ret: BinaryenType[] = new Array(k); const ret: NativeType[] = new Array(k);
for (let i: i32 = 0; i < k; ++i) for (let i: i32 = 0; i < k; ++i)
ret[i] = typeToBinaryenType(types[i]); ret[i] = typeToNativeType(types[i]);
return ret; return ret;
} }
function typeToBinaryenZero(module: Module, type: Type): BinaryenExpressionRef { function typeToNativeZero(module: Module, type: Type): ExpressionRef {
return type.kind == TypeKind.F32 return type.kind == TypeKind.F32
? module.createF32(0) ? module.createF32(0)
: type.kind == TypeKind.F64 : type.kind == TypeKind.F64
@ -1640,7 +1681,7 @@ function typeToBinaryenZero(module: Module, type: Type): BinaryenExpressionRef {
: module.createI32(0); : module.createI32(0);
} }
function typeToBinaryenOne(module: Module, type: Type): BinaryenExpressionRef { function typeToBinaryenOne(module: Module, type: Type): ExpressionRef {
return type.kind == TypeKind.F32 return type.kind == TypeKind.F32
? module.createF32(1) ? module.createF32(1)
: type.kind == TypeKind.F64 : type.kind == TypeKind.F64

View File

@ -2,7 +2,7 @@
export const PATH_DELIMITER: string = "/"; export const PATH_DELIMITER: string = "/";
export const PARENT_SUBST: string = ".."; export const PARENT_SUBST: string = "..";
export const GETTER_PREFIX: string = "get "; export const GETTER_PREFIX: string = "get_";
export const SETTER_PREFIX: string = "set "; export const SETTER_PREFIX: string = "set_";
export const INSTANCE_DELIMITER: string = "#"; export const INSTANCE_DELIMITER: string = "#";
export const STATIC_DELIMITER: string = "."; export const STATIC_DELIMITER: string = ".";

View File

@ -246,6 +246,8 @@ 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 _BinaryenHost(module: BinaryenModuleRef, op: BinaryenOp, name: CString | 0, operands: CArray<BinaryenExpressionRef>, numOperands: BinaryenIndex): BinaryenExpressionRef;
declare function _BinaryenNop(module: BinaryenModuleRef): BinaryenExpressionRef; declare function _BinaryenNop(module: BinaryenModuleRef): BinaryenExpressionRef;
declare function _BinaryenUnreachable(module: BinaryenModuleRef): BinaryenExpressionRef; declare function _BinaryenUnreachable(module: BinaryenModuleRef): BinaryenExpressionRef;
declare function _BinaryenAtomicLoad(module: BinaryenModuleRef, bytes: BinaryenIndex, offset: BinaryenIndex, type: BinaryenType, ptr: BinaryenExpressionRef): BinaryenExpressionRef;
declare function _BinaryenAtomicStore(module: BinaryenModuleRef, bytes: BinaryenIndex, offset: BinaryenIndex, ptr: BinaryenExpressionRef, value: BinaryenExpressionRef, type: BinaryenType): BinaryenExpressionRef;
declare function _BinaryenAtomicRMW(module: BinaryenModuleRef, op: BinaryenAtomicRMWOp, bytes: i32, offset: i32, ptr: BinaryenExpressionRef, value: BinaryenExpressionRef, type: BinaryenType): 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 _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 _BinaryenAtomicWait(module: BinaryenModuleRef, ptr: BinaryenExpressionRef, expected: BinaryenExpressionRef, timeout: BinaryenExpressionRef, expectedType: BinaryenType): BinaryenExpressionRef;
@ -263,6 +265,12 @@ declare function _BinaryenConstGetValueF64(expr: BinaryenExpressionRef): f64;
declare type BinaryenFunctionRef = usize; declare type BinaryenFunctionRef = usize;
declare function _BinaryenAddFunction(module: BinaryenModuleRef, name: CString, type: BinaryenFunctionTypeRef, varTypes: CArray<BinaryenType>, numVarTypes: BinaryenIndex, body: BinaryenExpressionRef): BinaryenFunctionRef; declare function _BinaryenAddFunction(module: BinaryenModuleRef, name: CString, type: BinaryenFunctionTypeRef, varTypes: CArray<BinaryenType>, numVarTypes: BinaryenIndex, body: BinaryenExpressionRef): BinaryenFunctionRef;
declare function _BinaryenGetFunction(module: BinaryenModuleRef, name: CString): BinaryenFunctionRef;
declare function _BinaryenRemoveFunction(module: BinaryenModuleRef, name: CString): void;
declare function _BinaryenFunctionGetBody(func: BinaryenFunctionRef): BinaryenExpressionRef;
declare function _BinaryenFunctionOptimize(func: BinaryenFunctionRef, module: BinaryenModuleRef): void;
declare function _BinaryenFunctionRunPasses(func: BinaryenFunctionRef, module: BinaryenModuleRef, passes: CArray<CString>, numPasses: BinaryenIndex): void;
declare type BinaryenImportRef = usize; declare type BinaryenImportRef = usize;
@ -289,7 +297,7 @@ declare function _BinaryenModulePrint(module: BinaryenModuleRef): void;
declare function _BinaryenModulePrintAsmjs(module: BinaryenModuleRef): void; declare function _BinaryenModulePrintAsmjs(module: BinaryenModuleRef): void;
declare function _BinaryenModuleValidate(module: BinaryenModuleRef): i32; declare function _BinaryenModuleValidate(module: BinaryenModuleRef): i32;
declare function _BinaryenModuleOptimize(module: BinaryenModuleRef): void; declare function _BinaryenModuleOptimize(module: BinaryenModuleRef): void;
declare function _BinaryenModuleRunPasses(module: BinaryenModuleRef, passes: string[]): void; declare function _BinaryenModuleRunPasses(module: BinaryenModuleRef, passes: CArray<CString>, numPasses: BinaryenIndex): void;
declare function _BinaryenModuleAutoDrop(module: BinaryenModuleRef): void; declare function _BinaryenModuleAutoDrop(module: BinaryenModuleRef): void;
declare function _BinaryenModuleWrite(module: BinaryenModuleRef, output: CString, outputSize: usize): usize; declare function _BinaryenModuleWrite(module: BinaryenModuleRef, output: CString, outputSize: usize): usize;
declare function _BinaryenModuleRead(input: CString, inputSize: usize): BinaryenModuleRef; declare function _BinaryenModuleRead(input: CString, inputSize: usize): BinaryenModuleRef;

View File

@ -19,7 +19,7 @@
*/ */
import { Module } from "./binaryen"; import { Module } from "./module";
import { Compiler } from "./compiler"; import { Compiler } from "./compiler";
import { DiagnosticMessage, DiagnosticCategory } from "./diagnostics"; import { DiagnosticMessage, DiagnosticCategory } from "./diagnostics";
import { Parser } from "./parser"; import { Parser } from "./parser";

View File

@ -1,7 +1,16 @@
import { I64, U64 } from "./util"; import { I64, U64 } from "./util";
import { Target } from "./compiler"; import { Target } from "./compiler";
export enum Type { export type ModuleRef = BinaryenModuleRef;
export type FunctionTypeRef = BinaryenFunctionTypeRef;
export type FunctionRef = BinaryenFunctionRef;
export type ExpressionRef = BinaryenExpressionRef;
export type GlobalRef = BinaryenGlobalRef;
export type ImportRef = BinaryenImportRef;
export type ExportRef = BinaryenExportRef;
export type Index = BinaryenIndex;
export enum NativeType {
None = _BinaryenNone(), None = _BinaryenNone(),
I32 = _BinaryenInt32(), I32 = _BinaryenInt32(),
I64 = _BinaryenInt64(), I64 = _BinaryenInt64(),
@ -201,11 +210,11 @@ export class MemorySegment {
export class Module { export class Module {
ref: BinaryenModuleRef; ref: ModuleRef;
lit: BinaryenLiteral; lit: BinaryenLiteral;
noEmit: bool; noEmit: bool;
static MAX_MEMORY_WASM32: BinaryenIndex = 0xffff; static MAX_MEMORY_WASM32: Index = 0xffff;
static create(): Module { static create(): Module {
const module: Module = new Module(); const module: Module = new Module();
@ -240,7 +249,7 @@ export class Module {
// types // types
addFunctionType(name: string, result: Type, paramTypes: Type[]): BinaryenFunctionRef { addFunctionType(name: string, result: NativeType, paramTypes: NativeType[]): FunctionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const cStr: CString = allocString(name); const cStr: CString = allocString(name);
const cArr: CArray<i32> = allocI32Array(paramTypes); const cArr: CArray<i32> = allocI32Array(paramTypes);
@ -252,7 +261,7 @@ export class Module {
} }
} }
getFunctionTypeBySignature(result: Type, paramTypes: Type[]): BinaryenFunctionTypeRef { getFunctionTypeBySignature(result: NativeType, paramTypes: NativeType[]): FunctionTypeRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const cArr: CArray<i32> = allocI32Array(paramTypes); const cArr: CArray<i32> = allocI32Array(paramTypes);
try { try {
@ -264,63 +273,63 @@ export class Module {
// expressions // expressions
createI32(value: i32): BinaryenExpressionRef { createI32(value: i32): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
_BinaryenLiteralInt32(this.lit, value); _BinaryenLiteralInt32(this.lit, value);
return _BinaryenConst(this.ref, this.lit); return _BinaryenConst(this.ref, this.lit);
} }
createI64(lo: i32, hi: i32): BinaryenExpressionRef { createI64(lo: i32, hi: i32): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
_BinaryenLiteralInt64(this.lit, lo, hi); _BinaryenLiteralInt64(this.lit, lo, hi);
return _BinaryenConst(this.ref, this.lit); return _BinaryenConst(this.ref, this.lit);
} }
createF32(value: f32): BinaryenExpressionRef { createF32(value: f32): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
_BinaryenLiteralFloat32(this.lit, value); _BinaryenLiteralFloat32(this.lit, value);
return _BinaryenConst(this.ref, this.lit); return _BinaryenConst(this.ref, this.lit);
} }
createF64(value: f64): BinaryenExpressionRef { createF64(value: f64): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
_BinaryenLiteralFloat64(this.lit, value); _BinaryenLiteralFloat64(this.lit, value);
return _BinaryenConst(this.ref, this.lit); return _BinaryenConst(this.ref, this.lit);
} }
createUnary(op: UnaryOp, expr: BinaryenExpressionRef): BinaryenExpressionRef { createUnary(op: UnaryOp, expr: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenUnary(this.ref, op, expr); return _BinaryenUnary(this.ref, op, expr);
} }
createBinary(op: BinaryOp, left: BinaryenExpressionRef, right: BinaryenExpressionRef): BinaryenExpressionRef { createBinary(op: BinaryOp, left: ExpressionRef, right: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenBinary(this.ref, op, left, right); return _BinaryenBinary(this.ref, op, left, right);
} }
createHost(op: HostOp, name: string | null = null, operands: BinaryenExpressionRef[] | null = null): BinaryenExpressionRef { createHost(op: HostOp, name: string | null = null, operands: ExpressionRef[] | null = null): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const cStr: CString = allocString(name); const cStr: CString = allocString(name);
const cArr: CArray<i32> = allocI32Array(operands); const cArr: CArray<i32> = allocI32Array(operands);
try { try {
return _BinaryenHost(this.ref, op, cStr, cArr, operands ? (<BinaryenExpressionRef[]>operands).length : 0); return _BinaryenHost(this.ref, op, cStr, cArr, operands ? (<ExpressionRef[]>operands).length : 0);
} finally { } finally {
_free(cArr); _free(cArr);
_free(cStr); _free(cStr);
} }
} }
createGetLocal(index: i32, type: Type): BinaryenExpressionRef { createGetLocal(index: i32, type: NativeType): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenGetLocal(this.ref, index, type); return _BinaryenGetLocal(this.ref, index, type);
} }
createTeeLocal(index: i32, value: BinaryenExpressionRef): BinaryenExpressionRef { createTeeLocal(index: i32, value: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenTeeLocal(this.ref, index, value); return _BinaryenTeeLocal(this.ref, index, value);
} }
createGetGlobal(name: string, type: Type): BinaryenExpressionRef { createGetGlobal(name: string, type: NativeType): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const cStr: CString = allocString(name); const cStr: CString = allocString(name);
try { try {
@ -330,34 +339,54 @@ export class Module {
} }
} }
createAtomicRMW(op: AtomicRMWOp, bytes: i32, offset: i32, ptr: BinaryenExpressionRef, value: BinaryenExpressionRef, type: Type): BinaryenExpressionRef { createLoad(bytes: Index, signed: bool, ptr: ExpressionRef, type: NativeType, offset: Index = 0): ExpressionRef {
if (this.noEmit) return 0;
return _BinaryenLoad(this.ref, bytes, signed ? 1 : 0, offset, /* always aligned */ bytes, type, ptr);
}
createStore(bytes: Index, ptr: ExpressionRef, value: ExpressionRef, type: NativeType, offset: Index = 0): ExpressionRef {
if (this.noEmit) return 0;
return _BinaryenStore(this.ref, bytes, offset, /* always aligned */ bytes, ptr, value, type);
}
createAtomicLoad(bytes: Index, ptr: ExpressionRef, type: NativeType, offset: Index = 0): ExpressionRef {
if (this.noEmit) return 0;
return _BinaryenAtomicLoad(this.ref, bytes, offset, type, ptr);
}
createAtomicStore(bytes: Index, ptr: ExpressionRef, value: ExpressionRef, type: NativeType, offset: Index = 0): ExpressionRef {
if (this.noEmit) return 0;
return _BinaryenAtomicStore(this.ref, bytes, offset, ptr, value, type);
}
createAtomicRMW(op: AtomicRMWOp, bytes: Index, offset: Index, ptr: ExpressionRef, value: ExpressionRef, type: NativeType): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenAtomicRMW(this.ref, op, bytes, offset, ptr, value, type); return _BinaryenAtomicRMW(this.ref, op, bytes, offset, ptr, value, type);
} }
createAtomicCmpxchg(bytes: i32, offset: i32, ptr: BinaryenExpressionRef, expected: BinaryenExpressionRef, replacement: BinaryenExpressionRef, type: Type): BinaryenExpressionRef { createAtomicCmpxchg(bytes: Index, offset: Index, ptr: ExpressionRef, expected: ExpressionRef, replacement: ExpressionRef, type: NativeType): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenAtomicCmpxchg(this.ref, bytes, offset, ptr, expected, replacement, type); return _BinaryenAtomicCmpxchg(this.ref, bytes, offset, ptr, expected, replacement, type);
} }
createAtomicWait(ptr: BinaryenExpressionRef, expected: BinaryenExpressionRef, timeout: BinaryenExpressionRef, expectedType: BinaryenType): BinaryenExpressionRef { createAtomicWait(ptr: ExpressionRef, expected: ExpressionRef, timeout: ExpressionRef, expectedType: NativeType): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenAtomicWait(this.ref, ptr, expected, timeout, expectedType); return _BinaryenAtomicWait(this.ref, ptr, expected, timeout, expectedType);
} }
createAtomicWake(ptr: BinaryenExpressionRef, wakeCount: BinaryenExpressionRef): BinaryenExpressionRef { createAtomicWake(ptr: ExpressionRef, wakeCount: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenAtomicWake(this.ref, ptr, wakeCount); return _BinaryenAtomicWake(this.ref, ptr, wakeCount);
} }
// statements // statements
createSetLocal(index: i32, value: BinaryenExpressionRef): BinaryenExpressionRef { createSetLocal(index: Index, value: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenSetLocal(this.ref, index, value); return _BinaryenSetLocal(this.ref, index, value);
} }
createSetGlobal(name: string, value: BinaryenExpressionRef): BinaryenExpressionRef { createSetGlobal(name: string, value: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const cStr: CString = allocString(name); const cStr: CString = allocString(name);
try { try {
@ -367,7 +396,7 @@ export class Module {
} }
} }
createBlock(label: string | null, children: BinaryenExpressionRef[], type: Type = Type.Undefined): BinaryenExpressionRef { createBlock(label: string | null, children: ExpressionRef[], type: NativeType = NativeType.Undefined): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const cStr: CString = allocString(label); const cStr: CString = allocString(label);
const cArr: CArray<i32> = allocI32Array(children); const cArr: CArray<i32> = allocI32Array(children);
@ -379,7 +408,7 @@ export class Module {
} }
} }
createBreak(label: string | null, condition: BinaryenExpressionRef = 0, value: BinaryenExpressionRef = 0): BinaryenExpressionRef { createBreak(label: string | null, condition: ExpressionRef = 0, value: ExpressionRef = 0): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const cStr: CString = allocString(label); const cStr: CString = allocString(label);
try { try {
@ -389,12 +418,12 @@ export class Module {
} }
} }
createDrop(expression: BinaryenExpressionRef): BinaryenExpressionRef { createDrop(expression: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenDrop(this.ref, expression); return _BinaryenDrop(this.ref, expression);
} }
createLoop(label: string | null, body: BinaryenExpressionRef): BinaryenExpressionRef { createLoop(label: string | null, body: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const cStr: CString = allocString(label); const cStr: CString = allocString(label);
try { try {
@ -404,27 +433,27 @@ export class Module {
} }
} }
createIf(condition: BinaryenExpressionRef, ifTrue: BinaryenExpressionRef, ifFalse: BinaryenExpressionRef = 0): BinaryenExpressionRef { createIf(condition: ExpressionRef, ifTrue: ExpressionRef, ifFalse: ExpressionRef = 0): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenIf(this.ref, condition, ifTrue, ifFalse); return _BinaryenIf(this.ref, condition, ifTrue, ifFalse);
} }
createNop(): BinaryenExpressionRef { createNop(): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenNop(this.ref); return _BinaryenNop(this.ref);
} }
createReturn(expression: BinaryenExpressionRef = 0): BinaryenExpressionRef { createReturn(expression: ExpressionRef = 0): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenReturn(this.ref, expression); return _BinaryenReturn(this.ref, expression);
} }
createSelect(condition: BinaryenExpressionRef, ifTrue: BinaryenExpressionRef, ifFalse: BinaryenExpressionRef): BinaryenExpressionRef { createSelect(condition: ExpressionRef, ifTrue: ExpressionRef, ifFalse: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenSelect(this.ref, condition, ifTrue, ifFalse); return _BinaryenSelect(this.ref, condition, ifTrue, ifFalse);
} }
createSwitch(names: string[], defaultName: string | null, condition: BinaryenExpressionRef, value: BinaryenExpressionRef = 0): BinaryenExpressionRef { createSwitch(names: string[], defaultName: string | null, condition: ExpressionRef, value: ExpressionRef = 0): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const strs: CString[] = new Array(names.length); const strs: CString[] = new Array(names.length);
let i: i32, k: i32 = names.length; let i: i32, k: i32 = names.length;
@ -440,7 +469,7 @@ export class Module {
} }
} }
createCall(target: string, operands: BinaryenExpressionRef[], returnType: Type): BinaryenExpressionRef { createCall(target: string, operands: ExpressionRef[], returnType: NativeType): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const cStr: CString = allocString(target); const cStr: CString = allocString(target);
const cArr: CArray<i32> = allocI32Array(operands); const cArr: CArray<i32> = allocI32Array(operands);
@ -452,7 +481,7 @@ export class Module {
} }
} }
createCallImport(target: string, operands: BinaryenExpressionRef[], returnType: Type): BinaryenExpressionRef { createCallImport(target: string, operands: ExpressionRef[], returnType: NativeType): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const cStr: CString = allocString(target); const cStr: CString = allocString(target);
const cArr: CArray<i32> = allocI32Array(operands); const cArr: CArray<i32> = allocI32Array(operands);
@ -464,14 +493,14 @@ export class Module {
} }
} }
createUnreachable(): BinaryenExpressionRef { createUnreachable(): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _BinaryenUnreachable(this.ref); return _BinaryenUnreachable(this.ref);
} }
// meta // meta
addGlobal(name: string, type: Type, mutable: bool, initializer: BinaryenExpressionRef): BinaryenGlobalRef { addGlobal(name: string, type: NativeType, mutable: bool, initializer: ExpressionRef): GlobalRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const cStr: CString = allocString(name); const cStr: CString = allocString(name);
try { try {
@ -481,7 +510,7 @@ export class Module {
} }
} }
addFunction(name: string, type: BinaryenFunctionTypeRef, varTypes: Type[], body: BinaryenExpressionRef): BinaryenFunctionRef { addFunction(name: string, type: FunctionTypeRef, varTypes: NativeType[], body: ExpressionRef): FunctionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const cStr: CString = allocString(name); const cStr: CString = allocString(name);
const cArr: CArray<i32> = allocI32Array(varTypes); const cArr: CArray<i32> = allocI32Array(varTypes);
@ -493,7 +522,7 @@ export class Module {
} }
} }
addExport(internalName: string, externalName: string): BinaryenExportRef { addExport(internalName: string, externalName: string): ExportRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const cStr1: CString = allocString(internalName); const cStr1: CString = allocString(internalName);
const cStr2: CString = allocString(externalName); const cStr2: CString = allocString(externalName);
@ -515,7 +544,7 @@ export class Module {
} }
} }
addImport(internalName: string, externalModuleName: string, externalBaseName: string, type: BinaryenFunctionTypeRef): BinaryenImportRef { addImport(internalName: string, externalModuleName: string, externalBaseName: string, type: FunctionTypeRef): ImportRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
const cStr1: CString = allocString(internalName); const cStr1: CString = allocString(internalName);
const cStr2: CString = allocString(externalModuleName); const cStr2: CString = allocString(externalModuleName);
@ -539,13 +568,13 @@ export class Module {
} }
} }
setMemory(initial: BinaryenIndex, maximum: BinaryenIndex, segments: MemorySegment[], target: Target, exportName: string | null = null): void { setMemory(initial: Index, maximum: Index, segments: MemorySegment[], target: Target, exportName: string | null = null): void {
if (this.noEmit) return; if (this.noEmit) return;
const cStr: CString = allocString(exportName); const cStr: CString = allocString(exportName);
let i: i32, k: i32 = segments.length; let i: i32, k: i32 = segments.length;
const segs: CArray<u8>[] = new Array(k); const segs: CArray<u8>[] = new Array(k);
const offs: BinaryenExpressionRef[] = new Array(k); const offs: ExpressionRef[] = new Array(k);
const sizs: BinaryenIndex[] = new Array(k); const sizs: Index[] = new Array(k);
for (i = 0; i < k; ++i) { for (i = 0; i < k; ++i) {
const buffer: Uint8Array = segments[i].buffer; const buffer: Uint8Array = segments[i].buffer;
const offset: U64 = segments[i].offset; const offset: U64 = segments[i].offset;
@ -569,7 +598,7 @@ export class Module {
} }
} }
setStart(func: BinaryenFunctionRef): void { setStart(func: FunctionRef): void {
if (this.noEmit) return; if (this.noEmit) return;
_BinaryenSetStart(this.ref, func); _BinaryenSetStart(this.ref, func);
} }
@ -595,42 +624,42 @@ export class Module {
} }
} }
export function getExpressionId(expr: BinaryenExpressionRef): ExpressionId { export function getExpressionId(expr: ExpressionRef): ExpressionId {
return _BinaryenExpressionGetId(expr); return _BinaryenExpressionGetId(expr);
} }
export function getExpressionType(expr: BinaryenExpressionRef): Type { export function getExpressionType(expr: ExpressionRef): NativeType {
return _BinaryenExpressionGetType(expr); return _BinaryenExpressionGetType(expr);
} }
export function printExpression(expr: BinaryenExpressionRef): void { export function printExpression(expr: ExpressionRef): void {
return _BinaryenExpressionPrint(expr); return _BinaryenExpressionPrint(expr);
} }
export function getConstValueI32(expr: BinaryenExpressionRef): i32 { export function getConstValueI32(expr: ExpressionRef): i32 {
return _BinaryenConstGetValueI32(expr); return _BinaryenConstGetValueI32(expr);
} }
export function getConstValueI64Low(expr: BinaryenExpressionRef): i32 { export function getConstValueI64Low(expr: ExpressionRef): i32 {
return _BinaryenConstGetValueI64Low(expr); return _BinaryenConstGetValueI64Low(expr);
} }
export function getConstValueI64High(expr: BinaryenExpressionRef): i32 { export function getConstValueI64High(expr: ExpressionRef): i32 {
return _BinaryenConstGetValueI64High(expr); return _BinaryenConstGetValueI64High(expr);
} }
export function getConstValueI64(expr: BinaryenExpressionRef): I64 { export function getConstValueI64(expr: ExpressionRef): I64 {
return new I64( return new I64(
_BinaryenConstGetValueI64Low(expr), _BinaryenConstGetValueI64Low(expr),
_BinaryenConstGetValueI64High(expr) _BinaryenConstGetValueI64High(expr)
); );
} }
export function getConstValueF32(expr: BinaryenExpressionRef): f32 { export function getConstValueF32(expr: ExpressionRef): f32 {
return _BinaryenConstGetValueF32(expr); return _BinaryenConstGetValueF32(expr);
} }
export function getConstValueF64(expr: BinaryenExpressionRef): f64 { export function getConstValueF64(expr: ExpressionRef): f64 {
return _BinaryenConstGetValueF64(expr); return _BinaryenConstGetValueF64(expr);
} }
@ -658,22 +687,22 @@ export class Relooper {
private constructor() {} private constructor() {}
addBlock(code: BinaryenExpressionRef): RelooperBlockRef { addBlock(code: ExpressionRef): RelooperBlockRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _RelooperAddBlock(this.ref, code); return _RelooperAddBlock(this.ref, code);
} }
addBranch(from: RelooperBlockRef, to: RelooperBlockRef, condition: BinaryenExpressionRef = 0, code: BinaryenExpressionRef = 0): void { addBranch(from: RelooperBlockRef, to: RelooperBlockRef, condition: ExpressionRef = 0, code: ExpressionRef = 0): void {
if (this.noEmit) return; if (this.noEmit) return;
_RelooperAddBranch(from, to, condition, code); _RelooperAddBranch(from, to, condition, code);
} }
addBlockWithSwitch(code: BinaryenExpressionRef, condition: BinaryenExpressionRef): RelooperBlockRef { addBlockWithSwitch(code: ExpressionRef, condition: ExpressionRef): RelooperBlockRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _RelooperAddBlockWithSwitch(this.ref, code, condition); return _RelooperAddBlockWithSwitch(this.ref, code, condition);
} }
addBranchForSwitch(from: RelooperBlockRef, to: RelooperBlockRef, indexes: i32[], code: BinaryenExpressionRef = 0): void { addBranchForSwitch(from: RelooperBlockRef, to: RelooperBlockRef, indexes: i32[], code: ExpressionRef = 0): void {
if (this.noEmit) return; if (this.noEmit) return;
const cArr: CArray<i32> = allocI32Array(indexes); const cArr: CArray<i32> = allocI32Array(indexes);
try { try {
@ -683,7 +712,7 @@ export class Relooper {
} }
} }
renderAndDispose(entry: RelooperBlockRef, labelHelper: BinaryenIndex): BinaryenExpressionRef { renderAndDispose(entry: RelooperBlockRef, labelHelper: Index): ExpressionRef {
if (this.noEmit) return 0; if (this.noEmit) return 0;
return _RelooperRenderAndDispose(this.ref, entry, labelHelper, this.module.ref); return _RelooperRenderAndDispose(this.ref, entry, labelHelper, this.module.ref);
} }

View File

@ -832,7 +832,7 @@ export class Function extends Element {
template: FunctionPrototype; template: FunctionPrototype;
/** Concrete type arguments. */ /** Concrete type arguments. */
typeArguments: Type[]; typeArguments: Type[];
/** Concrete function parameters. */ /** Concrete function parameters. Excluding `this` if an instance method. */
parameters: Parameter[]; parameters: Parameter[];
/** Concrete return type. */ /** Concrete return type. */
returnType: Type; returnType: Type;
@ -877,7 +877,7 @@ export class Function extends Element {
addLocal(type: Type, name: string | null = null): Local { addLocal(type: Type, name: string | null = null): Local {
// if it has a name, check previously as this method will throw otherwise // if it has a name, check previously as this method will throw otherwise
let localIndex = this.parameters.length + this.additionalLocals.length; let localIndex = this.parameters.length + this.additionalLocals.length;
if (this.instanceMethodOf) localIndex++; // plus 'this' if (this.isInstance) localIndex++; // plus 'this'
const local: Local = new Local(this.template.program, name ? name : "anonymous$" + localIndex.toString(10), localIndex, type); const local: Local = new Local(this.template.program, name ? name : "anonymous$" + localIndex.toString(10), localIndex, type);
if (name) { if (name) {
if (this.locals.has(<string>name)) if (this.locals.has(<string>name))

View File

@ -20,15 +20,15 @@
}, },
"files": [ "files": [
"ast.ts", "ast.ts",
"binaryen.d.ts",
"binaryen.ts",
"compiler.ts", "compiler.ts",
"diagnosticMessages.generated.ts", "diagnosticMessages.generated.ts",
"diagnostics.ts", "diagnostics.ts",
"evaluator.ts", "evaluator.ts",
"glue/binaryen.d.ts",
"glue/js.d.ts", "glue/js.d.ts",
"glue/js.ts", "glue/js.ts",
"index.ts", "index.ts",
"moddule.ts",
"parser.ts", "parser.ts",
"program.ts", "program.ts",
"tokenizer.ts", "tokenizer.ts",

View File

@ -1,171 +0,0 @@
// incrementing precedence
a
=
b
?
X
:
c
||
d
&&
e
|
f
^
g
&
h
==
i
<
j
<<
k
+
l
/
++
m
++
;
// decrementing precedence
++
a
++
/
b
+
c
<<
d
<
e
==
f
&
g
^
h
|
i
&&
j
||
k
?
X
:
y
=
l
;
// assignment (right-to-left)
a
=
b
+=
c
-=
d
**=
e
*=
f
/=
g
%=
h
<<=
i
>>=
j
>>>=
k
&=
l
^=
m
|=
n
;
// equality (left-to-right)
a
==
b
!=
c
===
d
!==
e
;
// relational (left-to-right)
a
<
b
<=
c
>
d
>=
e
;
// bitwise shift (left-to-right)
a
<<
b
>>
c
>>>
d
;
// addition (left-to-right)
a
+
b
-
c
;
// exponentiation (right-to-left), multiplication (left-to-right)
a
**
b
*
c
/
d
%
e
**
f
*
g
;
// prefix (right-to-left)
delete
void
typeof
--
++
-
+
~
!
a
;
// parenthesized
(
a
+
(
b
/
c
)
-
d
)
*
e
;

View File

@ -14,15 +14,7 @@ files.forEach(filename => {
const text = fs.readFileSync(__dirname + "/fixtures/" + filename, { encoding: "utf8" }).replace(/\r?\n/g, "\n").replace(/^\/\/.*\r?\n/mg, ""); const text = fs.readFileSync(__dirname + "/fixtures/" + filename, { encoding: "utf8" }).replace(/\r?\n/g, "\n").replace(/^\/\/.*\r?\n/mg, "");
parser.parseFile(text, filename, true); parser.parseFile(text, filename, true);
var sb: string[] = []; var sb: string[] = [];
if (isTree) { parser.program.sources[0].serialize(sb);
const statements = parser.program.sources[0].statements;
statements.forEach(stmt => {
if (stmt.kind != NodeKind.EXPRESSION) return;
(<ExpressionStatement>stmt).expression.serializeAsTree(sb, 0);
sb.push(";\n");
});
} else
parser.program.sources[0].serialize(sb);
const actual = sb.join(""); const actual = sb.join("");
const expected = isTree ? text : text.replace(/^\s+/mg, ""); const expected = isTree ? text : text.replace(/^\s+/mg, "");
const diffs = diff.diffLines(expected, actual); const diffs = diff.diffLines(expected, actual);