changetype builtin; some namespace parsing; more stdlib ideas; compiler options for asc

This commit is contained in:
dcodeIO 2017-12-08 04:03:44 +01:00
parent 59dafc8d22
commit bbb57baecb
62 changed files with 636 additions and 469 deletions

9
assembly.d.ts vendored
View File

@ -27,7 +27,7 @@ declare type f32 = number;
/** A 64-bit float. */
declare type f64 = number;
// builtins
// built-ins
/** Performs the sign-agnostic count leading zero bits operation on a 32-bit or 64-bit integer. All zero bits are considered leading if the value is zero. */
declare function clz<T = i32 | i64>(value: T): T;
@ -78,6 +78,8 @@ declare const NaN: f32 | f64;
declare const Infinity: f32 | f64;
/** Determines the byte size of the specified core or class type. Compiles to a constant. */
declare function sizeof<T>(): usize;
/** Changes the type of a value to another one. Useful for casting class instances to their pointer values and vice-versa. */
declare function changetype<T1,T2>(value: T1): T2;
/** Tests if a 32-bit or 64-bit float is NaN. */
declare function isNaN<T = f32 | f64>(value: T): bool;
/** Tests if a 32-bit or 64-bit float is finite, that is not NaN or +/-Infinity. */
@ -87,10 +89,15 @@ declare function assert(isTrue: bool): void;
// internal decorators
/** Annotates an element being part of the global namespace. */
declare function global(): any;
/** Annotates a function being always inlined. */
declare function inline(): any;
/** Annotates a class using a C-style memory layout. */
declare function struct(): any;
// standard library
/// <reference path="./std/carray.d.ts" />
/// <reference path="./std/cstring.d.ts" />
/// <reference path="./std/heap.d.ts" />

View File

