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. */ /** A 64-bit float. */
declare type f64 = number; 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. */ /** 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; declare function clz<T = i32 | i64>(value: T): T;
@ -78,6 +78,8 @@ declare const NaN: f32 | f64;
declare const Infinity: f32 | f64; declare const Infinity: f32 | f64;
/** Determines the byte size of the specified core or class type. Compiles to a constant. */ /** Determines the byte size of the specified core or class type. Compiles to a constant. */
declare function sizeof<T>(): usize; 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. */ /** Tests if a 32-bit or 64-bit float is NaN. */
declare function isNaN<T = f32 | f64>(value: T): bool; 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. */ /** 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 // internal decorators
/** Annotates an element being part of the global namespace. */
declare function global(): any; declare function global(): any;
/** Annotates a function being always inlined. */
declare function inline(): any; declare function inline(): any;
/** Annotates a class using a C-style memory layout. */
declare function struct(): any;
// standard library // standard library
/// <reference path="./std/carray.d.ts" /> /// <reference path="./std/carray.d.ts" />
/// <reference path="./std/cstring.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) if (hasErrors)
process.exit(1); 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; hasErrors = false;
while ((diagnostic = assemblyscript.nextDiagnostic(parser)) != null) { while ((diagnostic = assemblyscript.nextDiagnostic(parser)) != null) {

View File

@ -1,29 +1,37 @@
{ {
"version": { "version": {
"desc": "Print the compiler's version.", "desc": "Prints the compiler's version.",
"type": "boolean", "type": "boolean",
"aliases": [ "v" ] "aliases": [ "v" ]
}, },
"help": { "help": {
"desc": "Print this message.", "desc": "Prints this message.",
"type": "boolean", "type": "boolean",
"aliases": [ "h" ] "aliases": [ "h" ]
}, },
"optimize": { "optimize": {
"desc": "Optimize the module.", "desc": "Optimizes the module.",
"type": "boolean", "type": "boolean",
"aliases": [ "O" ] "aliases": [ "O" ]
}, },
"validate": { "validate": {
"desc": "Validate the module.", "desc": "Validates the module.",
"type": "boolean" "type": "boolean"
}, },
"outFile": { "outFile": {
"desc": "Specify the output file (binary format).", "desc": "Specifies the output file (binary format).",
"type": "string" "type": "string"
}, },
"textFile": { "textFile": {
"desc": "Specify the output file (text format).", "desc": "Specifies the output file (text format).",
"type": "string" "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; 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(); const stmt: ClassDeclaration = new ClassDeclaration();
stmt.range = range; stmt.range = range;
let i: i32, k: i32; 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; (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.typeParameters = typeParameters).length; i < k; ++i) typeParameters[i].parent = stmt;
if (stmt.extendsType = extendsType) (<TypeNode>extendsType).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.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.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; return stmt;
} }
@ -678,8 +678,8 @@ export abstract class Statement extends Node {
return stmt; return stmt;
} }
static createDecorator(expression: Expression, args: Expression[], range: Range): DecoratorStatement { static createDecorator(expression: Expression, args: Expression[], range: Range): Decorator {
const stmt: DecoratorStatement = new DecoratorStatement(); const stmt: Decorator = new Decorator();
stmt.range = range; stmt.range = range;
(stmt.expression = expression).parent = stmt; (stmt.expression = expression).parent = stmt;
for (let i: i32 = 0, k: i32 = (stmt.arguments = args).length; i < k; ++i) args[i].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; 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(); const stmt: EnumDeclaration = new EnumDeclaration();
stmt.range = range; stmt.range = range;
let i: i32, k: i32; 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; (stmt.identifier = identifier).parent = stmt;
for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].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; return stmt;
} }
@ -718,15 +719,15 @@ export abstract class Statement extends Node {
return stmt; 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(); const stmt: ExportStatement = new ExportStatement();
stmt.range = range; stmt.range = range;
let i: i32, k: i32; 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; for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].parent = stmt;
stmt.path = path; stmt.path = path;
stmt.normalizedPath = path ? resolvePath(normalizePath(path.value), range.source.normalizedPath) : null; stmt.normalizedPath = path ? resolvePath(normalizePath(path.value), range.source.normalizedPath) : null;
stmt.internalPath = stmt.normalizedPath ? mangleInternalPath(stmt.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; return stmt;
} }
@ -780,25 +781,26 @@ export abstract class Statement extends Node {
return elem; 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(); const stmt: InterfaceDeclaration = new InterfaceDeclaration();
stmt.range = range; stmt.range = range;
let i: i32, k: i32; 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; if (stmt.extendsType = extendsType) (<TypeNode>extendsType).parent = stmt;
for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].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; 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(); const stmt: FieldDeclaration = new FieldDeclaration();
stmt.range = range; stmt.range = range;
let i: i32, k: i32; 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; (stmt.identifier = identifier).parent = stmt;
if (stmt.type = type) (<TypeNode>type).parent = stmt; if (stmt.type = type) (<TypeNode>type).parent = stmt;
if (stmt.initializer = initializer) (<Expression>initializer).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; return stmt;
} }
@ -830,31 +832,31 @@ export abstract class Statement extends Node {
return elem; 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(); const stmt: FunctionDeclaration = new FunctionDeclaration();
stmt.range = range; stmt.range = range;
let i: i32, k: i32; 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; (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.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; 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.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; 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; 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(); const stmt: MethodDeclaration = new MethodDeclaration();
stmt.range = range; stmt.range = range;
let i: i32, k: i32; 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; (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.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; 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.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; 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; return stmt;
} }
@ -865,13 +867,14 @@ export abstract class Statement extends Node {
return elem; 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(); const stmt: NamespaceDeclaration = new NamespaceDeclaration();
stmt.range = range; stmt.range = range;
let i: i32, k: i32; 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; (stmt.identifier = identifier).parent = stmt;
for (i = 0, k = (stmt.members = members).length; i < k; ++i) members[i].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; return stmt;
} }
@ -916,22 +919,24 @@ export abstract class Statement extends Node {
return stmt; 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(); const stmt: VariableStatement = new VariableStatement();
stmt.range = range; stmt.range = range;
let i: i32, k: i32; 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; 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; 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(); const elem: VariableDeclaration = new VariableDeclaration();
elem.range = range; elem.range = range;
(elem.identifier = identifier).parent = elem; (elem.identifier = identifier).parent = elem;
if (elem.type = type) (<TypeNode>type).parent = elem; if (elem.type = type) (<TypeNode>type).parent = elem;
if (elem.initializer = initializer) (<Expression>initializer).parent = elem; if (elem.initializer = initializer) (<Expression>initializer).parent = elem;
elem.modifiers = modifiers; elem.modifiers = modifiers;
elem.decorators = decorators;
return elem; return elem;
} }
@ -987,6 +992,7 @@ export abstract class DeclarationStatement extends Statement {
identifier: IdentifierExpression; identifier: IdentifierExpression;
modifiers: Modifier[] | null; modifiers: Modifier[] | null;
decorators: Decorator[] | null = null;
protected _cachedInternalName: string | null = null; protected _cachedInternalName: string | null = null;
@ -1037,12 +1043,11 @@ export class ClassDeclaration extends DeclarationStatement {
extendsType: TypeNode | null; extendsType: TypeNode | null;
implementsTypes: TypeNode[]; implementsTypes: TypeNode[];
members: DeclarationStatement[]; members: DeclarationStatement[];
decorators: DecoratorStatement[];
get internalName(): string { get internalName(): string {
if (this._cachedInternalName !== null) if (this._cachedInternalName !== null)
return this._cachedInternalName; 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") if (globalDecorator && globalDecorator.expression.kind == NodeKind.IDENTIFIER && (<IdentifierExpression>globalDecorator.expression).name == "global")
return this._cachedInternalName = this.identifier.name; return this._cachedInternalName = this.identifier.name;
else else
@ -1051,6 +1056,7 @@ export class ClassDeclaration extends DeclarationStatement {
serialize(sb: string[]): void { serialize(sb: string[]): void {
let i: i32, k: i32; let i: i32, k: i32;
if (this.decorators)
for (i = 0, k = this.decorators.length; i < k; ++i) { for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb); this.decorators[i].serialize(sb);
sb.push("\n"); sb.push("\n");
@ -1109,7 +1115,7 @@ export class ContinueStatement extends Statement {
} }
} }
export class DecoratorStatement extends Statement { export class Decorator extends Statement {
kind = NodeKind.DECORATOR; kind = NodeKind.DECORATOR;
expression: Expression; expression: Expression;
@ -1264,10 +1270,10 @@ export class ExpressionStatement extends Statement {
export class FieldDeclaration extends VariableLikeDeclarationStatement { export class FieldDeclaration extends VariableLikeDeclarationStatement {
kind = NodeKind.FIELD; kind = NodeKind.FIELD;
decorators: DecoratorStatement[];
serialize(sb: string[]): void { serialize(sb: string[]): void {
let i: i32, k: i32; let i: i32, k: i32;
if (this.decorators)
for (i = 0, k = this.decorators.length; i < k; ++i) { for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb); this.decorators[i].serialize(sb);
sb.push("\n"); sb.push("\n");
@ -1323,12 +1329,11 @@ export class FunctionDeclaration extends DeclarationStatement {
parameters: Parameter[]; parameters: Parameter[];
returnType: TypeNode | null; returnType: TypeNode | null;
statements: Statement[] | null; statements: Statement[] | null;
decorators: DecoratorStatement[];
get internalName(): string { get internalName(): string {
if (this._cachedInternalName !== null) if (this._cachedInternalName !== null)
return this._cachedInternalName; 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") if (globalDecorator && globalDecorator.expression.kind == NodeKind.IDENTIFIER && (<IdentifierExpression>globalDecorator.expression).name == "global")
return this._cachedInternalName = this.identifier.name; return this._cachedInternalName = this.identifier.name;
else else
@ -1337,6 +1342,7 @@ export class FunctionDeclaration extends DeclarationStatement {
serialize(sb: string[]): void { serialize(sb: string[]): void {
let i: i32, k: i32; let i: i32, k: i32;
if (this.decorators)
for (i = 0, k = this.decorators.length; i < k; ++i) { for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb); this.decorators[i].serialize(sb);
sb.push("\n"); sb.push("\n");
@ -1453,6 +1459,11 @@ export class InterfaceDeclaration extends ClassDeclaration {
serialize(sb: string[]): void { serialize(sb: string[]): void {
let i: i32, k: i32; 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) if (this.modifiers)
for (i = 0, k = (<Modifier[]>this.modifiers).length; i < k; ++i) { for (i = 0, k = (<Modifier[]>this.modifiers).length; i < k; ++i) {
(<Modifier[]>this.modifiers)[i].serialize(sb); (<Modifier[]>this.modifiers)[i].serialize(sb);
@ -1491,6 +1502,7 @@ export class MethodDeclaration extends FunctionDeclaration {
serialize(sb: string[]): void { serialize(sb: string[]): void {
let i: i32, k: i32; let i: i32, k: i32;
if (this.decorators)
for (i = 0, k = this.decorators.length; i < k; ++i) { for (i = 0, k = this.decorators.length; i < k; ++i) {
this.decorators[i].serialize(sb); this.decorators[i].serialize(sb);
sb.push("\n"); sb.push("\n");
@ -1511,6 +1523,11 @@ export class NamespaceDeclaration extends DeclarationStatement {
serialize(sb: string[]): void { serialize(sb: string[]): void {
let i: i32, k: i32; 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) if (this.modifiers)
for (i = 0, k = (<Modifier[]>this.modifiers).length; i < k; ++i) { for (i = 0, k = (<Modifier[]>this.modifiers).length; i < k; ++i) {
(<Modifier[]>this.modifiers)[i].serialize(sb); (<Modifier[]>this.modifiers)[i].serialize(sb);
@ -1701,11 +1718,17 @@ export class VariableStatement extends Statement {
kind = NodeKind.VARIABLE; kind = NodeKind.VARIABLE;
modifiers: Modifier[] | null; modifiers: Modifier[] | null;
decorators: Decorator[] | null;
declarations: VariableDeclaration[]; declarations: VariableDeclaration[];
serialize(sb: string[]): void { serialize(sb: string[]): void {
let isConst: bool = false; let isConst: bool = false;
let i: i32, k: i32; 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) if (this.modifiers)
for (i = 0, k = (<Modifier[]>this.modifiers).length; i < k; ++i) { for (i = 0, k = (<Modifier[]>this.modifiers).length; i < k; ++i) {
(<Modifier[]>this.modifiers)[i].serialize(sb); (<Modifier[]>this.modifiers)[i].serialize(sb);
@ -1745,9 +1768,9 @@ export function hasModifier(kind: ModifierKind, modifiers: Modifier[] | null): b
return false; 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) { 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 expression: Expression = decorator.expression;
if (expression.kind == NodeKind.IDENTIFIER && (<IdentifierExpression>expression).name == name) if (expression.kind == NodeKind.IDENTIFIER && (<IdentifierExpression>expression).name == name)
return decorator; return decorator;

View File

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

View File

@ -148,7 +148,7 @@ export class Compiler extends DiagnosticEmitter {
const startFunctionTemplate: FunctionPrototype = new FunctionPrototype(program, "start", null); const startFunctionTemplate: FunctionPrototype = new FunctionPrototype(program, "start", null);
const startFunctionInstance: Function = new Function(startFunctionTemplate, startFunctionTemplate.internalName, [], [], Type.void, null); const startFunctionInstance: Function = new Function(startFunctionTemplate, startFunctionTemplate.internalName, [], [], Type.void, null);
this.currentFunction = this.startFunction = startFunctionInstance; 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}. */ /** Performs compilation of the underlying {@link Program} to a {@link Module}. */
@ -178,32 +178,12 @@ export class Compiler extends DiagnosticEmitter {
} }
// set up memory // set up memory
// store heapStart at `sizeof<usize>()` (that is right after `null`) as an usize
const initial: U64 = this.memoryOffset.clone(); const initial: U64 = this.memoryOffset.clone();
let heapStartBuffer: Uint8Array; if (this.options.target == Target.WASM64)
let heapStartOffset: i32; this.module.addGlobal("HEAP_START", NativeType.I64, false, this.module.createI64(initial.lo, initial.hi));
if (this.options.target == Target.WASM64) { else
heapStartBuffer = new Uint8Array(8); this.module.addGlobal("HEAP_START", NativeType.I32, false, this.module.createI32(initial.lo));
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?
// determine initial page size // determine initial page size
const initialOverlaps: U64 = initial.clone(); const initialOverlaps: U64 = initial.clone();
initialOverlaps.and32(0xffff); initialOverlaps.and32(0xffff);
@ -663,7 +643,7 @@ export class Compiler extends DiagnosticEmitter {
// memory // memory
addMemorySegment(buffer: Uint8Array): MemorySegment { 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.or32(7);
this.memoryOffset.add32(1); this.memoryOffset.add32(1);
} }

View File

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

View File

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

View File

@ -20,11 +20,12 @@
*/ */
import { Module } from "./module"; import { Module } from "./module";
import { Compiler } from "./compiler"; import { Compiler, Options, Target } from "./compiler";
import { DiagnosticMessage, DiagnosticCategory } from "./diagnostics"; import { DiagnosticMessage, DiagnosticCategory, formatDiagnosticMessage } from "./diagnostics";
import { Parser } from "./parser"; import { Parser } from "./parser";
import { Program } from "./program"; 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 { export function parseFile(text: string, path: string, parser: Parser | null = null): Parser {
let isEntry: bool = false; let isEntry: bool = false;
if (!parser) { if (!parser) {
@ -35,10 +36,12 @@ export function parseFile(text: string, path: string, parser: Parser | null = nu
return parser; return parser;
} }
/** Obtains the path to the next file required by the parser. Returns `null` once complete. */
export function nextFile(parser: Parser): string | null { export function nextFile(parser: Parser): string | null {
return parser.nextFile(); return parser.nextFile();
} }
/** Obtains the next diagnostic message. Returns `null` once there are no more messages. */
export function nextDiagnostic(parser: Parser): DiagnosticMessage | null { export function nextDiagnostic(parser: Parser): DiagnosticMessage | null {
const program: Program = parser.program; const program: Program = parser.program;
if (program.diagnosticsOffset < program.diagnostics.length) if (program.diagnosticsOffset < program.diagnostics.length)
@ -46,13 +49,49 @@ export function nextDiagnostic(parser: Parser): DiagnosticMessage | null {
return 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 { export function isError(message: DiagnosticMessage): bool {
return message.category == DiagnosticCategory.ERROR; return message.category == DiagnosticCategory.ERROR;
} }
export function compile(parser: Parser): Module { /** Creates a new set of compiler options. */
const program: Program = parser.finish(); export function createOptions(): Options {
return Compiler.compile(program); 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 { normalizePath, I64 } from "./util";
import { import {
Node,
NodeKind, NodeKind,
Source, Source,
@ -30,7 +31,7 @@ import {
BreakStatement, BreakStatement,
ClassDeclaration, ClassDeclaration,
ContinueStatement, ContinueStatement,
DecoratorStatement, Decorator,
DoStatement, DoStatement,
EnumDeclaration, EnumDeclaration,
EnumValueDeclaration, EnumValueDeclaration,
@ -60,7 +61,8 @@ import {
VariableDeclaration, VariableDeclaration,
WhileStatement, WhileStatement,
hasModifier hasModifier,
NamespaceDeclaration
} from "./ast"; } from "./ast";
@ -89,16 +91,25 @@ export class Parser extends DiagnosticEmitter {
source.tokenizer = tn; source.tokenizer = tn;
while (!tn.skip(Token.ENDOFFILE)) { while (!tn.skip(Token.ENDOFFILE)) {
const statement: Statement | null = this.parseTopLevelStatement(tn);
if (!statement)
return;
statement.parent = source;
source.statements.push(statement);
}
reusableModifiers = null;
}
let decorators: DecoratorStatement[] | null = null; parseTopLevelStatement(tn: Tokenizer, isNamespaceMember: bool = false): Statement | null {
let decorators: Decorator[] | null = null;
while (tn.skip(Token.AT)) { while (tn.skip(Token.AT)) {
const decorator: DecoratorStatement | null = this.parseDecorator(tn); const decorator: Decorator | null = this.parseDecorator(tn);
if (!decorator) if (!decorator)
break; break;
if (!decorators) if (!decorators)
decorators = new Array(); decorators = new Array();
(<DecoratorStatement[]>decorators).push(<DecoratorStatement>decorator); (<Decorator[]>decorators).push(<Decorator>decorator);
} }
let modifiers: Modifier[] | null = null; let modifiers: Modifier[] | null = null;
@ -122,22 +133,24 @@ export class Parser extends DiagnosticEmitter {
modifiers = addModifier(Statement.createModifier(ModifierKind.CONST, tn.range()), modifiers); modifiers = addModifier(Statement.createModifier(ModifierKind.CONST, tn.range()), modifiers);
if (tn.skip(Token.ENUM)) { if (tn.skip(Token.ENUM)) {
statement = this.parseEnum(tn, modifiers ? <Modifier[]>modifiers : createModifiers()); statement = this.parseEnum(tn, modifiers, decorators);
break; break;
} }
// fall through // fall through
case Token.VAR: case Token.VAR:
case Token.LET: case Token.LET:
statement = this.parseVariable(tn, modifiers ? <Modifier[]>modifiers : createModifiers()); statement = this.parseVariable(tn, modifiers, decorators);
decorators = null;
break; break;
case Token.ENUM: case Token.ENUM:
statement = this.parseEnum(tn, modifiers ? <Modifier[]>modifiers : createModifiers()); statement = this.parseEnum(tn, modifiers, decorators);
decorators = null;
break; break;
case Token.FUNCTION: case Token.FUNCTION:
statement = this.parseFunction(tn, modifiers ? <Modifier[]>modifiers : createModifiers(), decorators); statement = this.parseFunction(tn, modifiers, decorators);
decorators = null; decorators = null;
break; break;
@ -150,7 +163,12 @@ export class Parser extends DiagnosticEmitter {
// fall through // fall through
case Token.CLASS: case Token.CLASS:
statement = this.parseClass(tn, modifiers ? <Modifier[]>modifiers : createModifiers(), decorators); statement = this.parseClass(tn, modifiers, decorators);
decorators = null;
break;
case Token.NAMESPACE:
statement = this.parseNamespace(tn, modifiers, decorators);
decorators = null; decorators = null;
break; break;
@ -169,28 +187,25 @@ export class Parser extends DiagnosticEmitter {
default: default:
if (hasModifier(ModifierKind.EXPORT, modifiers)) { if (hasModifier(ModifierKind.EXPORT, modifiers)) {
tn.reset(); tn.reset();
statement = this.parseExport(tn, modifiers ? <Modifier[]>modifiers : createModifiers()); statement = this.parseExport(tn, modifiers); // TODO: why exactly does this have modifiers again?
} else { } else {
if (modifiers) { if (modifiers) {
if (hasModifier(ModifierKind.DECLARE, modifiers)) if (hasModifier(ModifierKind.DECLARE, modifiers))
this.error(DiagnosticCode._0_modifier_cannot_be_used_here, getModifier(ModifierKind.DECLARE, <Modifier[]>modifiers).range, "declare"); // recoverable this.error(DiagnosticCode._0_modifier_cannot_be_used_here, getModifier(ModifierKind.DECLARE, modifiers).range, "declare"); // recoverable
reusableModifiers = modifiers; reusableModifiers = modifiers;
} }
tn.reset(); tn.reset();
if (!isNamespaceMember)
statement = this.parseStatement(tn, true); statement = this.parseStatement(tn, true);
} }
break; break;
} }
if (decorators) if (decorators /* not consumed */)
for (let i: i32 = 0, k: i32 = (<DecoratorStatement[]>decorators).length; i < k; ++i) for (let i: i32 = 0, k: i32 = (<Decorator[]>decorators).length; i < k; ++i)
this.error(DiagnosticCode.Decorators_are_not_valid_here, (<DecoratorStatement[]>decorators)[i].range); this.error(DiagnosticCode.Decorators_are_not_valid_here, (<Decorator[]>decorators)[i].range);
if (!statement)
return; return statement;
statement.parent = source;
source.statements.push(statement);
}
reusableModifiers = null;
} }
nextFile(): string | null { nextFile(): string | null {
@ -318,7 +333,7 @@ export class Parser extends DiagnosticEmitter {
// statements // statements
parseDecorator(tn: Tokenizer): DecoratorStatement | null { parseDecorator(tn: Tokenizer): Decorator | null {
// at '@': Identifier ('.' Identifier)* '(' Arguments // at '@': Identifier ('.' Identifier)* '(' Arguments
const startPos: i32 = tn.tokenPos; const startPos: i32 = tn.tokenPos;
if (tn.skip(Token.IDENTIFIER)) { if (tn.skip(Token.IDENTIFIER)) {
@ -344,24 +359,24 @@ export class Parser extends DiagnosticEmitter {
return null; 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)* ';'? // 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 members: VariableDeclaration[] = new Array();
const isDeclare = hasModifier(ModifierKind.DECLARE, modifiers); const isDeclare = hasModifier(ModifierKind.DECLARE, modifiers);
do { do {
const member: VariableDeclaration | null = this.parseVariableDeclaration(tn, isDeclare, modifiers); const member: VariableDeclaration | null = this.parseVariableDeclaration(tn, isDeclare, modifiers, decorators);
if (!member) if (!member)
return null; return null;
members.push(<VariableDeclaration>member); members.push(<VariableDeclaration>member);
} while (tn.skip(Token.COMMA)); } 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); tn.skip(Token.SEMICOLON);
return ret; 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)? // Identifier (':' Type)? ('=' Expression)?
if (!tn.skip(Token.IDENTIFIER)) { if (!tn.skip(Token.IDENTIFIER)) {
this.error(DiagnosticCode.Identifier_expected, tn.range()); this.error(DiagnosticCode.Identifier_expected, tn.range());
@ -383,12 +398,12 @@ export class Parser extends DiagnosticEmitter {
if (!initializer) if (!initializer)
return null; 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 )*)? '}' ';'? // 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) { if (tn.next() != Token.IDENTIFIER) {
this.error(DiagnosticCode.Identifier_expected, tn.range()); this.error(DiagnosticCode.Identifier_expected, tn.range());
return null; return null;
@ -411,7 +426,7 @@ export class Parser extends DiagnosticEmitter {
return null; 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); tn.skip(Token.SEMICOLON);
return ret; return ret;
} }
@ -528,13 +543,9 @@ export class Parser extends DiagnosticEmitter {
return null; 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* '}' ';'? // at 'function': Identifier ('<' TypeParameters)? '(' Parameters (':' Type)? '{' Statement* '}' ';'?
const startPos: i32 = decorators && (<DecoratorStatement[]>decorators).length const startPos: i32 = modifiers && modifiers.length ? modifiers[0].range.start : tn.tokenPos;
? (<DecoratorStatement[]>decorators)[0].range.start
: modifiers.length
? modifiers[0].range.start
: tn.tokenPos;
if (!tn.skip(Token.IDENTIFIER)) { if (!tn.skip(Token.IDENTIFIER)) {
this.error(DiagnosticCode.Identifier_expected, tn.range(tn.pos)); this.error(DiagnosticCode.Identifier_expected, tn.range(tn.pos));
@ -576,16 +587,16 @@ export class Parser extends DiagnosticEmitter {
} }
} else if (!isDeclare) } else if (!isDeclare)
this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, tn.range(tn.pos)); 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); tn.skip(Token.SEMICOLON);
return ret; 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* '}' // at 'class': Identifier ('<' TypeParameters)? ('extends' Type)? ('implements' Type (',' Type)*)? '{' ClassMember* '}'
const startPos: i32 = decorators && (<DecoratorStatement[]>decorators).length const startPos: i32 = decorators && decorators.length
? (<DecoratorStatement[]>decorators)[0].range.start ? decorators[0].range.start
: modifiers.length : modifiers && modifiers.length
? modifiers[0].range.start ? modifiers[0].range.start
: tn.tokenPos; : tn.tokenPos;
@ -628,7 +639,7 @@ export class Parser extends DiagnosticEmitter {
members.push(<DeclarationStatement>member); members.push(<DeclarationStatement>member);
} while (!tn.skip(Token.CLOSEBRACE)); } 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 } else
this.error(DiagnosticCode._0_expected, tn.range(), "{"); this.error(DiagnosticCode._0_expected, tn.range(), "{");
} else } else
@ -640,13 +651,13 @@ export class Parser extends DiagnosticEmitter {
// ('public' | 'private' | 'protected')? ('static' | 'abstract')? ('get' | 'set')? Identifier ... // ('public' | 'private' | 'protected')? ('static' | 'abstract')? ('get' | 'set')? Identifier ...
const startRange: Range = tn.range(); const startRange: Range = tn.range();
let decorators: DecoratorStatement[] = new Array(); let decorators: Decorator[] = new Array();
while (tn.skip(Token.AT)) { while (tn.skip(Token.AT)) {
const decorator: DecoratorStatement | null = this.parseDecorator(tn); const decorator: Decorator | null = this.parseDecorator(tn);
if (!decorator) if (!decorator)
break; break;
decorators.push(<DecoratorStatement>decorator); decorators.push(<Decorator>decorator);
} }
let modifiers: Modifier[] | null = null; 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 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); tn.skip(Token.SEMICOLON);
return ret; return ret;
@ -731,7 +742,7 @@ export class Parser extends DiagnosticEmitter {
if (!initializer) if (!initializer)
return null; 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); tn.skip(Token.SEMICOLON);
return ret; return ret;
} }
@ -740,9 +751,32 @@ export class Parser extends DiagnosticEmitter {
return null; 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)? ';'? // 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)) { if (tn.skip(Token.OPENBRACE)) {
const members: ExportMember[] = new Array(); const members: ExportMember[] = new Array();
if (!tn.skip(Token.CLOSEBRACE)) { if (!tn.skip(Token.CLOSEBRACE)) {
@ -766,7 +800,7 @@ export class Parser extends DiagnosticEmitter {
return null; 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)) { if (ret.normalizedPath && !this.seenlog.has(<string>ret.normalizedPath)) {
this.backlog.push(<string>ret.normalizedPath); this.backlog.push(<string>ret.normalizedPath);
this.seenlog.add(<string>ret.normalizedPath); this.seenlog.add(<string>ret.normalizedPath);
@ -881,7 +915,7 @@ export class Parser extends DiagnosticEmitter {
return this.parseBreak(tn); return this.parseBreak(tn);
case Token.CONST: 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: case Token.CONTINUE:
return this.parseContinue(tn); return this.parseContinue(tn);
@ -897,7 +931,7 @@ export class Parser extends DiagnosticEmitter {
case Token.LET: case Token.LET:
case Token.VAR: case Token.VAR:
return this.parseVariable(tn, []); return this.parseVariable(tn, null, null);
case Token.OPENBRACE: case Token.OPENBRACE:
return this.parseBlockStatement(tn, topLevel); return this.parseBlockStatement(tn, topLevel);
@ -1007,7 +1041,7 @@ export class Parser extends DiagnosticEmitter {
if (tn.skip(Token.OPENPAREN)) { if (tn.skip(Token.OPENPAREN)) {
let initializer: Statement | null = null; let initializer: Statement | null = null;
if (tn.skip(Token.LET) || tn.skip(Token.CONST) || tn.skip(Token.VAR)) { 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)) { } else if (!tn.skip(Token.SEMICOLON)) {
initializer = this.parseExpressionStatement(tn); initializer = this.parseExpressionStatement(tn);
if (!initializer) if (!initializer)

View File

@ -22,7 +22,7 @@ import {
ClassDeclaration, ClassDeclaration,
DeclarationStatement, DeclarationStatement,
DecoratorStatement, Decorator,
EnumDeclaration, EnumDeclaration,
EnumValueDeclaration, EnumValueDeclaration,
ExportMember, 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) { 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 expression: Expression = decorator.expression;
const args: Expression[] = decorator.arguments; const args: Expression[] = decorator.arguments;
if (expression.kind == NodeKind.IDENTIFIER && args.length <= 1 && (<IdentifierExpression>expression).name == "global") { 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" /> /// <reference path="../assembly.d.ts" />
/** A C-compatible array class. */
declare class CArray<T> { declare class CArray<T> {
[key: number]: T; [key: number]: T;
/** Constructs a new C-Array of the specified capacity. */
constructor(capacity: usize); 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" /> /// <reference path="../assembly.d.ts" />
declare class CString extends CArray<u8> { /** A C-compatible string class. */
constructor(text: string); 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" /> /// <reference path="../../assembly.d.ts" />
/** A C-compatible Array class. */
@global() @global()
@struct()
class CArray<T> { class CArray<T> {
/** Constructs a new C-Array of the specified capacity. */
constructor(capacity: usize) { 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() @inline()
"[]"(index: usize): T { "[]"(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() @inline()
"[]="(index: usize, value: T): T { "[]="(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; return value;
} }
/** Disposes this instance and the memory associated with it. */
dispose(): void { 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" /> /// <reference path="../../assembly.d.ts" />
/** A C-compatible string class. */
@global() @global()
class CString extends CArray<u8> { @struct()
class CString {
/** Constructs a new C-String from a String. */ constructor(string: string) {
constructor(text: string) { const ptr: usize = Heap.allocate(<usize>string.length * 2 + 1);
super(text.length * 2 + 1); let idx: usize = ptr;
let idx: usize = unsafe_cast<this,usize>(this); for (let i: usize = 0, k: usize = <usize>(<string>str).length; i < k; ++i) {
for (let i: usize = 0, k: usize = (<string>str).length; i < k; ++i) { let u: i32 = string.charCodeAt(i);
let u: i32 = text.charCodeAt(i);
if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k) 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) if (u <= 0x7F)
store<u8>(idx++, u as u8); store<u8>(idx++, u as u8);
else if (u <= 0x7FF) { else if (u <= 0x7FF) {
@ -43,5 +42,17 @@ class CString extends CArray<u8> {
} }
} }
store<u8>(idx, 0); 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": [ "files": [
"carray.ts", "carray.ts",
"cstring.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": [ "files": [
"carray.d.ts", "carray.d.ts",
"cstring.d.ts", "cstring.d.ts",
"memory.d.ts" "heap.d.ts"
] ]
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -13,3 +13,8 @@ export const a: i32 = 1;
const b: i32 = 2; const b: i32 = 2;
export { b as renamed_b }; 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))) (type $iii (func (param i32 i32) (result i32)))
(global $export/a i32 (i32.const 1)) (global $export/a i32 (i32.const 1))
(global $export/b i32 (i32.const 2)) (global $export/b i32 (i32.const 2))
(global $HEAP_START i32 (i32.const 4))
(memory $0 1) (memory $0 1)
(data (i32.const 4) "\08\00\00\00")
(export "add" (func $export/add)) (export "add" (func $export/add))
(export "renamed_sub" (func $export/sub)) (export "renamed_sub" (func $export/sub))
(export "a" (global $export/a)) (export "a" (global $export/a))
@ -50,6 +50,7 @@
reinterpret reinterpret
select select
sizeof sizeof
changetype
isNaN isNaN
isFinite isFinite
assert assert

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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