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;
return expr;
}
abstract serializeAsTree(sb: string[], indent: i32): void;
}
export const enum LiteralKind {
@ -384,20 +382,6 @@ export class ArrayLiteralExpression extends LiteralExpression {
}
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 {
@ -424,24 +408,6 @@ export class AssertionExpression extends Expression {
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 {
@ -458,14 +424,6 @@ export class BinaryExpression extends Expression {
sb.push(" ");
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 {
@ -495,12 +453,6 @@ export class CallExpression extends Expression {
}
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 {
@ -515,15 +467,6 @@ export class ElementAccessExpression extends Expression {
this.elementExpression.serialize(sb);
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 {
@ -534,12 +477,6 @@ export class FloatLiteralExpression extends LiteralExpression {
serialize(sb: string[]): void {
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 {
@ -550,12 +487,6 @@ export class IdentifierExpression extends Expression {
serialize(sb: string[]): void {
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 {
@ -566,12 +497,6 @@ export class IntegerLiteralExpression extends LiteralExpression {
serialize(sb: string[]): void {
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 {
@ -582,12 +507,6 @@ export class NewExpression extends CallExpression {
sb.push("new ");
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 {
@ -605,14 +524,6 @@ export class ParenthesizedExpression extends Expression {
this.expression.serialize(sb);
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 {
@ -626,12 +537,6 @@ export class PropertyAccessExpression extends Expression {
sb.push(".");
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 {
@ -642,12 +547,6 @@ export class RegexpLiteralExpression extends LiteralExpression {
serialize(sb: string[]): void {
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 {
@ -664,16 +563,6 @@ export class SelectExpression extends Expression {
sb.push(" : ");
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 {
@ -684,12 +573,6 @@ export class StringLiteralExpression extends LiteralExpression {
serialize(sb: string[]): void {
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 {
@ -729,17 +612,6 @@ export class UnaryPostfixExpression extends UnaryExpression {
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 {
@ -750,13 +622,6 @@ export class UnaryPrefixExpression extends UnaryExpression {
sb.push(operatorTokenToString(this.operator));
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
@ -1937,8 +1802,3 @@ function builderEndsWith(sb: string[], code: CharCode): bool {
}
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 { 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 { CharCode, I64, U64, normalizePath, sb } from "./util";
import { Token, Range } from "./tokenizer";
@ -77,14 +77,14 @@ import {
export enum Target {
/** WebAssembly with 32-bit pointers. */
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
}
export class Options {
/** WebAssembly target. Defaults to {@link 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;
/** If true, compiles everything instead of just reachable code. */
noTreeShaking: bool = false;
@ -92,27 +92,40 @@ export class Options {
export class Compiler extends DiagnosticEmitter {
/** Program reference. */
program: Program;
/** Provided options. */
options: Options;
/** Module instance being compiled. */
module: Module;
/** Start function being compiled. */
startFunction: Function;
startFunctionBody: BinaryenExpressionRef[] = new Array();
/** Start function expressions. */
startFunctionBody: ExpressionRef[] = new Array();
/** Current type in compilation. */
currentType: Type = Type.void;
/** Current function in compilation. */
currentFunction: Function;
/** Marker indicating whether continue statements are allowed in the current break context. */
disallowContinue: bool = true;
/** Counting memory offset. */
memoryOffset: U64 = new U64(8, 0); // leave space for (any size of) NULL
/** Memory segments being compiled. */
memorySegments: MemorySegment[] = new Array();
/** Already processed file names. */
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 {
const compiler: Compiler = new Compiler(program, options);
return compiler.compile();
}
/** Constructs a new compiler for a {@link Program} using the specified options. */
constructor(program: Program, options: Options | null = null) {
super(program.diagnostics);
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)
}
/** Performs compilation of the underlying {@link Program} to a {@link Module}. */
compile(): Module {
const program: Program = this.program;
@ -141,11 +155,11 @@ export class Compiler extends DiagnosticEmitter {
// make start function if not empty
if (this.startFunctionBody.length) {
let typeRef: BinaryenFunctionTypeRef = this.module.getFunctionTypeBySignature(BinaryenType.None, []);
let typeRef: FunctionTypeRef = this.module.getFunctionTypeBySignature(NativeType.None, []);
if (!typeRef)
typeRef = this.module.addFunctionType("v", BinaryenType.None, []);
typeRef = this.module.addFunctionType("v", NativeType.None, []);
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;
element.type = type;
}
const binaryenType: BinaryenType = typeToBinaryenType(<Type>type);
let initializer: BinaryenExpressionRef;
const nativeType: NativeType = typeToNativeType(<Type>type);
let initializer: ExpressionRef;
let initializeInStart: bool;
if (element.hasConstantValue) {
if (type.isLongInteger)
@ -304,23 +318,23 @@ export class Compiler extends DiagnosticEmitter {
} else
initializer = this.module.createI32(element.constantIntegerValue ? element.constantIntegerValue.toI32() : 0);
initializeInStart = false;
this.module.addGlobal(element.internalName, binaryenType, element.isMutable, initializer);
this.module.addGlobal(element.internalName, nativeType, element.isMutable, initializer);
} else if (declaration) {
if (declaration.initializer) {
initializer = this.compileExpression(declaration.initializer, type);
initializeInStart = declaration.initializer.kind != NodeKind.LITERAL; // MVP doesn't support complex initializers
} else {
initializer = typeToBinaryenZero(this.module, type);
initializer = typeToNativeZero(this.module, type);
initializeInStart = false;
}
} else
throw new Error("unexpected missing declaration or constant value");
const internalName: string = element.internalName;
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));
} else
this.module.addGlobal(internalName, BinaryenType.I32, element.isMutable, initializer);
this.module.addGlobal(internalName, NativeType.I32, element.isMutable, initializer);
return element.compiled = true;
}
@ -340,10 +354,10 @@ export class Compiler extends DiagnosticEmitter {
let previousInternalName: string | null = null;
for (let [key, val] of element.members) {
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) {
const declaration: EnumValueDeclaration = val.declaration;
let initializer: BinaryenExpressionRef;
let initializer: ExpressionRef;
let initializeInStart: bool = false;
if (declaration.value) {
initializer = this.compileExpression(<Expression>declaration.value, Type.i32);
@ -353,16 +367,16 @@ export class Compiler extends DiagnosticEmitter {
initializeInStart = false;
} else {
initializer = this.module.createBinary(BinaryOp.AddI32,
this.module.createGetGlobal(previousInternalName, BinaryenType.I32),
this.module.createGetGlobal(previousInternalName, NativeType.I32),
this.module.createI32(1)
);
initializeInStart = true;
}
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));
} else
this.module.addGlobal(val.internalName, BinaryenType.I32, false, initializer);
this.module.addGlobal(val.internalName, NativeType.I32, false, initializer);
} else
throw new Error("unexpected missing declaration or constant value");
previousInternalName = val.internalName;
@ -403,24 +417,24 @@ export class Compiler extends DiagnosticEmitter {
// compile statements
const previousFunction: Function = this.currentFunction;
this.currentFunction = instance;
const stmts: BinaryenExpressionRef[] = this.compileStatements(<Statement[]>declaration.statements);
const stmts: ExpressionRef[] = this.compileStatements(<Statement[]>declaration.statements);
this.currentFunction = previousFunction;
// create the function
let k: i32 = instance.parameters.length;
const binaryenResultType: BinaryenType = typeToBinaryenType(instance.returnType);
const binaryenParamTypes: BinaryenType[] = new Array(k);
const binaryenResultType: NativeType = typeToNativeType(instance.returnType);
const binaryenParamTypes: NativeType[] = new Array(k);
const signatureNameParts: string[] = new Array(k + 1);
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[k] = typeToSignatureNamePart(instance.returnType);
let binaryenTypeRef: BinaryenFunctionTypeRef = this.module.getFunctionTypeBySignature(binaryenResultType, binaryenParamTypes);
if (!binaryenTypeRef)
binaryenTypeRef = this.module.addFunctionType(signatureNameParts.join(""), binaryenResultType, binaryenParamTypes);
let typeRef: FunctionTypeRef = this.module.getFunctionTypeBySignature(binaryenResultType, binaryenParamTypes);
if (!typeRef)
typeRef = this.module.addFunctionType(signatureNameParts.join(""), binaryenResultType, binaryenParamTypes);
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)
this.module.addExport(internalName, <string>instance.globalExportName);
}
@ -583,7 +597,7 @@ export class Compiler extends DiagnosticEmitter {
// statements
compileStatement(statement: Statement): BinaryenExpressionRef {
compileStatement(statement: Statement): ExpressionRef {
switch (statement.kind) {
case NodeKind.BLOCK:
@ -631,19 +645,19 @@ export class Compiler extends DiagnosticEmitter {
throw new Error("unexpected statement kind");
}
compileStatements(statements: Statement[]): BinaryenExpressionRef[] {
compileStatements(statements: Statement[]): ExpressionRef[] {
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)
stmts[i] = this.compileStatement(statements[i]);
return stmts;
}
compileBlockStatement(statement: BlockStatement): BinaryenExpressionRef {
return this.module.createBlock(null, this.compileStatements(statement.statements), BinaryenType.None);
compileBlockStatement(statement: BlockStatement): ExpressionRef {
return this.module.createBlock(null, this.compileStatements(statement.statements), NativeType.None);
}
compileBreakStatement(statement: BreakStatement): BinaryenExpressionRef {
compileBreakStatement(statement: BreakStatement): ExpressionRef {
if (statement.label)
throw new Error("not implemented");
const context: string | null = this.currentFunction.breakContext;
@ -653,7 +667,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable();
}
compileContinueStatement(statement: ContinueStatement): BinaryenExpressionRef {
compileContinueStatement(statement: ContinueStatement): ExpressionRef {
if (statement.label)
throw new Error("not implemented");
const context: string | null = this.currentFunction.breakContext;
@ -663,10 +677,10 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable();
}
compileDoStatement(statement: DoStatement): BinaryenExpressionRef {
compileDoStatement(statement: DoStatement): ExpressionRef {
const label: string = this.currentFunction.enterBreakContext();
const condition: BinaryenExpressionRef = this.compileExpression(statement.condition, Type.i32);
const body: BinaryenExpressionRef = this.compileStatement(statement.statement);
const condition: ExpressionRef = this.compileExpression(statement.condition, Type.i32);
const body: ExpressionRef = this.compileStatement(statement.statement);
this.currentFunction.leaveBreakContext();
const breakLabel: string = "break$" + label;
const continueLabel: string = "continue$" + label;
@ -675,24 +689,24 @@ export class Compiler extends DiagnosticEmitter {
this.module.createBlock(null, [
body,
this.module.createBreak(continueLabel, condition)
], BinaryenType.None))
], BinaryenType.None);
], NativeType.None))
], NativeType.None);
}
compileEmptyStatement(statement: EmptyStatement): BinaryenExpressionRef {
compileEmptyStatement(statement: EmptyStatement): ExpressionRef {
return this.module.createNop();
}
compileExpressionStatement(statement: ExpressionStatement): BinaryenExpressionRef {
compileExpressionStatement(statement: ExpressionStatement): ExpressionRef {
return this.compileExpression(statement.expression, Type.void);
}
compileForStatement(statement: ForStatement): BinaryenExpressionRef {
compileForStatement(statement: ForStatement): ExpressionRef {
const context: string = this.currentFunction.enterBreakContext();
const initializer: BinaryenExpressionRef = 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 incrementor: BinaryenExpressionRef = statement.incrementor ? this.compileExpression(<Expression>statement.incrementor, Type.void) : this.module.createNop();
const body: BinaryenExpressionRef = this.compileStatement(statement.statement);
const initializer: ExpressionRef = statement.initializer ? this.compileStatement(<Statement>statement.initializer) : this.module.createNop();
const condition: ExpressionRef = statement.condition ? this.compileExpression(<Expression>statement.condition, Type.i32) : this.module.createI32(1);
const incrementor: ExpressionRef = statement.incrementor ? this.compileExpression(<Expression>statement.incrementor, Type.void) : this.module.createNop();
const body: ExpressionRef = this.compileStatement(statement.statement);
this.currentFunction.leaveBreakContext();
const continueLabel: string = "continue$" + context;
const breakLabel: string = "break$" + context;
@ -703,27 +717,27 @@ export class Compiler extends DiagnosticEmitter {
body,
incrementor,
this.module.createBreak(continueLabel)
], BinaryenType.None))
], BinaryenType.None))
], BinaryenType.None);
], NativeType.None))
], NativeType.None))
], NativeType.None);
}
compileIfStatement(statement: IfStatement): BinaryenExpressionRef {
const condition: BinaryenExpressionRef = this.compileExpression(statement.condition, Type.i32);
const ifTrue: BinaryenExpressionRef = this.compileStatement(statement.statement);
const ifFalse: BinaryenExpressionRef = statement.elseStatement ? this.compileStatement(<Statement>statement.elseStatement) : 0;
compileIfStatement(statement: IfStatement): ExpressionRef {
const condition: ExpressionRef = this.compileExpression(statement.condition, Type.i32);
const ifTrue: ExpressionRef = this.compileStatement(statement.statement);
const ifFalse: ExpressionRef = statement.elseStatement ? this.compileStatement(<Statement>statement.elseStatement) : 0;
return this.module.createIf(condition, ifTrue, ifFalse);
}
compileReturnStatement(statement: ReturnStatement): BinaryenExpressionRef {
compileReturnStatement(statement: ReturnStatement): ExpressionRef {
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.createUnreachable();
}
compileSwitchStatement(statement: SwitchStatement): BinaryenExpressionRef {
compileSwitchStatement(statement: SwitchStatement): ExpressionRef {
const context: string = this.currentFunction.enterBreakContext();
const previousDisallowContinue: bool = this.disallowContinue;
this.disallowContinue = true;
@ -733,18 +747,18 @@ export class Compiler extends DiagnosticEmitter {
let i: i32, k: i32 = statement.cases.length;
// 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
// 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 defaultIndex: i32 = -1;
for (i = 0; i < k; ++i) {
const case_: SwitchCase = statement.cases[i];
if (case_.label) {
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)
));
} else
@ -758,18 +772,18 @@ export class Compiler extends DiagnosticEmitter {
) + "$" + context);
// 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) {
const case_: SwitchCase = statement.cases[i];
const nextLabel: string = i == k - 1
? "break$" + context
: "case" + (i + 1).toString(10) + "$" + context;
const l: i32 = case_.statements.length;
const body: BinaryenExpressionRef[] = new Array(1 + l);
const body: ExpressionRef[] = new Array(1 + l);
body[0] = currentBlock;
for (let j: i32 = 0; j < l; ++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.disallowContinue = previousDisallowContinue;
@ -777,17 +791,17 @@ export class Compiler extends DiagnosticEmitter {
return currentBlock;
}
compileThrowStatement(statement: ThrowStatement): BinaryenExpressionRef {
compileThrowStatement(statement: ThrowStatement): ExpressionRef {
return this.module.createUnreachable(); // TODO: waiting for exception-handling spec
}
compileTryStatement(statement: TryStatement): BinaryenExpressionRef {
compileTryStatement(statement: TryStatement): ExpressionRef {
throw new Error("not implemented");
// can't yet support something like: try { return ... } finally { ... }
// worthwhile to investigate lowering returns to block results (here)?
}
compileVariableStatement(statement: VariableStatement): BinaryenExpressionRef {
compileVariableStatement(statement: VariableStatement): ExpressionRef {
const declarations: VariableDeclaration[] = statement.declarations;
// top-level variables become globals
@ -798,7 +812,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createNop();
}
// 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) {
const declaration: VariableDeclaration = declarations[i];
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 condition: BinaryenExpressionRef = this.compileExpression(statement.condition, Type.i32);
const condition: ExpressionRef = this.compileExpression(statement.condition, Type.i32);
const breakLabel: string = "break$" + label;
const continueLabel: string = "continue$" + label;
const body: BinaryenExpressionRef = this.compileStatement(statement.statement);
const body: ExpressionRef = this.compileStatement(statement.statement);
this.currentFunction.leaveBreakContext();
return this.module.createBlock(breakLabel, [
this.module.createLoop(continueLabel,
this.module.createIf(condition, this.module.createBlock(null, [
body,
this.module.createBreak(continueLabel)
], BinaryenType.None))
], NativeType.None))
)
], BinaryenType.None);
], NativeType.None);
}
// expressions
compileExpression(expression: Expression, contextualType: Type, convert: bool = true): BinaryenExpressionRef {
compileExpression(expression: Expression, contextualType: Type, convert: bool = true): ExpressionRef {
this.currentType = contextualType;
let expr: BinaryenExpressionRef;
let expr: ExpressionRef;
switch (expression.kind) {
case NodeKind.ASSERTION:
@ -906,7 +920,7 @@ export class Compiler extends DiagnosticEmitter {
return expr;
}
convertExpression(expr: BinaryenExpressionRef, fromType: Type, toType: Type): BinaryenExpressionRef {
convertExpression(expr: ExpressionRef, fromType: Type, toType: Type): ExpressionRef {
// void to any
if (fromType.kind == TypeKind.VOID)
@ -1059,19 +1073,19 @@ export class Compiler extends DiagnosticEmitter {
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
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.compileExpression(expression.expression, contextualType);
}
compileBinaryExpression(expression: BinaryExpression, contextualType: Type): BinaryenExpressionRef {
compileBinaryExpression(expression: BinaryExpression, contextualType: Type): ExpressionRef {
let op: BinaryOp;
let left: BinaryenExpressionRef;
let right: BinaryenExpressionRef;
let left: ExpressionRef;
let right: ExpressionRef;
let compound: Token = 0;
switch (expression.operator) {
@ -1287,12 +1301,12 @@ export class Compiler extends DiagnosticEmitter {
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);
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);
if (!element)
return this.module.createUnreachable();
@ -1307,12 +1321,12 @@ export class Compiler extends DiagnosticEmitter {
if (element.kind == ElementKind.GLOBAL && (<Global>element).type) {
if (tee) {
const globalBinaryenType: BinaryenType = typeToBinaryenType(<Type>(<Global>element).type);
const globalNativeType: NativeType = typeToNativeType(<Type>(<Global>element).type);
this.currentType = <Type>(<Global>element).type;
return this.module.createBlock(null, [ // teeGlobal
this.module.createSetGlobal((<Global>element).internalName, valueWithCorrectType),
this.module.createGetGlobal((<Global>element).internalName, globalBinaryenType)
], globalBinaryenType);
this.module.createGetGlobal((<Global>element).internalName, globalNativeType)
], globalNativeType);
}
return this.module.createSetGlobal((<Global>element).internalName, valueWithCorrectType);
}
@ -1322,7 +1336,17 @@ export class Compiler extends DiagnosticEmitter {
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
if (!element)
return this.module.createUnreachable();
@ -1336,40 +1360,57 @@ export class Compiler extends DiagnosticEmitter {
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)
this.compileFunction(functionInstance);
// validate and compile arguments
const parameters: Parameter[] = functionInstance.parameters;
let k: i32 = parameters.length;
if (argumentExpressions.length > k) {
this.error(DiagnosticCode.Expected_0_arguments_but_got_1, reportNode.range, k.toString(10), argumentExpressions.length.toString(10));
const parameterCount: i32 = parameters.length;
const argumentCount: i32 = argumentExpressions.length;
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();
}
const operands: BinaryenExpressionRef[] = new Array(k);
for (let i: i32 = 0; i < k; ++i) {
const operands: ExpressionRef[] = new Array(parameterCount);
for (let i: i32 = 0; i < parameterCount; ++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 {
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);
} else {
this.error(DiagnosticCode.Expected_at_least_0_arguments_but_got_1, reportNode.range, (i + 1).toString(10), argumentExpressions.length.toString(10));
} else { // too few arguments
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.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
if (!element)
return this.module.createUnreachable();
throw new Error("not implemented");
}
compileIdentifierExpression(expression: IdentifierExpression, contextualType: Type): BinaryenExpressionRef {
compileIdentifierExpression(expression: IdentifierExpression, contextualType: Type): ExpressionRef {
// null
if (expression.kind == NodeKind.NULL) {
@ -1397,7 +1438,7 @@ export class Compiler extends DiagnosticEmitter {
} else if (expression.kind == NodeKind.THIS) {
if (this.currentFunction.instanceMethodOf) {
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.currentType = this.options.target == Target.WASM64 ? Type.u64 : Type.u32;
@ -1431,12 +1472,12 @@ export class Compiler extends DiagnosticEmitter {
// 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
if (element.kind == ElementKind.GLOBAL)
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();
// field
@ -1451,7 +1492,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable();
}
compileLiteralExpression(expression: LiteralExpression, contextualType: Type): BinaryenExpressionRef {
compileLiteralExpression(expression: LiteralExpression, contextualType: Type): ExpressionRef {
switch (expression.literalKind) {
// case LiteralKind.ARRAY:
@ -1484,62 +1525,62 @@ export class Compiler extends DiagnosticEmitter {
throw new Error("not implemented");
}
compileNewExpression(expression: NewExpression, contextualType: Type): BinaryenExpressionRef {
compileNewExpression(expression: NewExpression, contextualType: Type): ExpressionRef {
throw new Error("not implemented");
}
compileParenthesizedExpression(expression: ParenthesizedExpression, contextualType: Type): BinaryenExpressionRef {
compileParenthesizedExpression(expression: ParenthesizedExpression, contextualType: Type): ExpressionRef {
return this.compileExpression(expression.expression, contextualType);
}
compilePropertyAccessExpression(expression: PropertyAccessExpression, contextualType: Type): BinaryenExpressionRef {
compilePropertyAccessExpression(expression: PropertyAccessExpression, contextualType: Type): ExpressionRef {
throw new Error("not implemented");
}
compileSelectExpression(expression: SelectExpression, contextualType: Type): BinaryenExpressionRef {
const condition: BinaryenExpressionRef = this.compileExpression(expression.condition, Type.i32);
const ifThen: BinaryenExpressionRef = this.compileExpression(expression.ifThen, contextualType);
const ifElse: BinaryenExpressionRef = this.compileExpression(expression.ifElse, contextualType);
compileSelectExpression(expression: SelectExpression, contextualType: Type): ExpressionRef {
const condition: ExpressionRef = this.compileExpression(expression.condition, Type.i32);
const ifThen: ExpressionRef = this.compileExpression(expression.ifThen, contextualType);
const ifElse: ExpressionRef = this.compileExpression(expression.ifElse, contextualType);
return this.module.createSelect(condition, ifThen, ifElse);
}
compileUnaryPostfixExpression(expression: UnaryPostfixExpression, contextualType: Type): BinaryenExpressionRef {
compileUnaryPostfixExpression(expression: UnaryPostfixExpression, contextualType: Type): ExpressionRef {
const operator: Token = expression.operator;
let op: BinaryOp;
let binaryenType: BinaryenType;
let binaryenOne: BinaryenExpressionRef;
let nativeType: NativeType;
let nativeOne: ExpressionRef;
if (contextualType == Type.f32) {
op = operator == Token.PLUS_PLUS ? BinaryOp.AddF32 : BinaryOp.SubF32;
binaryenType = BinaryenType.F32;
binaryenOne = this.module.createF32(1);
nativeType = NativeType.F32;
nativeOne = this.module.createF32(1);
} else if (contextualType == Type.f64) {
op = operator == Token.PLUS_PLUS ? BinaryOp.AddF64 : BinaryOp.SubF64;
binaryenType = BinaryenType.F64;
binaryenOne = this.module.createF64(1);
nativeType = NativeType.F64;
nativeOne = this.module.createF64(1);
} else if (contextualType.isLongInteger) {
op = operator == Token.PLUS_PLUS ? BinaryOp.AddI64 : BinaryOp.SubI64;
binaryenType = BinaryenType.I64;
binaryenOne = this.module.createI64(1, 0);
nativeType = NativeType.I64;
nativeOne = this.module.createI64(1, 0);
} else {
op = operator == Token.PLUS_PLUS ? BinaryOp.AddI32 : BinaryOp.SubI32;
binaryenType = BinaryenType.I32;
binaryenOne = this.module.createI32(1);
nativeType = NativeType.I32;
nativeOne = this.module.createI32(1);
}
const getValue: BinaryenExpressionRef = this.compileExpression(expression.expression, contextualType);
const setValue: BinaryenExpressionRef = this.compileAssignmentWithValue(expression.expression, this.module.createBinary(op, getValue, binaryenOne), false); // reports
const getValue: ExpressionRef = this.compileExpression(expression.expression, contextualType);
const setValue: ExpressionRef = this.compileAssignmentWithValue(expression.expression, this.module.createBinary(op, getValue, nativeOne), false); // reports
return this.module.createBlock(null, [
getValue,
setValue
], binaryenType);
], nativeType);
}
compileUnaryPrefixExpression(expression: UnaryPrefixExpression, contextualType: Type): BinaryenExpressionRef {
compileUnaryPrefixExpression(expression: UnaryPrefixExpression, contextualType: Type): ExpressionRef {
const operandExpression: Expression = expression.expression;
let operand: BinaryenExpressionRef;
let operand: ExpressionRef;
let op: UnaryOp;
switch (expression.operator) {
@ -1610,27 +1651,27 @@ export class Compiler extends DiagnosticEmitter {
// helpers
function typeToBinaryenType(type: Type): BinaryenType {
function typeToNativeType(type: Type): NativeType {
return type.kind == TypeKind.F32
? BinaryenType.F32
? NativeType.F32
: type.kind == TypeKind.F64
? BinaryenType.F64
? NativeType.F64
: type.isLongInteger
? BinaryenType.I64
? NativeType.I64
: type.isAnyInteger || type.kind == TypeKind.BOOL
? BinaryenType.I32
: BinaryenType.None;
? NativeType.I32
: NativeType.None;
}
function typesToBinaryenTypes(types: Type[]): BinaryenType[] {
function typesToNativeTypes(types: Type[]): NativeType[] {
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)
ret[i] = typeToBinaryenType(types[i]);
ret[i] = typeToNativeType(types[i]);
return ret;
}
function typeToBinaryenZero(module: Module, type: Type): BinaryenExpressionRef {
function typeToNativeZero(module: Module, type: Type): ExpressionRef {
return type.kind == TypeKind.F32
? module.createF32(0)
: type.kind == TypeKind.F64
@ -1640,7 +1681,7 @@ function typeToBinaryenZero(module: Module, type: Type): BinaryenExpressionRef {
: module.createI32(0);
}
function typeToBinaryenOne(module: Module, type: Type): BinaryenExpressionRef {
function typeToBinaryenOne(module: Module, type: Type): ExpressionRef {
return type.kind == TypeKind.F32
? module.createF32(1)
: type.kind == TypeKind.F64

View File

@ -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 = ".";

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 _BinaryenNop(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 _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;
@ -263,6 +265,12 @@ declare function _BinaryenConstGetValueF64(expr: BinaryenExpressionRef): f64;
declare type BinaryenFunctionRef = usize;
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;
@ -289,7 +297,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 _BinaryenModuleRunPasses(module: BinaryenModuleRef, passes: CArray<CString>, numPasses: BinaryenIndex): 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;

View File

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

View File

@ -1,7 +1,16 @@
import { I64, U64 } from "./util";
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(),
I32 = _BinaryenInt32(),
I64 = _BinaryenInt64(),
@ -201,11 +210,11 @@ export class MemorySegment {
export class Module {
ref: BinaryenModuleRef;
ref: ModuleRef;
lit: BinaryenLiteral;
noEmit: bool;
static MAX_MEMORY_WASM32: BinaryenIndex = 0xffff;
static MAX_MEMORY_WASM32: Index = 0xffff;
static create(): Module {
const module: Module = new Module();
@ -240,7 +249,7 @@ export class Module {
// types
addFunctionType(name: string, result: Type, paramTypes: Type[]): BinaryenFunctionRef {
addFunctionType(name: string, result: NativeType, paramTypes: NativeType[]): FunctionRef {
if (this.noEmit) return 0;
const cStr: CString = allocString(name);
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;
const cArr: CArray<i32> = allocI32Array(paramTypes);
try {
@ -264,63 +273,63 @@ export class Module {
// expressions
createI32(value: i32): BinaryenExpressionRef {
createI32(value: i32): ExpressionRef {
if (this.noEmit) return 0;
_BinaryenLiteralInt32(this.lit, value);
return _BinaryenConst(this.ref, this.lit);
}
createI64(lo: i32, hi: i32): BinaryenExpressionRef {
createI64(lo: i32, hi: i32): ExpressionRef {
if (this.noEmit) return 0;
_BinaryenLiteralInt64(this.lit, lo, hi);
return _BinaryenConst(this.ref, this.lit);
}
createF32(value: f32): BinaryenExpressionRef {
createF32(value: f32): ExpressionRef {
if (this.noEmit) return 0;
_BinaryenLiteralFloat32(this.lit, value);
return _BinaryenConst(this.ref, this.lit);
}
createF64(value: f64): BinaryenExpressionRef {
createF64(value: f64): ExpressionRef {
if (this.noEmit) return 0;
_BinaryenLiteralFloat64(this.lit, value);
return _BinaryenConst(this.ref, this.lit);
}
createUnary(op: UnaryOp, expr: BinaryenExpressionRef): BinaryenExpressionRef {
createUnary(op: UnaryOp, expr: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0;
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;
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;
const cStr: CString = allocString(name);
const cArr: CArray<i32> = allocI32Array(operands);
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 {
_free(cArr);
_free(cStr);
}
}
createGetLocal(index: i32, type: Type): BinaryenExpressionRef {
createGetLocal(index: i32, type: NativeType): ExpressionRef {
if (this.noEmit) return 0;
return _BinaryenGetLocal(this.ref, index, type);
}
createTeeLocal(index: i32, value: BinaryenExpressionRef): BinaryenExpressionRef {
createTeeLocal(index: i32, value: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0;
return _BinaryenTeeLocal(this.ref, index, value);
}
createGetGlobal(name: string, type: Type): BinaryenExpressionRef {
createGetGlobal(name: string, type: NativeType): ExpressionRef {
if (this.noEmit) return 0;
const cStr: CString = allocString(name);
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;
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;
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;
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;
return _BinaryenAtomicWake(this.ref, ptr, wakeCount);
}
// statements
createSetLocal(index: i32, value: BinaryenExpressionRef): BinaryenExpressionRef {
createSetLocal(index: Index, value: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0;
return _BinaryenSetLocal(this.ref, index, value);
}
createSetGlobal(name: string, value: BinaryenExpressionRef): BinaryenExpressionRef {
createSetGlobal(name: string, value: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0;
const cStr: CString = allocString(name);
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;
const cStr: CString = allocString(label);
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;
const cStr: CString = allocString(label);
try {
@ -389,12 +418,12 @@ export class Module {
}
}
createDrop(expression: BinaryenExpressionRef): BinaryenExpressionRef {
createDrop(expression: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0;
return _BinaryenDrop(this.ref, expression);
}
createLoop(label: string | null, body: BinaryenExpressionRef): BinaryenExpressionRef {
createLoop(label: string | null, body: ExpressionRef): ExpressionRef {
if (this.noEmit) return 0;
const cStr: CString = allocString(label);
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;
return _BinaryenIf(this.ref, condition, ifTrue, ifFalse);
}
createNop(): BinaryenExpressionRef {
createNop(): ExpressionRef {
if (this.noEmit) return 0;
return _BinaryenNop(this.ref);
}
createReturn(expression: BinaryenExpressionRef = 0): BinaryenExpressionRef {
createReturn(expression: ExpressionRef = 0): ExpressionRef {
if (this.noEmit) return 0;
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;
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;
const strs: CString[] = new Array(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;
const cStr: CString = allocString(target);
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;
const cStr: CString = allocString(target);
const cArr: CArray<i32> = allocI32Array(operands);
@ -464,14 +493,14 @@ export class Module {
}
}
createUnreachable(): BinaryenExpressionRef {
createUnreachable(): ExpressionRef {
if (this.noEmit) return 0;
return _BinaryenUnreachable(this.ref);
}
// 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;
const cStr: CString = allocString(name);
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;
const cStr: CString = allocString(name);
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;
const cStr1: CString = allocString(internalName);
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;
const cStr1: CString = allocString(internalName);
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;
const cStr: CString = allocString(exportName);
let i: i32, k: i32 = segments.length;
const segs: CArray<u8>[] = new Array(k);
const offs: BinaryenExpressionRef[] = new Array(k);
const sizs: BinaryenIndex[] = new Array(k);
const offs: ExpressionRef[] = new Array(k);
const sizs: Index[] = new Array(k);
for (i = 0; i < k; ++i) {
const buffer: Uint8Array = segments[i].buffer;
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;
_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);
}
export function getExpressionType(expr: BinaryenExpressionRef): Type {
export function getExpressionType(expr: ExpressionRef): NativeType {
return _BinaryenExpressionGetType(expr);
}
export function printExpression(expr: BinaryenExpressionRef): void {
export function printExpression(expr: ExpressionRef): void {
return _BinaryenExpressionPrint(expr);
}
export function getConstValueI32(expr: BinaryenExpressionRef): i32 {
export function getConstValueI32(expr: ExpressionRef): i32 {
return _BinaryenConstGetValueI32(expr);
}
export function getConstValueI64Low(expr: BinaryenExpressionRef): i32 {
export function getConstValueI64Low(expr: ExpressionRef): i32 {
return _BinaryenConstGetValueI64Low(expr);
}
export function getConstValueI64High(expr: BinaryenExpressionRef): i32 {
export function getConstValueI64High(expr: ExpressionRef): i32 {
return _BinaryenConstGetValueI64High(expr);
}
export function getConstValueI64(expr: BinaryenExpressionRef): I64 {
export function getConstValueI64(expr: ExpressionRef): I64 {
return new I64(
_BinaryenConstGetValueI64Low(expr),
_BinaryenConstGetValueI64High(expr)
);
}
export function getConstValueF32(expr: BinaryenExpressionRef): f32 {
export function getConstValueF32(expr: ExpressionRef): f32 {
return _BinaryenConstGetValueF32(expr);
}
export function getConstValueF64(expr: BinaryenExpressionRef): f64 {
export function getConstValueF64(expr: ExpressionRef): f64 {
return _BinaryenConstGetValueF64(expr);
}
@ -658,22 +687,22 @@ export class Relooper {
private constructor() {}
addBlock(code: BinaryenExpressionRef): RelooperBlockRef {
addBlock(code: ExpressionRef): RelooperBlockRef {
if (this.noEmit) return 0;
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;
_RelooperAddBranch(from, to, condition, code);
}
addBlockWithSwitch(code: BinaryenExpressionRef, condition: BinaryenExpressionRef): RelooperBlockRef {
addBlockWithSwitch(code: ExpressionRef, condition: ExpressionRef): RelooperBlockRef {
if (this.noEmit) return 0;
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;
const cArr: CArray<i32> = allocI32Array(indexes);
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;
return _RelooperRenderAndDispose(this.ref, entry, labelHelper, this.module.ref);
}

View File

@ -832,7 +832,7 @@ export class Function extends Element {
template: FunctionPrototype;
/** Concrete type arguments. */
typeArguments: Type[];
/** Concrete function parameters. */
/** Concrete function parameters. Excluding `this` if an instance method. */
parameters: Parameter[];
/** Concrete return type. */
returnType: Type;
@ -877,7 +877,7 @@ export class Function extends Element {
addLocal(type: Type, name: string | null = null): Local {
// if it has a name, check previously as this method will throw otherwise
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);
if (name) {
if (this.locals.has(<string>name))

View File

@ -20,15 +20,15 @@
},
"files": [
"ast.ts",
"binaryen.d.ts",
"binaryen.ts",
"compiler.ts",
"diagnosticMessages.generated.ts",
"diagnostics.ts",
"evaluator.ts",
"glue/binaryen.d.ts",
"glue/js.d.ts",
"glue/js.ts",
"index.ts",
"moddule.ts",
"parser.ts",
"program.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, "");
parser.parseFile(text, filename, true);
var sb: string[] = [];
if (isTree) {
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);
parser.program.sources[0].serialize(sb);
const actual = sb.join("");
const expected = isTree ? text : text.replace(/^\s+/mg, "");
const diffs = diff.diffLines(expected, actual);