@ -110,7 +110,12 @@ while ((diagnostic = assemblyscript.nextDiagnostic(parser)) != null) {
if (hasErrors)
process.exit(1);
var module = assemblyscript.compile(parser);
var options = assemblyscript.createOptions();
assemblyscript.setTarget(options, 0);
assemblyscript.setNoTreeShaking(options, args.noTreeShaking);
assemblyscript.setNoDebug(options, args.noDebug);
var module = assemblyscript.compile(parser, options);
hasErrors = false;
while ((diagnostic = assemblyscript.nextDiagnostic(parser)) != null) {

View File

@ -1,29 +1,37 @@
{
"version": {
"desc": "Print the compiler's version.",
"desc": "Prints the compiler's version.",
"type": "boolean",
"aliases": [ "v" ]
},
"help": {
"desc": "Print this message.",
"desc": "Prints this message.",
"type": "boolean",
"aliases": [ "h" ]
},
"optimize": {
"desc": "Optimize the module.",
"desc": "Optimizes the module.",
"type": "boolean",
"aliases": [ "O" ]
},
"validate": {
"desc": "Validate the module.",
"desc": "Validates the module.",
"type": "boolean"
},
"outFile": {
"desc": "Specify the output file (binary format).",
"desc": "Specifies the output file (binary format).",
"type": "string"
},
"textFile": {
"desc": "Specify the output file (text format).",
"desc": "Specifies the output file (text format).",
"type": "string"
},
"noTreeShaking": {
"desc": "Disables built-in tree-shaking.",
"type": "boolean"
},
"noDebug": {
"desc": "Replaces assertions with nops.",
"type": "boolean"
}
}

View File

@ -657,17 +657,17 @@ export abstract class Statement extends Node {
return stmt;
}
static createClass(modifiers: Modifier[], identifier: IdentifierExpression, typeParameters: TypeParameter[], extendsType: TypeNode | null, implementsTypes: TypeNode[], members: DeclarationStatement[], decorators: DecoratorStatement[], range: Range): ClassDeclaration {
static createClass(identifier: IdentifierExpression, typeParameters: TypeParameter[], extendsType: TypeNode | null, implementsTypes: TypeNode[], members: DeclarationStatement[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): ClassDeclaration {
const stmt: ClassDeclaration = new ClassDeclaration();
stmt.range = range;
let i: i32, k: i32;
for (i = 0, k = (stmt.modifiers = modifiers).length; i < k; ++i) modifiers[i].parent = stmt;
(stmt.identifier = identifier).parent = stmt;
for (i = 0, k = (stmt.typeParameters = typeParameters).length; i < k; ++i) typeParameters[i].parent = stmt;
if (stmt.extendsType = extendsType) (<TypeNode>extendsType).parent = stmt;
for (i = 0, k = (stmt.implementsTypes = implementsTypes).length; i < k; ++i) implementsTypes[i].parent = stmt;
for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].parent = stmt;
for (i = 0, k = (stmt.decorators = decorators).length; i < k; ++i) decorators[i].parent = stmt;
if (stmt.modifiers = modifiers) for (i = 0, k = (<Modifier[]>modifiers).length; i < k; ++i) (<Modifier[]>modifiers)[i].parent = stmt;
if (stmt.decorators = decorators) for (i = 0, k = (<Decorator[]>decorators).length; i < k; ++i) (<Decorator[]>decorators)[i].parent = stmt;
return stmt;
}
@ -678,8 +678,8 @@ export abstract class Statement extends Node {
return stmt;
}
static createDecorator(expression: Expression, args: Expression[], range: Range): DecoratorStatement {
const stmt: DecoratorStatement = new DecoratorStatement();
static createDecorator(expression: Expression, args: Expression[], range: Range): Decorator {
const stmt: Decorator = new Decorator();
stmt.range = range;
(stmt.expression = expression).parent = stmt;
for (let i: i32 = 0, k: i32 = (stmt.arguments = args).length; i < k; ++i) args[i].parent = stmt;
@ -700,13 +700,14 @@ export abstract class Statement extends Node {
return stmt;
}
static createEnum(modifiers: Modifier[], identifier: IdentifierExpression, members: EnumValueDeclaration[], range: Range): EnumDeclaration {
static createEnum(identifier: IdentifierExpression, members: EnumValueDeclaration[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): EnumDeclaration {
const stmt: EnumDeclaration = new EnumDeclaration();
stmt.range = range;
let i: i32, k: i32;
for (i = 0, k = (stmt.modifiers = modifiers).length; i < k; ++i) modifiers[i].parent = stmt;
(stmt.identifier = identifier).parent = stmt;
for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].parent = stmt;
if (stmt.modifiers = modifiers) for (i = 0, k = (<Modifier[]>modifiers).length; i < k; ++i) (<Modifier[]>modifiers)[i].parent = stmt;
if (stmt.decorators = decorators) for (i = 0, k = (<Decorator[]>decorators).length; i < k; ++i) (<Decorator[]>decorators)[i].parent = stmt;
return stmt;
}
@ -718,15 +719,15 @@ export abstract class Statement extends Node {
return stmt;
}
static createExport(modifiers: Modifier[], members: ExportMember[], path: StringLiteralExpression | null, range: Range): ExportStatement {
static createExport(members: ExportMember[], path: StringLiteralExpression | null, modifiers: Modifier[] | null, range: Range): ExportStatement {
const stmt: ExportStatement = new ExportStatement();
stmt.range = range;
let i: i32, k: i32;
for (i = 0, k = (stmt.modifiers = modifiers).length; i < k; ++i) modifiers[i].parent = stmt;
for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].parent = stmt;
stmt.path = path;
stmt.normalizedPath = path ? resolvePath(normalizePath(path.value), range.source.normalizedPath) : null;
stmt.internalPath = stmt.normalizedPath ? mangleInternalPath(stmt.normalizedPath) : null;
if (stmt.modifiers = modifiers) for (i = 0, k = (<Modifier[]>modifiers).length; i < k; ++i) (<Modifier[]>modifiers)[i].parent = stmt;
return stmt;
}
@ -780,25 +781,26 @@ export abstract class Statement extends Node {
return elem;
}
static createInterface(modifiers: Modifier[], extendsType: TypeNode | null, members: DeclarationStatement[], range: Range): InterfaceDeclaration {
static createInterface(identifier: IdentifierExpression, extendsType: TypeNode | null, members: DeclarationStatement[], modifiers: Modifier[] | null, range: Range): InterfaceDeclaration {
const stmt: InterfaceDeclaration = new InterfaceDeclaration();
stmt.range = range;
let i: i32, k: i32;
for (i = 0, k = (stmt.modifiers = modifiers).length; i < k; ++i) modifiers[i].parent = stmt;
(stmt.identifier = identifier).parent = stmt;
if (stmt.extendsType = extendsType) (<TypeNode>extendsType).parent = stmt;
for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].parent = stmt;
if (stmt.modifiers = modifiers) for (i = 0, k = (<Modifier[]>modifiers).length; i < k; ++i) (<Modifier[]>modifiers)[i].parent = stmt;
return stmt;
}
static createField(modifiers: Modifier[], identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, decorators: DecoratorStatement[], range: Range): FieldDeclaration {
static createField(identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): FieldDeclaration {
const stmt: FieldDeclaration = new FieldDeclaration();
stmt.range = range;
let i: i32, k: i32;
for (i = 0, k = (stmt.modifiers = modifiers).length; i < k; ++i) modifiers[i].parent = stmt;
(stmt.identifier = identifier).parent = stmt;
if (stmt.type = type) (<TypeNode>type).parent = stmt;
if (stmt.initializer = initializer) (<Expression>initializer).parent = stmt;
for (i = 0, k = (stmt.decorators = decorators).length; i < k; ++i) decorators[i].parent = stmt;
if (stmt.modifiers = modifiers) for (i = 0, k = (<Modifier[]>modifiers).length; i < k; ++i) (<Modifier[]>modifiers)[i].parent = stmt;
if (stmt.decorators = decorators) for (i = 0, k = (<Decorator[]>decorators).length; i < k; ++i) (<Decorator[]>decorators)[i].parent = stmt;
return stmt;
}
@ -830,31 +832,31 @@ export abstract class Statement extends Node {
return elem;
}
static createFunction(modifiers: Modifier[], identifier: IdentifierExpression, typeParameters: TypeParameter[], parameters: Parameter[], returnType: TypeNode | null, statements: Statement[] | null, decorators: DecoratorStatement[], range: Range): FunctionDeclaration {
static createFunction(identifier: IdentifierExpression, typeParameters: TypeParameter[], parameters: Parameter[], returnType: TypeNode | null, statements: Statement[] | null, modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): FunctionDeclaration {
const stmt: FunctionDeclaration = new FunctionDeclaration();
stmt.range = range;
let i: i32, k: i32;
for (i = 0, k = (stmt.modifiers = modifiers).length; i < k; ++i) modifiers[i].parent = stmt;
(stmt.identifier = identifier).parent = stmt;
for (i = 0, k = (stmt.typeParameters = typeParameters).length; i < k; ++i) typeParameters[i].parent = stmt;
for (i = 0, k = (stmt.parameters = parameters).length; i < k; ++i) parameters[i].parent = stmt;
if (stmt.returnType = returnType) (<TypeNode>returnType).parent = stmt;
if (stmt.statements = statements) for (i = 0, k = (<Statement[]>statements).length; i < k; ++i) (<Statement[]>statements)[i].parent = stmt;
for (i = 0, k = (stmt.decorators = decorators).length; i < k; ++i) decorators[i].parent = stmt;
if (stmt.modifiers = modifiers) for (i = 0, k = (<Modifier[]>modifiers).length; i < k; ++i) (<Modifier[]>modifiers)[i].parent = stmt;
if (stmt.decorators = decorators) for (i = 0, k = (<Decorator[]>decorators).length; i < k; ++i) (<Decorator[]>decorators)[i].parent = stmt;
return stmt;
}
static createMethod(modifiers: Modifier[], identifier: IdentifierExpression, typeParameters: TypeParameter[], parameters: Parameter[], returnType: TypeNode | null, statements: Statement[] | null, decorators: DecoratorStatement[], range: Range): MethodDeclaration {
static createMethod(identifier: IdentifierExpression, typeParameters: TypeParameter[], parameters: Parameter[], returnType: TypeNode | null, statements: Statement[] | null, modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): MethodDeclaration {
const stmt: MethodDeclaration = new MethodDeclaration();
stmt.range = range;
let i: i32, k: i32;
for (i = 0, k = (stmt.modifiers = modifiers).length; i < k; ++i) modifiers[i].parent = stmt;
(stmt.identifier = identifier).parent = stmt;
for (i = 0, k = (stmt.typeParameters = typeParameters).length; i < k; ++i) typeParameters[i].parent = stmt;
for (i = 0, k = (stmt.parameters = parameters).length; i < k; ++i) parameters[i].parent = stmt;
if (stmt.returnType = returnType) (<TypeNode>returnType).parent = stmt;;
if (stmt.statements = statements) for (i = 0, k = (<Statement[]>statements).length; i < k; ++i) (<Statement[]>statements)[i].parent = stmt;
for (i = 0, k = (stmt.decorators = decorators).length; i < k; ++i) decorators[i].parent = stmt;
if (stmt.modifiers = modifiers) for (i = 0, k = (<Modifier[]>modifiers).length; i < k; ++i) (<Modifier[]>modifiers)[i].parent = stmt;
if (stmt.decorators = decorators) for (i = 0, k = (<Decorator[]>decorators).length; i < k; ++i) (<Decorator[]>decorators)[i].parent = stmt;
return stmt;
}
@ -865,13 +867,14 @@ export abstract class Statement extends Node {
return elem;
}
static createNamespace(modifiers: Modifier[], identifier: IdentifierExpression, members: DeclarationStatement[], range: Range): NamespaceDeclaration {
static createNamespace(identifier: IdentifierExpression, members: Statement[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): NamespaceDeclaration {
const stmt: NamespaceDeclaration = new NamespaceDeclaration();
stmt.range = range;
let i: i32, k: i32;
for (i = 0, k = (stmt.modifiers = modifiers).length; i < k; ++i) modifiers[i].parent = stmt;
(stmt.identifier = identifier).parent = stmt;
for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].parent = stmt;
if (stmt.modifiers = modifiers) for (i = 0, k = (<Modifier[]>modifiers).length; i < k; ++i) (<Modifier[]>modifiers)[i].parent = stmt;
if (stmt.decorators = decorators) for (i = 0, k = (<Decorator[]>decorators).length; i < k; ++i) (<Decorator[]>decorators)[i].parent = stmt;
return stmt;
}
@ -916,22 +919,24 @@ export abstract class Statement extends Node {
return stmt;
}
static createVariable(modifiers: Modifier[], declarations: VariableDeclaration[], range: Range): VariableStatement {
static createVariable(declarations: VariableDeclaration[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): VariableStatement {
const stmt: VariableStatement = new VariableStatement();
stmt.range = range;
let i: i32, k: i32;
for (i = 0, k = (stmt.modifiers = modifiers).length; i < k; ++i) modifiers[i].parent = stmt;
for (i = 0, k = (stmt.declarations = declarations).length; i < k; ++i) declarations[i].parent = stmt;
if (stmt.modifiers = modifiers) for (i = 0, k = (<Modifier[]>modifiers).length; i < k; ++i) (<Modifier[]>modifiers)[i].parent = stmt;
if (stmt.decorators = decorators) for (i = 0, k = (<Decorator[]>decorators).length; i < k; ++i) (<Decorator[]>decorators)[i].parent = stmt;
return stmt;
}
static createVariableDeclaration(identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, modifiers: Modifier[] | null, range: Range): VariableDeclaration {
static createVariableDeclaration(identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): VariableDeclaration {
const elem: VariableDeclaration = new VariableDeclaration();
elem.range = range;
(elem.identifier = identifier).parent = elem;
if (elem.type = type) (<TypeNode>type).parent = elem;
if (elem.initializer = initializer) (<Expression>initializer).parent = elem;
elem.modifiers = modifiers;
elem.decorators = decorators;
return elem;
}
@ -987,6 +992,7 @@ export abstract class DeclarationStatement extends Statement {
identifier: IdentifierExpression;
modifiers: Modifier[] | null;
decorators: Decorator[] | null = null;
protected _cachedInternalName: string | null = null;
@ -1037,12 +1043,11 @@ export class ClassDeclaration extends DeclarationStatement {
extendsType: TypeNode | null;
implementsTypes: TypeNode[];
members: DeclarationStatement[];
decorators: DecoratorStatement[];
get internalName(): string {
if (this._cachedInternalName !== null)
return this._cachedInternalName;
const globalDecorator: DecoratorStatement | null = getDecoratorByName("global", this.decorators);
const globalDecorator: Decorator | null = this.decorators ? getDecoratorByName("global", this.decorators) : null;
if (globalDecorator && globalDecorator.expression.kind == NodeKind.IDENTIFIER && (<IdentifierExpression>globalDecorator.expression).name == "global")
return this._cachedInternalName = this.identifier.name;
else
@ -1051,10 +1056,11 @@ export class ClassDeclaration extends DeclarationStatement {
serialize(sb: string[]): void {
let i: i32, k: i32;
for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb);
sb.push("\n");
}
if (this.decorators)
for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb);
sb.push("\n");
}
if (this.modifiers)
for (i = 0, k = (<Modifier[]>this.modifiers).length; i < k; ++i) {
(<Modifier[]>this.modifiers)[i].serialize(sb);
@ -1109,7 +1115,7 @@ export class ContinueStatement extends Statement {
}
}
export class DecoratorStatement extends Statement {
export class Decorator extends Statement {
kind = NodeKind.DECORATOR;
expression: Expression;
@ -1264,14 +1270,14 @@ export class ExpressionStatement extends Statement {
export class FieldDeclaration extends VariableLikeDeclarationStatement {
kind = NodeKind.FIELD;
decorators: DecoratorStatement[];
serialize(sb: string[]): void {
let i: i32, k: i32;
for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb);
sb.push("\n");
}
if (this.decorators)
for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb);
sb.push("\n");
}
if (this.modifiers)
for (i = 0, k = (<Modifier[]>this.modifiers).length; i < k; ++i) {
(<Modifier[]>this.modifiers)[i].serialize(sb);
@ -1323,12 +1329,11 @@ export class FunctionDeclaration extends DeclarationStatement {
parameters: Parameter[];
returnType: TypeNode | null;
statements: Statement[] | null;
decorators: DecoratorStatement[];
get internalName(): string {
if (this._cachedInternalName !== null)
return this._cachedInternalName;
const globalDecorator: DecoratorStatement | null = getDecoratorByName("global", this.decorators);
const globalDecorator: Decorator | null = this.decorators ? getDecoratorByName("global", this.decorators) : null;
if (globalDecorator && globalDecorator.expression.kind == NodeKind.IDENTIFIER && (<IdentifierExpression>globalDecorator.expression).name == "global")
return this._cachedInternalName = this.identifier.name;
else
@ -1337,10 +1342,11 @@ export class FunctionDeclaration extends DeclarationStatement {
serialize(sb: string[]): void {
let i: i32, k: i32;
for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb);
sb.push("\n");
}
if (this.decorators)
for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb);
sb.push("\n");
}
if (this.modifiers)
for (i = 0, k = (<Modifier[]>this.modifiers).length; i < k; ++i) {
(<Modifier[]>this.modifiers)[i].serialize(sb);
@ -1453,6 +1459,11 @@ export class InterfaceDeclaration extends ClassDeclaration {
serialize(sb: string[]): void {
let i: i32, k: i32;
if (this.decorators)
for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb);
sb.push("\n");
}
if (this.modifiers)
for (i = 0, k = (<Modifier[]>this.modifiers).length; i < k; ++i) {
(<Modifier[]>this.modifiers)[i].serialize(sb);
@ -1491,10 +1502,11 @@ export class MethodDeclaration extends FunctionDeclaration {
serialize(sb: string[]): void {
let i: i32, k: i32;
for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb);
sb.push("\n");
}
if (this.decorators)
for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb);
sb.push("\n");
}
if (this.modifiers)
for (i = 0, k = (<Modifier[]>this.modifiers).length; i < k; ++i) {
(<Modifier[]>this.modifiers)[i].serialize(sb);
@ -1511,6 +1523,11 @@ export class NamespaceDeclaration extends DeclarationStatement {
serialize(sb: string[]): void {
let i: i32, k: i32;
if (this.decorators)
for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb);
sb.push("\n");
}
if (this.modifiers)
for (i = 0, k = (<Modifier[]>this.modifiers).length; i < k; ++i) {
(<Modifier[]>this.modifiers)[i].serialize(sb);
@ -1701,11 +1718,17 @@ export class VariableStatement extends Statement {
kind = NodeKind.VARIABLE;
modifiers: Modifier[] | null;
decorators: Decorator[] | null;
declarations: VariableDeclaration[];
serialize(sb: string[]): void {
let isConst: bool = false;
let i: i32, k: i32;
if (this.decorators)
for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb);
sb.push("\n");
}
if (this.modifiers)
for (i = 0, k = (<Modifier[]>this.modifiers).length; i < k; ++i) {
(<Modifier[]>this.modifiers)[i].serialize(sb);
@ -1745,9 +1768,9 @@ export function hasModifier(kind: ModifierKind, modifiers: Modifier[] | null): b
return false;
}
export function getDecoratorByName(name: string, decorators: DecoratorStatement[]): DecoratorStatement | null {
export function getDecoratorByName(name: string, decorators: Decorator[]): Decorator | null {
for (let i: i32 = 0, k: i32 = decorators.length; i < k; ++i) {
const decorator: DecoratorStatement = decorators[i];
const decorator: Decorator = decorators[i];
const expression: Expression = decorator.expression;
if (expression.kind == NodeKind.IDENTIFIER && (<IdentifierExpression>expression).name == name)
return decorator;

View File

@ -2,7 +2,7 @@ import { Compiler, Target, typeToNativeType, typeToNativeOne } from "./compiler"
import { DiagnosticCode } from "./diagnostics";
import { Node, Expression } from "./ast";
import { Type } from "./types";
import { ExpressionRef, UnaryOp, BinaryOp, HostOp, NativeType } from "./module";
import { Module, ExpressionRef, UnaryOp, BinaryOp, HostOp, NativeType } from "./module";
import { Program, FunctionPrototype, Local } from "./program";
/** Initializes the specified program with built-in functions. */
@ -29,6 +29,7 @@ export function initialize(program: Program): void {
addFunction(program, "reinterpret", true);
addFunction(program, "select", true);
addFunction(program, "sizeof", true);
addFunction(program, "changetype", true);
addFunction(program, "isNaN", true);
addFunction(program, "isFinite", true);
addFunction(program, "assert");
@ -47,6 +48,7 @@ function addFunction(program: Program, name: string, isGeneric: bool = false, is
/** Compiles a call to a built-in function. */
export function compileCall(compiler: Compiler, internalName: string, typeArguments: Type[], operands: Expression[], reportNode: Node): ExpressionRef {
const module: Module = compiler.module;
const usizeType: Type = select<Type>(Type.usize64, Type.usize32, compiler.options.target == Target.WASM64);
let arg0: ExpressionRef,
@ -55,126 +57,127 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume
let tempLocal0: Local;
let tempLocal1: Local;
let nativeType: NativeType;
let type: Type;
switch (internalName) {
case "clz": // clz<T>(value: T) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if ((compiler.currentType = typeArguments[0]).isAnyInteger) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
return (compiler.currentType = typeArguments[0]).isLongInteger // sic
? compiler.module.createUnary(UnaryOp.ClzI64, arg0)
? module.createUnary(UnaryOp.ClzI64, arg0)
: typeArguments[0].isSmallInteger
? compiler.module.createBinary(BinaryOp.AndI32,
compiler.module.createUnary(UnaryOp.ClzI32, arg0),
compiler.module.createI32(typeArguments[0].smallIntegerMask)
? module.createBinary(BinaryOp.AndI32,
module.createUnary(UnaryOp.ClzI32, arg0),
module.createI32(typeArguments[0].smallIntegerMask)
)
: compiler.module.createUnary(UnaryOp.ClzI32, arg0);
: module.createUnary(UnaryOp.ClzI32, arg0);
}
break;
case "ctz": // ctz<T>(value: T) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if ((compiler.currentType = typeArguments[0]).isAnyInteger) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
return (compiler.currentType = typeArguments[0]).isLongInteger // sic
? compiler.module.createUnary(UnaryOp.CtzI64, arg0)
? module.createUnary(UnaryOp.CtzI64, arg0)
: typeArguments[0].isSmallInteger
? compiler.module.createBinary(BinaryOp.AndI32,
compiler.module.createUnary(UnaryOp.CtzI32, arg0),
compiler.module.createI32(typeArguments[0].smallIntegerMask)
? module.createBinary(BinaryOp.AndI32,
module.createUnary(UnaryOp.CtzI32, arg0),
module.createI32(typeArguments[0].smallIntegerMask)
)
: compiler.module.createUnary(UnaryOp.CtzI32, arg0);
: module.createUnary(UnaryOp.CtzI32, arg0);
}
break;
case "popcnt": // popcnt<T>(value: T) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if ((compiler.currentType = typeArguments[0]).isAnyInteger) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
return (compiler.currentType = typeArguments[0]).isLongInteger // sic
? compiler.module.createUnary(UnaryOp.PopcntI64, arg0)
? module.createUnary(UnaryOp.PopcntI64, arg0)
: typeArguments[0].isSmallInteger
? compiler.module.createBinary(BinaryOp.AndI32,
compiler.module.createUnary(UnaryOp.PopcntI32, arg0),
compiler.module.createI32(typeArguments[0].smallIntegerMask)
? module.createBinary(BinaryOp.AndI32,
module.createUnary(UnaryOp.PopcntI32, arg0),
module.createI32(typeArguments[0].smallIntegerMask)
)
: compiler.module.createUnary(UnaryOp.PopcntI32, arg0);
: module.createUnary(UnaryOp.PopcntI32, arg0);
}
break;
case "rotl": // rotl<T>(value: T, shift: T) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 2, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if ((compiler.currentType = typeArguments[0]).isAnyInteger) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
arg1 = compiler.compileExpression(operands[1], typeArguments[0]);
return (compiler.currentType = typeArguments[0]).isLongInteger // sic
? compiler.module.createBinary(BinaryOp.RotlI64, arg0, arg1)
? module.createBinary(BinaryOp.RotlI64, arg0, arg1)
: typeArguments[0].isSmallInteger
? compiler.module.createBinary(BinaryOp.AndI32,
compiler.module.createBinary(BinaryOp.RotlI32, arg0, arg1),
compiler.module.createI32(typeArguments[0].smallIntegerMask)
? module.createBinary(BinaryOp.AndI32,
module.createBinary(BinaryOp.RotlI32, arg0, arg1),
module.createI32(typeArguments[0].smallIntegerMask)
)
: compiler.module.createBinary(BinaryOp.RotlI32, arg0, arg1);
: module.createBinary(BinaryOp.RotlI32, arg0, arg1);
}
break;
case "rotr": // rotr<T>(value: T, shift: T) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 2, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if ((compiler.currentType = typeArguments[0]).isAnyInteger) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
arg1 = compiler.compileExpression(operands[1], typeArguments[0]);
return (compiler.currentType = typeArguments[0]).isLongInteger // sic
? compiler.module.createBinary(BinaryOp.RotrI64, arg0, arg1)
? module.createBinary(BinaryOp.RotrI64, arg0, arg1)
: typeArguments[0].isSmallInteger
? compiler.module.createBinary(BinaryOp.AndI32,
compiler.module.createBinary(BinaryOp.RotrI32, arg0, arg1),
compiler.module.createI32(typeArguments[0].smallIntegerMask)
? module.createBinary(BinaryOp.AndI32,
module.createBinary(BinaryOp.RotrI32, arg0, arg1),
module.createI32(typeArguments[0].smallIntegerMask)
)
: compiler.module.createBinary(BinaryOp.RotrI32, arg0, arg1);
: module.createBinary(BinaryOp.RotrI32, arg0, arg1);
}
break;
case "abs": // abs<T>(value: T) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if ((compiler.currentType = typeArguments[0]) != Type.void) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
if ((compiler.currentType = typeArguments[0]).isAnyFloat) // sic
return typeArguments[0] == Type.f32
? compiler.module.createUnary(UnaryOp.AbsF32, arg0)
: compiler.module.createUnary(UnaryOp.AbsF64, arg0);
? module.createUnary(UnaryOp.AbsF32, arg0)
: module.createUnary(UnaryOp.AbsF64, arg0);
if (typeArguments[0].isAnyInteger) {
if (typeArguments[0].isSignedInteger) {
tempLocal0 = compiler.currentFunction.addLocal(typeArguments[0]);
if (typeArguments[0].isLongInteger)
return compiler.module.createSelect(
compiler.module.createBinary(BinaryOp.SubI64,
compiler.module.createI64(0, 0),
compiler.module.createTeeLocal(tempLocal0.index, arg0)
return module.createSelect(
module.createBinary(BinaryOp.SubI64,
module.createI64(0, 0),
module.createTeeLocal(tempLocal0.index, arg0)
),
compiler.module.createGetLocal(tempLocal0.index, NativeType.I64),
compiler.module.createBinary(BinaryOp.LtI64,
compiler.module.createGetLocal(tempLocal0.index, NativeType.I64),
compiler.module.createI64(0, 0)
module.createGetLocal(tempLocal0.index, NativeType.I64),
module.createBinary(BinaryOp.LtI64,
module.createGetLocal(tempLocal0.index, NativeType.I64),
module.createI64(0, 0)
)
);
else
return compiler.module.createSelect(
compiler.module.createBinary(BinaryOp.SubI32,
compiler.module.createI32(0),
compiler.module.createTeeLocal(tempLocal0.index, arg0)
return module.createSelect(
module.createBinary(BinaryOp.SubI32,
module.createI32(0),
module.createTeeLocal(tempLocal0.index, arg0)
),
compiler.module.createGetLocal(tempLocal0.index, NativeType.I32),
compiler.module.createBinary(BinaryOp.LtI32,
compiler.module.createGetLocal(tempLocal0.index, NativeType.I32),
compiler.module.createI32(0)
module.createGetLocal(tempLocal0.index, NativeType.I32),
module.createBinary(BinaryOp.LtI32,
module.createGetLocal(tempLocal0.index, NativeType.I32),
module.createI32(0)
)
);
} else
@ -185,33 +188,33 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume
case "max": // max<T>(left: T, right: T) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 2, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if ((compiler.currentType = typeArguments[0]) != Type.void) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
arg1 = compiler.compileExpression(operands[1], typeArguments[0]);
if ((compiler.currentType = typeArguments[0]).isAnyFloat) // sic
return typeArguments[0] == Type.f32
? compiler.module.createBinary(BinaryOp.MaxF32, arg0, arg1)
: compiler.module.createBinary(BinaryOp.MaxF64, arg0, arg1);
? module.createBinary(BinaryOp.MaxF32, arg0, arg1)
: module.createBinary(BinaryOp.MaxF64, arg0, arg1);
if (typeArguments[0].isAnyInteger) {
tempLocal0 = compiler.currentFunction.addLocal(typeArguments[0]);
tempLocal1 = compiler.currentFunction.addLocal(typeArguments[0]);
if (typeArguments[0].isLongInteger)
return compiler.module.createSelect(
compiler.module.createTeeLocal(tempLocal0.index, arg0),
compiler.module.createTeeLocal(tempLocal1.index, arg1),
compiler.module.createBinary(typeArguments[0].isSignedInteger ? BinaryOp.GtI64 : BinaryOp.GtU64,
compiler.module.createGetLocal(tempLocal0.index, NativeType.I64),
compiler.module.createGetLocal(tempLocal1.index, NativeType.I64)
return module.createSelect(
module.createTeeLocal(tempLocal0.index, arg0),
module.createTeeLocal(tempLocal1.index, arg1),
module.createBinary(typeArguments[0].isSignedInteger ? BinaryOp.GtI64 : BinaryOp.GtU64,
module.createGetLocal(tempLocal0.index, NativeType.I64),
module.createGetLocal(tempLocal1.index, NativeType.I64)
)
);
else
return compiler.module.createSelect(
compiler.module.createTeeLocal(tempLocal0.index, arg0),
compiler.module.createTeeLocal(tempLocal1.index, arg1),
compiler.module.createBinary(typeArguments[0].isSignedInteger ? BinaryOp.GtI32 : BinaryOp.GtU32,
compiler.module.createGetLocal(tempLocal0.index, NativeType.I32),
compiler.module.createGetLocal(tempLocal1.index, NativeType.I32)
return module.createSelect(
module.createTeeLocal(tempLocal0.index, arg0),
module.createTeeLocal(tempLocal1.index, arg1),
module.createBinary(typeArguments[0].isSignedInteger ? BinaryOp.GtI32 : BinaryOp.GtU32,
module.createGetLocal(tempLocal0.index, NativeType.I32),
module.createGetLocal(tempLocal1.index, NativeType.I32)
)
);
}
@ -220,33 +223,33 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume
case "min": // min<T>(left: T, right: T) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 2, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if ((compiler.currentType = typeArguments[0]) != Type.void) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
arg1 = compiler.compileExpression(operands[1], typeArguments[0]);
if ((compiler.currentType = typeArguments[0]).isAnyFloat) // sic
return typeArguments[0] == Type.f32
? compiler.module.createBinary(BinaryOp.MinF32, arg0, arg1)
: compiler.module.createBinary(BinaryOp.MinF64, arg0, arg1);
? module.createBinary(BinaryOp.MinF32, arg0, arg1)
: module.createBinary(BinaryOp.MinF64, arg0, arg1);
if (typeArguments[0].isAnyInteger) {
tempLocal0 = compiler.currentFunction.addLocal(typeArguments[0]);
tempLocal1 = compiler.currentFunction.addLocal(typeArguments[0]);
if (typeArguments[0].isLongInteger)
return compiler.module.createSelect(
compiler.module.createTeeLocal(tempLocal0.index, arg0),
compiler.module.createTeeLocal(tempLocal1.index, arg1),
compiler.module.createBinary(typeArguments[0].isSignedInteger ? BinaryOp.LtI64 : BinaryOp.LtU64,
compiler.module.createGetLocal(tempLocal0.index, NativeType.I64),
compiler.module.createGetLocal(tempLocal1.index, NativeType.I64)
return module.createSelect(
module.createTeeLocal(tempLocal0.index, arg0),
module.createTeeLocal(tempLocal1.index, arg1),
module.createBinary(typeArguments[0].isSignedInteger ? BinaryOp.LtI64 : BinaryOp.LtU64,
module.createGetLocal(tempLocal0.index, NativeType.I64),
module.createGetLocal(tempLocal1.index, NativeType.I64)
)
);
else
return compiler.module.createSelect(
compiler.module.createTeeLocal(tempLocal0.index, arg0),
compiler.module.createTeeLocal(tempLocal1.index, arg1),
compiler.module.createBinary(typeArguments[0].isSignedInteger ? BinaryOp.LtI32 : BinaryOp.LtU32,
compiler.module.createGetLocal(tempLocal0.index, NativeType.I32),
compiler.module.createGetLocal(tempLocal1.index, NativeType.I32)
return module.createSelect(
module.createTeeLocal(tempLocal0.index, arg0),
module.createTeeLocal(tempLocal1.index, arg1),
module.createBinary(typeArguments[0].isSignedInteger ? BinaryOp.LtI32 : BinaryOp.LtU32,
module.createGetLocal(tempLocal0.index, NativeType.I32),
module.createGetLocal(tempLocal1.index, NativeType.I32)
)
);
}
@ -255,174 +258,185 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume
case "ceil": // ceil<T>(value: T) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if ((compiler.currentType = typeArguments[0]).isAnyFloat) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
return (compiler.currentType = typeArguments[0]) == Type.f32 // sic
? compiler.module.createUnary(UnaryOp.CeilF32, arg0)
: compiler.module.createUnary(UnaryOp.CeilF64, arg0);
? module.createUnary(UnaryOp.CeilF32, arg0)
: module.createUnary(UnaryOp.CeilF64, arg0);
}
break;
case "floor": // floor<T>(value: T) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if ((compiler.currentType = typeArguments[0]).isAnyFloat) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
return (compiler.currentType = typeArguments[0]) == Type.f32 // sic
? compiler.module.createUnary(UnaryOp.FloorF32, arg0)
: compiler.module.createUnary(UnaryOp.FloorF64, arg0);
? module.createUnary(UnaryOp.FloorF32, arg0)
: module.createUnary(UnaryOp.FloorF64, arg0);
}
break;
case "copysign": // copysign<T>(left: T, right: T) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 2, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if ((compiler.currentType = typeArguments[0]).isAnyFloat) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
arg1 = compiler.compileExpression(operands[1], typeArguments[0]);
return (compiler.currentType = typeArguments[0]) == Type.f32 // sic
? compiler.module.createBinary(BinaryOp.CopysignF32, arg0, arg1)
: compiler.module.createBinary(BinaryOp.CopysignF64, arg0, arg1);
? module.createBinary(BinaryOp.CopysignF32, arg0, arg1)
: module.createBinary(BinaryOp.CopysignF64, arg0, arg1);
}
break;
case "nearest": // nearest<T>(value: T) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if ((compiler.currentType = typeArguments[0]).isAnyFloat) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
return (compiler.currentType = typeArguments[0]) == Type.f32 // sic
? compiler.module.createUnary(UnaryOp.NearestF32, arg0)
: compiler.module.createUnary(UnaryOp.NearestF64, arg0);
? module.createUnary(UnaryOp.NearestF32, arg0)
: module.createUnary(UnaryOp.NearestF64, arg0);
}
break;
case "sqrt": // sqrt<T>(value: T) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if ((compiler.currentType = typeArguments[0]).isAnyFloat) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
return (compiler.currentType = typeArguments[0]) == Type.f32 // sic
? compiler.module.createUnary(UnaryOp.SqrtF32, arg0)
: compiler.module.createUnary(UnaryOp.SqrtF64, arg0);
? module.createUnary(UnaryOp.SqrtF32, arg0)
: module.createUnary(UnaryOp.SqrtF64, arg0);
}
break;
case "trunc": // trunc<T>(value: T) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if ((compiler.currentType = typeArguments[0]).isAnyFloat) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
return (compiler.currentType = typeArguments[0]) == Type.f32 // sic
? compiler.module.createUnary(UnaryOp.TruncF32, arg0)
: compiler.module.createUnary(UnaryOp.TruncF64, arg0);
? module.createUnary(UnaryOp.TruncF32, arg0)
: module.createUnary(UnaryOp.TruncF64, arg0);
}
break;
case "sizeof": // sizeof<T>() -> usize
compiler.currentType = usizeType;
if (!validateCall(compiler, typeArguments, 1, operands, 0, reportNode))
return compiler.module.createUnreachable();
return usizeType.isLongInteger
? compiler.module.createI64(typeArguments[0].byteSize, 0)
: compiler.module.createI32(typeArguments[0].byteSize);
case "load": // load<T>(offset: usize) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
arg0 = compiler.compileExpression(operands[0], usizeType); // reports
if ((compiler.currentType = typeArguments[0]) != Type.void)
return compiler.module.createLoad(typeArguments[0].byteSize, typeArguments[0].isSignedInteger, arg0, typeToNativeType(typeArguments[0]));
return module.createLoad(typeArguments[0].byteSize, typeArguments[0].isSignedInteger, arg0, typeToNativeType(typeArguments[0]));
break;
case "store": // store<T>(offset: usize, value: T) -> void
compiler.currentType = Type.void;
if (!validateCall(compiler, typeArguments, 1, operands, 2, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
arg0 = compiler.compileExpression(operands[0], usizeType); // reports
arg1 = compiler.compileExpression(operands[1], typeArguments[0]); // reports
compiler.currentType = Type.void;
if (typeArguments[0] != Type.void)
return compiler.module.createStore(typeArguments[0].byteSize, arg0, arg1, typeToNativeType(typeArguments[0]));
return module.createStore(typeArguments[0].byteSize, arg0, arg1, typeToNativeType(typeArguments[0]));
break;
case "reinterpret": // reinterpret<T1,T2>(value: T1) -> T2
if (!validateCall(compiler, typeArguments, 2, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
compiler.currentType = typeArguments[1];
if (typeArguments[0].isLongInteger && typeArguments[1] == Type.f64) {
arg0 = compiler.compileExpression(operands[0], Type.i64); // reports
compiler.currentType = Type.f64;
return compiler.module.createUnary(UnaryOp.ReinterpretI64, arg0);
return module.createUnary(UnaryOp.ReinterpretI64, arg0);
}
if (typeArguments[0].isAnyInteger && typeArguments[0].byteSize == 4 && typeArguments[1] == Type.f32) {
arg0 = compiler.compileExpression(operands[0], Type.i32); // reports
compiler.currentType = Type.f32;
return compiler.module.createUnary(UnaryOp.ReinterpretI32, arg0);
return module.createUnary(UnaryOp.ReinterpretI32, arg0);
}
if (typeArguments[0] == Type.f64 && typeArguments[1].isLongInteger) {
arg0 = compiler.compileExpression(operands[0], Type.f64); // reports
compiler.currentType = typeArguments[1];
return compiler.module.createUnary(UnaryOp.ReinterpretF64, arg0);
return module.createUnary(UnaryOp.ReinterpretF64, arg0);
}
if (typeArguments[0] == Type.f32 && typeArguments[1].isAnyInteger && typeArguments[1].byteSize == 4) {
arg0 = compiler.compileExpression(operands[0], Type.f32); // reports
compiler.currentType = typeArguments[1];
return compiler.module.createUnary(UnaryOp.ReinterpretF32, arg0);
return module.createUnary(UnaryOp.ReinterpretF32, arg0);
}
break;
case "select": // select<T>(ifTrue: T, ifFalse: T, condition: bool) -> T
if (!validateCall(compiler, typeArguments, 1, operands, 3, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if (typeArguments[0] != Type.void) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]); // reports
arg1 = compiler.compileExpression(operands[1], typeArguments[0]); // reports
arg2 = compiler.compileExpression(operands[2], Type.i32); // reports
compiler.currentType = typeArguments[0];
return compiler.module.createSelect(arg0, arg1, arg2);
return module.createSelect(arg0, arg1, arg2);
}
break;
case "current_memory": // current_memory() -> i32
compiler.currentType = Type.i32;
if (!validateCall(compiler, typeArguments, 0, operands, 0, reportNode))
return compiler.module.createUnreachable();
return compiler.module.createHost(HostOp.CurrentMemory);
return module.createUnreachable();
return module.createHost(HostOp.CurrentMemory);
case "grow_memory": // grow_memory(pages: i32) -> i32
compiler.currentType = Type.i32;
if (!validateCall(compiler, typeArguments, 0, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
arg0 = compiler.compileExpression(operands[0], Type.i32);
return compiler.module.createHost(HostOp.GrowMemory, null, [ arg0 ]);
return module.createHost(HostOp.GrowMemory, null, [ arg0 ]);
case "unreachable": // unreachable() -> *
// does not modify currentType
validateCall(compiler, typeArguments, 0, operands, 0, reportNode);
return compiler.module.createUnreachable();
return module.createUnreachable();
case "sizeof": // sizeof<T>() -> usize
compiler.currentType = usizeType;
if (!validateCall(compiler, typeArguments, 1, operands, 0, reportNode))
return module.createUnreachable();
return usizeType.isLongInteger
? module.createI64(typeArguments[0].byteSize, 0)
: module.createI32(typeArguments[0].byteSize);
case "changetype": // changetype<T1,T2>(value: T1) -> T2
if (!validateCall(compiler, typeArguments, 2, operands, 1, reportNode))
return module.createUnreachable();
if ((typeArguments[0] == usizeType && typeArguments[1].classType) || (typeArguments[0].classType && typeArguments[1] == usizeType)) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]);
compiler.currentType = typeArguments[1];
return arg0;
}
compiler.error(DiagnosticCode.Type_0_cannot_be_changed_to_type_1, reportNode.range, typeArguments[0].toString(), typeArguments[1].toString());
return module.createUnreachable();
case "isNaN": // isNaN<T>(value: T) -> bool
compiler.currentType = Type.bool;
if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if (typeArguments[0].isAnyInteger)
return compiler.module.createI32(0);
return module.createI32(0);
if (typeArguments[0].isAnyFloat) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]); // reports
compiler.currentType = Type.bool;
if (typeArguments[0] == Type.f32) {
tempLocal0 = compiler.currentFunction.addLocal(Type.f32);
return compiler.module.createBinary(BinaryOp.NeF32,
compiler.module.createTeeLocal(tempLocal0.index, arg0),
compiler.module.createGetLocal(tempLocal0.index, NativeType.F32)
return module.createBinary(BinaryOp.NeF32,
module.createTeeLocal(tempLocal0.index, arg0),
module.createGetLocal(tempLocal0.index, NativeType.F32)
);
} else {
tempLocal0 = compiler.currentFunction.addLocal(Type.f64);
return compiler.module.createBinary(BinaryOp.NeF64,
compiler.module.createTeeLocal(tempLocal0.index, arg0),
compiler.module.createGetLocal(tempLocal0.index, NativeType.F64)
return module.createBinary(BinaryOp.NeF64,
module.createTeeLocal(tempLocal0.index, arg0),
module.createGetLocal(tempLocal0.index, NativeType.F64)
);
}
}
@ -431,40 +445,40 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume
case "isFinite": // isFinite<T>(value: T) -> bool
compiler.currentType = Type.bool;
if (!validateCall(compiler, typeArguments, 1, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
if (typeArguments[0].isAnyInteger)
return compiler.module.createI32(1);
return module.createI32(1);
if (typeArguments[0].isAnyFloat) {
arg0 = compiler.compileExpression(operands[0], typeArguments[0]); // reports
compiler.currentType = Type.bool;
if (typeArguments[0] == Type.f32) {
tempLocal0 = compiler.currentFunction.addLocal(Type.f32);
return compiler.module.createSelect(
compiler.module.createBinary(BinaryOp.NeF32,
compiler.module.createUnary(UnaryOp.AbsF32,
compiler.module.createTeeLocal(tempLocal0.index, arg0)
return module.createSelect(
module.createBinary(BinaryOp.NeF32,
module.createUnary(UnaryOp.AbsF32,
module.createTeeLocal(tempLocal0.index, arg0)
),
compiler.module.createF32(Infinity)
module.createF32(Infinity)
),
compiler.module.createI32(0),
compiler.module.createBinary(BinaryOp.EqF32,
compiler.module.createGetLocal(tempLocal0.index, NativeType.F32),
compiler.module.createGetLocal(tempLocal0.index, NativeType.F32)
module.createI32(0),
module.createBinary(BinaryOp.EqF32,
module.createGetLocal(tempLocal0.index, NativeType.F32),
module.createGetLocal(tempLocal0.index, NativeType.F32)
)
);
} else {
tempLocal0 = compiler.currentFunction.addLocal(Type.f64);
return compiler.module.createSelect(
compiler.module.createBinary(BinaryOp.NeF64,
compiler.module.createUnary(UnaryOp.AbsF64,
compiler.module.createTeeLocal(tempLocal0.index, arg0)
return module.createSelect(
module.createBinary(BinaryOp.NeF64,
module.createUnary(UnaryOp.AbsF64,
module.createTeeLocal(tempLocal0.index, arg0)
),
compiler.module.createF64(Infinity)
module.createF64(Infinity)
),
compiler.module.createI32(0),
compiler.module.createBinary(BinaryOp.EqF64,
compiler.module.createGetLocal(tempLocal0.index, NativeType.F64),
compiler.module.createGetLocal(tempLocal0.index, NativeType.F64)
module.createI32(0),
module.createBinary(BinaryOp.EqF64,
module.createGetLocal(tempLocal0.index, NativeType.F64),
module.createGetLocal(tempLocal0.index, NativeType.F64)
)
);
}
@ -474,14 +488,14 @@ export function compileCall(compiler: Compiler, internalName: string, typeArgume
case "assert": // assert(isTrue: bool) -> void
compiler.currentType = Type.void;
if (!validateCall(compiler, typeArguments, 0, operands, 1, reportNode))
return compiler.module.createUnreachable();
return module.createUnreachable();
arg0 = compiler.compileExpression(operands[0], Type.i32); // reports
compiler.currentType = Type.void;
return compiler.options.noDebug
? compiler.module.createNop()
: compiler.module.createIf(
compiler.module.createUnary(UnaryOp.EqzI32, arg0),
compiler.module.createUnreachable()
? module.createNop()
: module.createIf(
module.createUnary(UnaryOp.EqzI32, arg0),
module.createUnreachable()
);
// case "fmod":

View File

@ -148,7 +148,7 @@ export class Compiler extends DiagnosticEmitter {
const startFunctionTemplate: FunctionPrototype = new FunctionPrototype(program, "start", null);
const startFunctionInstance: Function = new Function(startFunctionTemplate, startFunctionTemplate.internalName, [], [], Type.void, null);
this.currentFunction = this.startFunction = startFunctionInstance;
this.memoryOffset = new U64(2 * (this.options.target == Target.WASM64 ? 8 : 4), 0); // leave space for `null` and heapStart (both of usize type)
this.memoryOffset = new U64(this.options.target == Target.WASM64 ? 8 : 4, 0); // leave space for `null`
}
/** Performs compilation of the underlying {@link Program} to a {@link Module}. */
@ -178,32 +178,12 @@ export class Compiler extends DiagnosticEmitter {
}
// set up memory
// store heapStart at `sizeof<usize>()` (that is right after `null`) as an usize
const initial: U64 = this.memoryOffset.clone();
let heapStartBuffer: Uint8Array;
let heapStartOffset: i32;
if (this.options.target == Target.WASM64) {
heapStartBuffer = new Uint8Array(8);
heapStartOffset = 8;
heapStartBuffer[0] = (initial.lo ) as u8;
heapStartBuffer[1] = (initial.lo >>> 8) as u8;
heapStartBuffer[2] = (initial.lo >>> 16) as u8;
heapStartBuffer[3] = (initial.lo >>> 24) as u8;
heapStartBuffer[4] = (initial.hi ) as u8;
heapStartBuffer[5] = (initial.hi >>> 8) as u8;
heapStartBuffer[6] = (initial.hi >>> 16) as u8;
heapStartBuffer[7] = (initial.hi >>> 24) as u8;
} else {
if (!initial.fitsInU32)
throw new Error("static memory size overflows 32 bits");
heapStartBuffer = new Uint8Array(4);
heapStartOffset = 4;
heapStartBuffer[0] = (initial.lo ) as u8;
heapStartBuffer[1] = (initial.lo >>> 8) as u8;
heapStartBuffer[2] = (initial.lo >>> 16) as u8;
heapStartBuffer[3] = (initial.lo >>> 24) as u8;
}
this.memorySegments.push(MemorySegment.create(heapStartBuffer, new U64(heapStartOffset, 0))); // TODO: use a global instead?
if (this.options.target == Target.WASM64)
this.module.addGlobal("HEAP_START", NativeType.I64, false, this.module.createI64(initial.lo, initial.hi));
else
this.module.addGlobal("HEAP_START", NativeType.I32, false, this.module.createI32(initial.lo));
// determine initial page size
const initialOverlaps: U64 = initial.clone();
initialOverlaps.and32(0xffff);
@ -663,7 +643,7 @@ export class Compiler extends DiagnosticEmitter {
// memory
addMemorySegment(buffer: Uint8Array): MemorySegment {
if (this.memoryOffset.lo & 7) { // align to 8 bytes so any possible data type is aligned here
if (this.memoryOffset.lo & 7) { // align to 8 bytes so any native data type is aligned here
this.memoryOffset.or32(7);
this.memoryOffset.add32(1);
}

View File

@ -7,6 +7,7 @@ export enum DiagnosticCode {
Operation_is_unsafe = 103,
Cannot_export_a_mutable_global = 104,
Compiling_constant_global_with_non_constant_initializer_as_mutable = 105,
Type_0_cannot_be_changed_to_type_1 = 106,
Unterminated_string_literal = 1002,
Identifier_expected = 1003,
_0_expected = 1005,
@ -79,6 +80,7 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
case 103: return "Operation is unsafe.";
case 104: return "Cannot export a mutable global.";
case 105: return "Compiling constant global with non-constant initializer as mutable.";
case 106: return "Type '{0}' cannot be changed to type '{1}'.";
case 1002: return "Unterminated string literal.";
case 1003: return "Identifier expected.";
case 1005: return "'{0}' expected.";

View File

@ -5,6 +5,7 @@
"Operation is unsafe.": 103,
"Cannot export a mutable global.": 104,
"Compiling constant global with non-constant initializer as mutable.": 105,
"Type '{0}' cannot be changed to type '{1}'.": 106,
"Unterminated string literal.": 1002,
"Identifier expected.": 1003,

View File

@ -20,11 +20,12 @@
*/
import { Module } from "./module";
import { Compiler } from "./compiler";
import { DiagnosticMessage, DiagnosticCategory } from "./diagnostics";
import { Compiler, Options, Target } from "./compiler";
import { DiagnosticMessage, DiagnosticCategory, formatDiagnosticMessage } from "./diagnostics";
import { Parser } from "./parser";
import { Program } from "./program";
/** Parses a single source file. If `parser` has been omitted a new one is created. */
export function parseFile(text: string, path: string, parser: Parser | null = null): Parser {
let isEntry: bool = false;
if (!parser) {
@ -35,10 +36,12 @@ export function parseFile(text: string, path: string, parser: Parser | null = nu
return parser;
}
/** Obtains the path to the next file required by the parser. Returns `null` once complete. */
export function nextFile(parser: Parser): string | null {
return parser.nextFile();
}
/** Obtains the next diagnostic message. Returns `null` once there are no more messages. */
export function nextDiagnostic(parser: Parser): DiagnosticMessage | null {
const program: Program = parser.program;
if (program.diagnosticsOffset < program.diagnostics.length)
@ -46,13 +49,49 @@ export function nextDiagnostic(parser: Parser): DiagnosticMessage | null {
return null;
}
/** Formats a diagnostic message to a string. */
export function formatDiagnostic(message: DiagnosticMessage, useColors: bool, showContext: bool): string {
return formatDiagnosticMessage(message, useColors, showContext);
}
/** Tests whether a diagnostic is informatory. */
export function isInfo(message: DiagnosticMessage): bool {
return message.category == DiagnosticCategory.INFO;
}
/** Tests whether a diagnostic is a warning. */
export function isWarning(message: DiagnosticMessage): bool {
return message.category == DiagnosticCategory.WARNING;
}
/** Tests whether a diagnostic is an error. */
export function isError(message: DiagnosticMessage): bool {
return message.category == DiagnosticCategory.ERROR;
}
export function compile(parser: Parser): Module {
const program: Program = parser.finish();
return Compiler.compile(program);
/** Creates a new set of compiler options. */
export function createOptions(): Options {
return new Options();
}
export { DiagnosticMessage, formatDiagnosticMessage as formatDiagnostic } from "./diagnostics";
/** Sets the `target` option. */
export function setTarget(options: Options, target: Target): void {
options.target = target;
}
/** Sets the `noTreeShaking` option. */
export function setNoTreeShaking(options: Options, noTreeShaking: bool): void {
options.noTreeShaking = noTreeShaking;
}
/** Sets the `noDebug` option. */
export function setNoDebug(options: Options, noDebug: bool): void {
options.noDebug = noDebug;
}
/** Compiles the sources computed by the parser to a module. */
export function compile(parser: Parser, options: Options | null = null): Module {
const program: Program = parser.finish();
const compiler: Compiler = new Compiler(program, options);
return compiler.compile();
}

View File

@ -13,6 +13,7 @@ import { DiagnosticCode, DiagnosticEmitter } from "./diagnostics";
import { normalizePath, I64 } from "./util";
import {
Node,
NodeKind,
Source,
@ -30,7 +31,7 @@ import {
BreakStatement,
ClassDeclaration,
ContinueStatement,
DecoratorStatement,
Decorator,
DoStatement,
EnumDeclaration,
EnumValueDeclaration,
@ -60,7 +61,8 @@ import {
VariableDeclaration,
WhileStatement,
hasModifier
hasModifier,
NamespaceDeclaration
} from "./ast";
@ -89,102 +91,7 @@ export class Parser extends DiagnosticEmitter {
source.tokenizer = tn;
while (!tn.skip(Token.ENDOFFILE)) {
let decorators: DecoratorStatement[] | null = null;
while (tn.skip(Token.AT)) {
const decorator: DecoratorStatement | null = this.parseDecorator(tn);
if (!decorator)
break;
if (!decorators)
decorators = new Array();
(<DecoratorStatement[]>decorators).push(<DecoratorStatement>decorator);
}
let modifiers: Modifier[] | null = null;
if (tn.skip(Token.EXPORT))
modifiers = addModifier(Statement.createModifier(ModifierKind.EXPORT, tn.range()), modifiers);
if (tn.skip(Token.DECLARE)) {
modifiers = addModifier(Statement.createModifier(ModifierKind.DECLARE, tn.range()), modifiers);
tn.peek(true);
if (tn.nextTokenOnNewLine)
this.error(DiagnosticCode.Line_break_not_permitted_here, tn.range(tn.pos)); // recoverable, compatibility
}
tn.mark();
let statement: Statement | null = null;
switch (tn.next()) {
case Token.CONST:
modifiers = addModifier(Statement.createModifier(ModifierKind.CONST, tn.range()), modifiers);
if (tn.skip(Token.ENUM)) {
statement = this.parseEnum(tn, modifiers ? <Modifier[]>modifiers : createModifiers());
break;
}
// fall through
case Token.VAR:
case Token.LET:
statement = this.parseVariable(tn, modifiers ? <Modifier[]>modifiers : createModifiers());
break;
case Token.ENUM:
statement = this.parseEnum(tn, modifiers ? <Modifier[]>modifiers : createModifiers());
break;
case Token.FUNCTION:
statement = this.parseFunction(tn, modifiers ? <Modifier[]>modifiers : createModifiers(), decorators);
decorators = null;
break;
case Token.ABSTRACT:
if (!tn.skip(Token.CLASS)) {
this.error(DiagnosticCode._0_expected, tn.range(tn.pos), "class");
break;
}
modifiers = addModifier(Statement.createModifier(ModifierKind.ABSTRACT, tn.range()), modifiers);
// fall through
case Token.CLASS:
statement = this.parseClass(tn, modifiers ? <Modifier[]>modifiers : createModifiers(), decorators);
decorators = null;
break;
case Token.IMPORT:
if (hasModifier(ModifierKind.EXPORT, modifiers)) {
statement = this.parseExportImport(tn, getModifier(ModifierKind.EXPORT, <Modifier[]>modifiers).range);
} else
statement = this.parseImport(tn);
if (modifiers)
reusableModifiers = modifiers;
break;
case Token.TYPE:
// TODO
default:
if (hasModifier(ModifierKind.EXPORT, modifiers)) {
tn.reset();
statement = this.parseExport(tn, modifiers ? <Modifier[]>modifiers : createModifiers());
} else {
if (modifiers) {
if (hasModifier(ModifierKind.DECLARE, modifiers))
this.error(DiagnosticCode._0_modifier_cannot_be_used_here, getModifier(ModifierKind.DECLARE, <Modifier[]>modifiers).range, "declare"); // recoverable
reusableModifiers = modifiers;
}
tn.reset();
statement = this.parseStatement(tn, true);
}
break;
}
if (decorators)
for (let i: i32 = 0, k: i32 = (<DecoratorStatement[]>decorators).length; i < k; ++i)
this.error(DiagnosticCode.Decorators_are_not_valid_here, (<DecoratorStatement[]>decorators)[i].range);
const statement: Statement | null = this.parseTopLevelStatement(tn);
if (!statement)
return;
statement.parent = source;
@ -193,6 +100,114 @@ export class Parser extends DiagnosticEmitter {
reusableModifiers = null;
}
parseTopLevelStatement(tn: Tokenizer, isNamespaceMember: bool = false): Statement | null {
let decorators: Decorator[] | null = null;
while (tn.skip(Token.AT)) {
const decorator: Decorator | null = this.parseDecorator(tn);
if (!decorator)
break;
if (!decorators)
decorators = new Array();
(<Decorator[]>decorators).push(<Decorator>decorator);
}
let modifiers: Modifier[] | null = null;
if (tn.skip(Token.EXPORT))
modifiers = addModifier(Statement.createModifier(ModifierKind.EXPORT, tn.range()), modifiers);
if (tn.skip(Token.DECLARE)) {
modifiers = addModifier(Statement.createModifier(ModifierKind.DECLARE, tn.range()), modifiers);
tn.peek(true);
if (tn.nextTokenOnNewLine)
this.error(DiagnosticCode.Line_break_not_permitted_here, tn.range(tn.pos)); // recoverable, compatibility
}
tn.mark();
let statement: Statement | null = null;
switch (tn.next()) {
case Token.CONST:
modifiers = addModifier(Statement.createModifier(ModifierKind.CONST, tn.range()), modifiers);
if (tn.skip(Token.ENUM)) {
statement = this.parseEnum(tn, modifiers, decorators);
break;
}
// fall through
case Token.VAR:
case Token.LET:
statement = this.parseVariable(tn, modifiers, decorators);
decorators = null;
break;
case Token.ENUM:
statement = this.parseEnum(tn, modifiers, decorators);
decorators = null;
break;
case Token.FUNCTION:
statement = this.parseFunction(tn, modifiers, decorators);
decorators = null;
break;
case Token.ABSTRACT:
if (!tn.skip(Token.CLASS)) {
this.error(DiagnosticCode._0_expected, tn.range(tn.pos), "class");
break;
}
modifiers = addModifier(Statement.createModifier(ModifierKind.ABSTRACT, tn.range()), modifiers);
// fall through
case Token.CLASS:
statement = this.parseClass(tn, modifiers, decorators);
decorators = null;
break;
case Token.NAMESPACE:
statement = this.parseNamespace(tn, modifiers, decorators);
decorators = null;
break;
case Token.IMPORT:
if (hasModifier(ModifierKind.EXPORT, modifiers)) {
statement = this.parseExportImport(tn, getModifier(ModifierKind.EXPORT, <Modifier[]>modifiers).range);
} else
statement = this.parseImport(tn);
if (modifiers)
reusableModifiers = modifiers;
break;
case Token.TYPE:
// TODO
default:
if (hasModifier(ModifierKind.EXPORT, modifiers)) {
tn.reset();
statement = this.parseExport(tn, modifiers); // TODO: why exactly does this have modifiers again?
} else {
if (modifiers) {
if (hasModifier(ModifierKind.DECLARE, modifiers))
this.error(DiagnosticCode._0_modifier_cannot_be_used_here, getModifier(ModifierKind.DECLARE, modifiers).range, "declare"); // recoverable
reusableModifiers = modifiers;
}
tn.reset();
if (!isNamespaceMember)
statement = this.parseStatement(tn, true);
}
break;
}
if (decorators /* not consumed */)
for (let i: i32 = 0, k: i32 = (<Decorator[]>decorators).length; i < k; ++i)
this.error(DiagnosticCode.Decorators_are_not_valid_here, (<Decorator[]>decorators)[i].range);
return statement;
}
nextFile(): string | null {
if (this.backlog.length) {
const filename: string = this.backlog[0];
@ -318,7 +333,7 @@ export class Parser extends DiagnosticEmitter {
// statements
parseDecorator(tn: Tokenizer): DecoratorStatement | null {
parseDecorator(tn: Tokenizer): Decorator | null {
// at '@': Identifier ('.' Identifier)* '(' Arguments
const startPos: i32 = tn.tokenPos;
if (tn.skip(Token.IDENTIFIER)) {
@ -344,24 +359,24 @@ export class Parser extends DiagnosticEmitter {
return null;
}
parseVariable(tn: Tokenizer, modifiers: Modifier[]): VariableStatement | null {
parseVariable(tn: Tokenizer, modifiers: Modifier[] | null, decorators: Decorator[] | null): VariableStatement | null {
// at ('const' | 'let' | 'var'): VariableDeclaration (',' VariableDeclaration)* ';'?
const startPos: i32 = modifiers.length ? modifiers[0].range.start : tn.tokenPos;
const startPos: i32 = modifiers && modifiers.length ? modifiers[0].range.start : tn.tokenPos;
const members: VariableDeclaration[] = new Array();
const isDeclare = hasModifier(ModifierKind.DECLARE, modifiers);
do {
const member: VariableDeclaration | null = this.parseVariableDeclaration(tn, isDeclare, modifiers);
const member: VariableDeclaration | null = this.parseVariableDeclaration(tn, isDeclare, modifiers, decorators);
if (!member)
return null;
members.push(<VariableDeclaration>member);
} while (tn.skip(Token.COMMA));
const ret: VariableStatement = Statement.createVariable(modifiers, members, tn.range(startPos, tn.pos));
const ret: VariableStatement = Statement.createVariable(members, modifiers, decorators, tn.range(startPos, tn.pos));
tn.skip(Token.SEMICOLON);
return ret;
}
parseVariableDeclaration(tn: Tokenizer, isDeclare: bool = false, parentModifiers: Modifier[]): VariableDeclaration | null {
parseVariableDeclaration(tn: Tokenizer, isDeclare: bool = false, parentModifiers: Modifier[] | null, parentDecorators: Decorator[] | null): VariableDeclaration | null {
// Identifier (':' Type)? ('=' Expression)?
if (!tn.skip(Token.IDENTIFIER)) {
this.error(DiagnosticCode.Identifier_expected, tn.range());
@ -383,12 +398,12 @@ export class Parser extends DiagnosticEmitter {
if (!initializer)
return null;
}
return Statement.createVariableDeclaration(identifier, type, initializer, parentModifiers, Range.join(identifier.range, tn.range()));
return Statement.createVariableDeclaration(identifier, type, initializer, parentModifiers, parentDecorators, Range.join(identifier.range, tn.range()));
}
parseEnum(tn: Tokenizer, modifiers: Modifier[]): EnumDeclaration | null {
parseEnum(tn: Tokenizer, modifiers: Modifier[] | null, decorators: Decorator[] | null): EnumDeclaration | null {
// at 'enum': Identifier '{' (EnumValueDeclaration (',' EnumValueDeclaration )*)? '}' ';'?
const startPos: i32 = modifiers.length ? modifiers[0].range.start : tn.tokenPos;
const startPos: i32 = modifiers && modifiers.length ? modifiers[0].range.start : tn.tokenPos;
if (tn.next() != Token.IDENTIFIER) {
this.error(DiagnosticCode.Identifier_expected, tn.range());
return null;
@ -411,7 +426,7 @@ export class Parser extends DiagnosticEmitter {
return null;
}
}
const ret: EnumDeclaration = Statement.createEnum(modifiers, identifier, members, tn.range(startPos, tn.pos));
const ret: EnumDeclaration = Statement.createEnum(identifier, members, modifiers, decorators, tn.range(startPos, tn.pos));
tn.skip(Token.SEMICOLON);
return ret;
}
@ -528,13 +543,9 @@ export class Parser extends DiagnosticEmitter {
return null;
}
parseFunction(tn: Tokenizer, modifiers: Modifier[], decorators: DecoratorStatement[] | null): FunctionDeclaration | null {
parseFunction(tn: Tokenizer, modifiers: Modifier[] | null, decorators: Decorator[] | null): FunctionDeclaration | null {
// at 'function': Identifier ('<' TypeParameters)? '(' Parameters (':' Type)? '{' Statement* '}' ';'?
const startPos: i32 = decorators && (<DecoratorStatement[]>decorators).length
? (<DecoratorStatement[]>decorators)[0].range.start
: modifiers.length
? modifiers[0].range.start
: tn.tokenPos;
const startPos: i32 = modifiers && modifiers.length ? modifiers[0].range.start : tn.tokenPos;
if (!tn.skip(Token.IDENTIFIER)) {
this.error(DiagnosticCode.Identifier_expected, tn.range(tn.pos));
@ -576,16 +587,16 @@ export class Parser extends DiagnosticEmitter {
}
} else if (!isDeclare)
this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, tn.range(tn.pos));
const ret: FunctionDeclaration = Statement.createFunction(modifiers, identifier, typeParameters, <Parameter[]>parameters, returnType, statements, decorators ? <DecoratorStatement[]>decorators : [], tn.range(startPos, tn.pos));
const ret: FunctionDeclaration = Statement.createFunction(identifier, typeParameters, <Parameter[]>parameters, returnType, statements, modifiers, decorators, tn.range(startPos, tn.pos));
tn.skip(Token.SEMICOLON);
return ret;
}
parseClass(tn: Tokenizer, modifiers: Modifier[], decorators: DecoratorStatement[] | null): ClassDeclaration | null {
parseClass(tn: Tokenizer, modifiers: Modifier[] | null, decorators: Decorator[] | null): ClassDeclaration | null {
// at 'class': Identifier ('<' TypeParameters)? ('extends' Type)? ('implements' Type (',' Type)*)? '{' ClassMember* '}'
const startPos: i32 = decorators && (<DecoratorStatement[]>decorators).length
? (<DecoratorStatement[]>decorators)[0].range.start
: modifiers.length
const startPos: i32 = decorators && decorators.length
? decorators[0].range.start
: modifiers && modifiers.length
? modifiers[0].range.start
: tn.tokenPos;
@ -628,7 +639,7 @@ export class Parser extends DiagnosticEmitter {
members.push(<DeclarationStatement>member);
} while (!tn.skip(Token.CLOSEBRACE));
}
return Statement.createClass(modifiers, identifier, <TypeParameter[]>typeParameters, extendsType, implementsTypes, members, decorators ? <DecoratorStatement[]>decorators : [], tn.range(startPos, tn.pos));
return Statement.createClass(identifier, <TypeParameter[]>typeParameters, extendsType, implementsTypes, members, modifiers, decorators, tn.range(startPos, tn.pos));
} else
this.error(DiagnosticCode._0_expected, tn.range(), "{");
} else
@ -640,13 +651,13 @@ export class Parser extends DiagnosticEmitter {
// ('public' | 'private' | 'protected')? ('static' | 'abstract')? ('get' | 'set')? Identifier ...
const startRange: Range = tn.range();
let decorators: DecoratorStatement[] = new Array();
let decorators: Decorator[] = new Array();
while (tn.skip(Token.AT)) {
const decorator: DecoratorStatement | null = this.parseDecorator(tn);
const decorator: Decorator | null = this.parseDecorator(tn);
if (!decorator)
break;
decorators.push(<DecoratorStatement>decorator);
decorators.push(<Decorator>decorator);
}
let modifiers: Modifier[] | null = null;
@ -706,7 +717,7 @@ export class Parser extends DiagnosticEmitter {
this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, tn.range()); // recoverable
}
const ret: MethodDeclaration = Statement.createMethod(modifiers ? modifiers : createModifiers(), identifier, <TypeParameter[]>typeParameters, <Parameter[]>parameters, returnType, statements, decorators, Range.join(startRange, tn.range()));
const ret: MethodDeclaration = Statement.createMethod(identifier, <TypeParameter[]>typeParameters, <Parameter[]>parameters, returnType, statements, modifiers, decorators, Range.join(startRange, tn.range()));
tn.skip(Token.SEMICOLON);
return ret;
@ -731,7 +742,7 @@ export class Parser extends DiagnosticEmitter {
if (!initializer)
return null;
}
const ret: FieldDeclaration = Statement.createField(modifiers ? modifiers : createModifiers(), identifier, type, initializer, decorators, Range.join(startRange, tn.range()));
const ret: FieldDeclaration = Statement.createField(identifier, type, initializer, modifiers, decorators, Range.join(startRange, tn.range()));
tn.skip(Token.SEMICOLON);
return ret;
}
@ -740,9 +751,32 @@ export class Parser extends DiagnosticEmitter {
return null;
}
parseExport(tn: Tokenizer, modifiers: Modifier[]): ExportStatement | null {
parseNamespace(tn: Tokenizer, modifiers: Modifier[] | null, decorators: Decorator[] | null): NamespaceDeclaration | null {
// at 'namespace': Identifier '{' (Variable | Function)* '}'
const startRange: Range = modifiers && modifiers.length ? modifiers[0].range : tn.range();
if (tn.skip(Token.IDENTIFIER)) {
const identifier: IdentifierExpression = Expression.createIdentifier(tn.readIdentifier(), tn.range());
if (tn.skip(Token.OPENBRACE)) {
const members: Statement[] = new Array();
while (!tn.skip(Token.CLOSEBRACE)) {
const member: Statement | null = this.parseTopLevelStatement(tn, true);
if (!member)
return null;
members.push(member);
}
const ret: NamespaceDeclaration = Statement.createNamespace(identifier, members, modifiers, decorators, Range.join(startRange, tn.range()));
tn.skip(Token.SEMICOLON);
return ret;
} else
this.error(DiagnosticCode._0_expected, tn.range(), "{");
} else
this.error(DiagnosticCode.Identifier_expected, tn.range());
return null;
}
parseExport(tn: Tokenizer, modifiers: Modifier[] | null): ExportStatement | null {
// at 'export': '{' ExportMember (',' ExportMember)* }' ('from' StringLiteral)? ';'?
const startRange: Range = modifiers.length ? modifiers[0].range : tn.range();
const startRange: Range = modifiers && modifiers.length ? modifiers[0].range : tn.range();
if (tn.skip(Token.OPENBRACE)) {
const members: ExportMember[] = new Array();
if (!tn.skip(Token.CLOSEBRACE)) {
@ -766,7 +800,7 @@ export class Parser extends DiagnosticEmitter {
return null;
}
}
const ret: ExportStatement = Statement.createExport(modifiers, members, path, Range.join(startRange, tn.range()));
const ret: ExportStatement = Statement.createExport(members, path, modifiers, Range.join(startRange, tn.range()));
if (ret.normalizedPath && !this.seenlog.has(<string>ret.normalizedPath)) {
this.backlog.push(<string>ret.normalizedPath);
this.seenlog.add(<string>ret.normalizedPath);
@ -881,7 +915,7 @@ export class Parser extends DiagnosticEmitter {
return this.parseBreak(tn);
case Token.CONST:
return this.parseVariable(tn, [ Statement.createModifier(ModifierKind.CONST, tn.range()) ]);
return this.parseVariable(tn, [ Statement.createModifier(ModifierKind.CONST, tn.range()) ], null);
case Token.CONTINUE:
return this.parseContinue(tn);
@ -897,7 +931,7 @@ export class Parser extends DiagnosticEmitter {
case Token.LET:
case Token.VAR:
return this.parseVariable(tn, []);
return this.parseVariable(tn, null, null);
case Token.OPENBRACE:
return this.parseBlockStatement(tn, topLevel);
@ -1007,7 +1041,7 @@ export class Parser extends DiagnosticEmitter {
if (tn.skip(Token.OPENPAREN)) {
let initializer: Statement | null = null;
if (tn.skip(Token.LET) || tn.skip(Token.CONST) || tn.skip(Token.VAR)) {
initializer = this.parseVariable(tn, /* TODO */ createModifiers());
initializer = this.parseVariable(tn, null, null);
} else if (!tn.skip(Token.SEMICOLON)) {
initializer = this.parseExpressionStatement(tn);
if (!initializer)

View File

@ -22,7 +22,7 @@ import {
ClassDeclaration,
DeclarationStatement,
DecoratorStatement,
Decorator,
EnumDeclaration,
EnumValueDeclaration,
ExportMember,
@ -665,9 +665,9 @@ export class Program extends DiagnosticEmitter {
}
}
function checkGlobalDecorator(decorators: DecoratorStatement[]): string | null {
function checkGlobalDecorator(decorators: Decorator[]): string | null {
for (let i: i32 = 0, k: i32 = decorators.length; i < k; ++i) {
const decorator: DecoratorStatement = decorators[i];
const decorator: Decorator = decorators[i];
const expression: Expression = decorator.expression;
const args: Expression[] = decorator.arguments;
if (expression.kind == NodeKind.IDENTIFIER && args.length <= 1 && (<IdentifierExpression>expression).name == "global") {

6
std/carray.d.ts vendored
View File

@ -1,6 +1,12 @@
/// <reference path="../assembly.d.ts" />
/** A C-compatible array class. */
declare class CArray<T> {
[key: number]: T;
/** Constructs a new C-Array of the specified capacity. */
constructor(capacity: usize);
/** Disposes this instance and the memory associated with it. */
dispose(): void;
}

11
std/cstring.d.ts vendored
View File

@ -1,5 +1,12 @@
/// <reference path="../assembly.d.ts" />
declare class CString extends CArray<u8> {
constructor(text: string);
/** A C-compatible string class. */
declare class CString {
readonly [key: number]: u8;
/** Constructs a new C-String from a standard string. */
constructor(string: string);
/** Disposes this instance and the memory associated with it. */
dispose(): void;
}

20
std/heap.ts Normal file
View File

@ -0,0 +1,20 @@
/// <reference path="../assembly.d.ts" />
/** A static class representing the heap. */
declare class Heap {
/** Allocates a chunk of memory and returns a pointer to it. */
static allocate(size: usize): usize;
/** Disposes a chunk of memory by its pointer. */
static dispose(ptr: usize): void;
/** Gets the amount of used heap space, in bytes. */
static get used(): usize;
/** Gets the amount of free heap space, in bytes. */
static get free(): usize;
/** Gets the size of the heap, in bytes. */
static get size(): usize;
}

View File

@ -1,29 +1,25 @@
/// <reference path="../../assembly.d.ts" />
/** A C-compatible Array class. */
@global()
@struct()
class CArray<T> {
/** Constructs a new C-Array of the specified capacity. */
constructor(capacity: usize) {
return unsafe_cast<usize,this>(Memory.allocate(capacity * sizeof<T>()));
return changetype<usize, this>(Heap.allocate(capacity * sizeof<T>()));
}
/** Gets the element at the specified index using bracket notation. */
@inline()
"[]"(index: usize): T {
return load<T>(unsafe_cast<this,usize>(this) + index * sizeof<T>());
return load<T>(changetype<this, usize>(this) + index * sizeof<T>());
}
/** Sets the element at the specified index using bracket notation. */
@inline()
"[]="(index: usize, value: T): T {
store<T>(unsafe_cast<this,usize>(this) + index * sizeof<T>(), value);
store<T>(changetype<this, usize>(this) + index * sizeof<T>(), value);
return value;
}
/** Disposes this instance and the memory associated with it. */
dispose(): void {
Memory.dispose(unsafe_cast<this,usize>(this));
Heap.dispose(changetype<this, usize>(this));
}
}

View File

@ -1,17 +1,16 @@
/// <reference path="../../assembly.d.ts" />
/** A C-compatible string class. */
@global()
class CString extends CArray<u8> {
@struct()
class CString {
/** Constructs a new C-String from a String. */
constructor(text: string) {
super(text.length * 2 + 1);
let idx: usize = unsafe_cast<this,usize>(this);
for (let i: usize = 0, k: usize = (<string>str).length; i < k; ++i) {
let u: i32 = text.charCodeAt(i);
constructor(string: string) {
const ptr: usize = Heap.allocate(<usize>string.length * 2 + 1);
let idx: usize = ptr;
for (let i: usize = 0, k: usize = <usize>(<string>str).length; i < k; ++i) {
let u: i32 = string.charCodeAt(i);
if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k)
u = 0x10000 + ((u & 0x3FF) << 10) | (text.charCodeAt(++i) & 0x3FF);
u = 0x10000 + ((u & 0x3FF) << 10) | (string.charCodeAt(++i) & 0x3FF);
if (u <= 0x7F)
store<u8>(idx++, u as u8);
else if (u <= 0x7FF) {
@ -43,5 +42,17 @@ class CString extends CArray<u8> {
}
}
store<u8>(idx, 0);
return changetype<usize, this>(ptr);
}
@inline()
"[]"(index: usize): u8 {
return load<u8>(changetype<this, usize>(this) + index /* * sizeof<u8>() */);
}
// read-only
dispose(): void {
Heap.dispose(changetype<this, usize>(this));
}
}

38
std/impl/heap.ts Normal file
View File

@ -0,0 +1,38 @@
/// <reference path="../../assembly.d.ts" />
const ALIGN_LOG2: usize = 3;
const ALIGN_SIZE: usize = 1 << ALIGN_LOG2;
const ALIGN_MASK: usize = ALIGN_SIZE - 1;
let HEAP_OFFSET: usize = HEAP_START; // HEAP_START is a constant generated by the compiler
@global()
@struct()
class Heap {
static allocate(size: usize): usize {
const ptr: usize = HEAP_OFFSET;
assert(ptr + size <= (<usize>current_memory() << 16));
if (((HEAP_OFFSET += size) & ALIGN_MASK) != 0) // align next offset
HEAP_OFFSET = (HEAP_OFFSET | ALIGN_MASK) + 1;
return ptr;
}
static dispose(ptr: usize): void {
// just a big chunk of non-disposable memory for now
}
static get used(): usize {
return HEAP_OFFSET - HEAP_START;
}
static get free(): usize {
return (<usize>current_memory() << 16) - HEAP_OFFSET;
}
static get size(): usize {
return (<usize>current_memory() << 16) - HEAP_START;
}
private constructor() {}
}

View File

@ -1,21 +0,0 @@
/// <reference path="../../assembly.d.ts" />
const MEMORY_ALIGN_LOG2: usize = 3;
const MEMORY_ALIGN_SIZE: usize = 1 << MEMORY_ALIGN_LOG2;
const MEMORY_ALIGN_MASK: usize = MEMORY_ALIGN_SIZE - 1;
@global()
class Memory {
static allocate(size: usize): usize {
const ptr: usize = HEAP_OFFSET;
HEAP_OFFSET += size;
if ((HEAP_OFFSET & MEMORY_ALIGN_MASK) != 0)
HEAP_OFFSET = (HEAP_OFFSET | MEMORY_ALIGN_MASK) + 1;
return ptr;
}
static dispose(ptr: usize): void {
// just a big chunk of non-disposable memory for now
}
}

View File

@ -6,6 +6,6 @@
"files": [
"carray.ts",
"cstring.ts",
"memory.ts"
"heap.ts"
]
}

6
std/memory.d.ts vendored
View File

@ -1,6 +0,0 @@
/// <reference path="../assembly.d.ts" />
declare class Memory {
static allocate(size: usize): usize;
static dispose(ptr: usize): void;
}

View File

@ -6,6 +6,6 @@
"files": [
"carray.d.ts",
"cstring.d.ts",
"memory.d.ts"
"heap.d.ts"
]
}

View File

@ -1,7 +1,6 @@
(module
(type $v (func))
(memory $0 1)
(data (i32.const 4) "\08")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)

View File

@ -1,7 +1,7 @@
(module
(type $v (func))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
@ -37,6 +37,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -6,7 +6,6 @@
(global $binary/f (mut f32) (f32.const 0))
(global $binary/F (mut f64) (f64.const 0))
(memory $0 1)
(data (i32.const 4) "\08")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)

View File

@ -5,8 +5,8 @@
(global $binary/I (mut i64) (i64.const 0))
(global $binary/f (mut f32) (f32.const 0))
(global $binary/F (mut f64) (f64.const 0))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
@ -840,6 +840,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -7,7 +7,6 @@
(global $builtins/F (mut f64) (f64.const 0))
(global $builtins/s (mut i32) (i32.const 0))
(memory $0 1)
(data (i32.const 4) "\08")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)

View File

@ -6,8 +6,8 @@
(global $builtins/b (mut i32) (i32.const 0))
(global $builtins/F (mut f64) (f64.const 0))
(global $builtins/s (mut i32) (i32.const 0))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
@ -1083,6 +1083,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -1,8 +1,8 @@
(module
(type $v (func))
(import "env" "external" (func $declare/external))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "external" (func $declare/external))
(export "memory" (memory $0))
)
@ -30,6 +30,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -1,7 +1,6 @@
(module
(type $iv (func (param i32)))
(memory $0 1)
(data (i32.const 4) "\08")
(export "loopDo" (func $do/loopDo))
(export "loopDoInDo" (func $do/loopDoInDo))
(export "memory" (memory $0))

View File

@ -1,7 +1,7 @@
(module
(type $iv (func (param i32)))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "loopDo" (func $do/loopDo))
(export "loopDoInDo" (func $do/loopDoInDo))
(export "memory" (memory $0))
@ -75,6 +75,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -4,7 +4,6 @@
(global $enum/NonConstant.ZERO (mut i32) (i32.const 0))
(global $enum/NonConstant.ONE (mut i32) (i32.const 0))
(memory $0 1)
(data (i32.const 4) "\08")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)

View File

@ -4,7 +4,6 @@
(global $enum/NonConstant.ZERO (mut i32) (i32.const 0))
(global $enum/NonConstant.ONE (mut i32) (i32.const 0))
(memory $0 1)
(data (i32.const 4) "\08")
(export "memory" (memory $0))
(start $start)
(func $enum/getZero (; 0 ;) (type $i) (result i32)

View File

@ -15,8 +15,8 @@
(global $enum/Mixed.FOUR i32 (i32.const 4))
(global $enum/NonConstant.ZERO (mut i32) (i32.const 0))
(global $enum/NonConstant.ONE (mut i32) (i32.const 0))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(start $start)
(func $enum/getZero (; 0 ;) (type $i) (result i32)
@ -60,6 +60,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -3,7 +3,6 @@
(global $export/a i32 (i32.const 1))
(global $export/b i32 (i32.const 2))
(memory $0 1)
(data (i32.const 4) "\08")
(export "add" (func $export/add))
(export "renamed_sub" (func $export/sub))
(export "a" (global $export/a))

View File

@ -13,3 +13,8 @@ export const a: i32 = 1;
const b: i32 = 2;
export { b as renamed_b };
/* export namespace ns {
function one(): void {}
export function two(): void {}
} */

View File

@ -2,8 +2,8 @@
(type $iii (func (param i32 i32) (result i32)))
(global $export/a i32 (i32.const 1))
(global $export/b i32 (i32.const 2))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "add" (func $export/add))
(export "renamed_sub" (func $export/sub))
(export "a" (global $export/a))
@ -50,6 +50,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -2,7 +2,6 @@
(type $v (func))
(global $for/i (mut i32) (i32.const 0))
(memory $0 1)
(data (i32.const 4) "\08")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)

View File

@ -1,8 +1,8 @@
(module
(type $v (func))
(global $for/i (mut i32) (i32.const 0))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
@ -171,6 +171,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -5,7 +5,6 @@
(global $game-of-life/h (mut i32) (i32.const 0))
(global $game-of-life/s (mut i32) (i32.const 0))
(memory $0 1)
(data (i32.const 4) "\08")
(export "init" (func $game-of-life/init))
(export "step" (func $game-of-life/step))
(export "memory" (memory $0))

View File

@ -4,8 +4,8 @@
(global $game-of-life/w (mut i32) (i32.const 0))
(global $game-of-life/h (mut i32) (i32.const 0))
(global $game-of-life/s (mut i32) (i32.const 0))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "init" (func $game-of-life/init))
(export "step" (func $game-of-life/step))
(export "memory" (memory $0))
@ -332,6 +332,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -1,7 +1,6 @@
(module
(type $ii (func (param i32) (result i32)))
(memory $0 1)
(data (i32.const 4) "\08")
(export "ifThenElse" (func $if/ifThenElse))
(export "ifThen" (func $if/ifThen))
(export "ifThenElseBlock" (func $if/ifThenElse))

View File

@ -1,7 +1,7 @@
(module
(type $ii (func (param i32) (result i32)))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "ifThenElse" (func $if/ifThenElse))
(export "ifThen" (func $if/ifThen))
(export "ifThenElseBlock" (func $if/ifThenElseBlock))
@ -70,6 +70,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -2,7 +2,6 @@
(type $iii (func (param i32 i32) (result i32)))
(type $v (func))
(memory $0 1)
(data (i32.const 4) "\08")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)

View File

@ -2,7 +2,6 @@
(type $iii (func (param i32 i32) (result i32)))
(type $v (func))
(memory $0 1)
(data (i32.const 4) "\08")
(export "memory" (memory $0))
(start $start)
(func $export/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)

View File

@ -3,8 +3,8 @@
(type $v (func))
(global $export/a i32 (i32.const 1))
(global $export/b i32 (i32.const 2))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(start $start)
(func $export/add (; 0 ;) (type $iii) (param $0 i32) (param $1 i32) (result i32)
@ -62,6 +62,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -1,7 +1,6 @@
(module
(type $v (func))
(memory $0 1)
(data (i32.const 4) "\08")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)

View File

@ -1,7 +1,7 @@
(module
(type $v (func))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
@ -163,6 +163,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -5,7 +5,6 @@
(global $logical/f (mut f32) (f32.const 0))
(global $logical/F (mut f64) (f64.const 0))
(memory $0 1)
(data (i32.const 4) "\08")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)

View File

@ -4,8 +4,8 @@
(global $logical/I (mut i64) (i64.const 0))
(global $logical/f (mut f32) (f32.const 0))
(global $logical/F (mut f64) (f64.const 0))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
@ -291,6 +291,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -4,7 +4,6 @@
(global $export/a i32 (i32.const 1))
(global $export/b i32 (i32.const 2))
(memory $0 1)
(data (i32.const 4) "\08")
(export "add" (func $export/add))
(export "renamed_sub" (func $export/sub))
(export "renamed_a" (global $export/a))

View File

@ -3,8 +3,8 @@
(type $v (func))
(global $export/a i32 (i32.const 1))
(global $export/b i32 (i32.const 2))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "add" (func $export/add))
(export "renamed_sub" (func $export/sub))
(export "renamed_a" (global $export/a))
@ -68,6 +68,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -1,7 +1,6 @@
(module
(type $ii (func (param i32) (result i32)))
(memory $0 1)
(data (i32.const 4) "\08")
(export "doSwitch" (func $switch/doSwitch))
(export "doSwitchDefaultFirst" (func $switch/doSwitchDefaultFirst))
(export "doSwitchDefaultOmitted" (func $switch/doSwitchDefaultOmitted))

View File

@ -1,7 +1,7 @@
(module
(type $ii (func (param i32) (result i32)))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "doSwitch" (func $switch/doSwitch))
(export "doSwitchDefaultFirst" (func $switch/doSwitchDefaultFirst))
(export "doSwitchDefaultOmitted" (func $switch/doSwitchDefaultOmitted))
@ -169,6 +169,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -2,7 +2,6 @@
(type $v (func))
(global $ternary/a (mut i32) (i32.const 0))
(memory $0 1)
(data (i32.const 4) "\08")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)

View File

@ -1,8 +1,8 @@
(module
(type $v (func))
(global $ternary/a (mut i32) (i32.const 0))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
@ -57,6 +57,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -6,7 +6,6 @@
(type $iv (func (param i32)))
(type $v (func))
(memory $0 1)
(data (i32.const 4) "\08")
(export "control$construct" (func $tlsf/control$construct))
(export "memory" (memory $0))
(start $start)

View File

@ -6,7 +6,6 @@
(type $iv (func (param i32)))
(type $v (func))
(memory $0 1)
(data (i32.const 4) "\08")
(export "control$construct" (func $tlsf/control$construct))
(export "memory" (memory $0))
(start $start)

View File

@ -21,8 +21,8 @@
(global $tlsf/CONTROL$SL_BITMAP_OFFSET i32 (i32.const 20))
(global $tlsf/SL_INDEX_COUNT i32 (i32.const 32))
(global $tlsf/CONTROL$BLOCKS_OFFSET i32 (i32.const 112))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "control$construct" (func $tlsf/control$construct))
(export "memory" (memory $0))
(start $start)
@ -352,6 +352,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -5,7 +5,6 @@
(global $unary/f (mut f32) (f32.const 0))
(global $unary/F (mut f64) (f64.const 0))
(memory $0 1)
(data (i32.const 4) "\08")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)

View File

@ -4,8 +4,8 @@
(global $unary/I (mut i64) (i64.const 0))
(global $unary/f (mut f32) (f32.const 0))
(global $unary/F (mut f64) (f64.const 0))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "memory" (memory $0))
(start $start)
(func $start (; 0 ;) (type $v)
@ -657,6 +657,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert

View File

@ -1,7 +1,6 @@
(module
(type $iv (func (param i32)))
(memory $0 1)
(data (i32.const 4) "\08")
(export "loopWhile" (func $while/loopWhile))
(export "loopWhileInWhile" (func $while/loopWhileInWhile))
(export "memory" (memory $0))

View File

@ -1,7 +1,7 @@
(module
(type $iv (func (param i32)))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "loopWhile" (func $while/loopWhile))
(export "loopWhileInWhile" (func $while/loopWhileInWhile))
(export "memory" (memory $0))
@ -84,6 +84,7 @@
reinterpret
select
sizeof
changetype
isNaN
isFinite
assert