mirror of
https://github.com/fluencelabs/assemblyscript
synced 2025-04-26 15:32:16 +00:00
Progress
This commit is contained in:
parent
f55fc70220
commit
50116acede
113
src/ast.ts
113
src/ast.ts
@ -94,11 +94,16 @@ export enum NodeKind {
|
|||||||
BINARY,
|
BINARY,
|
||||||
CALL,
|
CALL,
|
||||||
ELEMENTACCESS,
|
ELEMENTACCESS,
|
||||||
|
FALSE,
|
||||||
LITERAL,
|
LITERAL,
|
||||||
NEW,
|
NEW,
|
||||||
|
NULL,
|
||||||
PARENTHESIZED,
|
PARENTHESIZED,
|
||||||
PROPERTYACCESS,
|
PROPERTYACCESS,
|
||||||
SELECT,
|
SELECT,
|
||||||
|
SUPER,
|
||||||
|
THIS,
|
||||||
|
TRUE,
|
||||||
UNARYPOSTFIX,
|
UNARYPOSTFIX,
|
||||||
UNARYPREFIX,
|
UNARYPREFIX,
|
||||||
|
|
||||||
@ -163,6 +168,7 @@ export function nodeKindToString(kind: NodeKind): string {
|
|||||||
case NodeKind.EXPORTIMPORT: return "EXPORTIMPORT";
|
case NodeKind.EXPORTIMPORT: return "EXPORTIMPORT";
|
||||||
case NodeKind.EXPRESSION: return "EXPRESSION";
|
case NodeKind.EXPRESSION: return "EXPRESSION";
|
||||||
case NodeKind.INTERFACE: return "INTERFACE";
|
case NodeKind.INTERFACE: return "INTERFACE";
|
||||||
|
case NodeKind.FALSE: return "FALSE";
|
||||||
case NodeKind.FOR: return "FOR";
|
case NodeKind.FOR: return "FOR";
|
||||||
case NodeKind.FUNCTION: return "FUNCTION";
|
case NodeKind.FUNCTION: return "FUNCTION";
|
||||||
case NodeKind.IF: return "IF";
|
case NodeKind.IF: return "IF";
|
||||||
@ -170,10 +176,14 @@ export function nodeKindToString(kind: NodeKind): string {
|
|||||||
case NodeKind.IMPORTDECLARATION: return "IMPORTDECLARATION";
|
case NodeKind.IMPORTDECLARATION: return "IMPORTDECLARATION";
|
||||||
case NodeKind.METHOD: return "METHOD";
|
case NodeKind.METHOD: return "METHOD";
|
||||||
case NodeKind.NAMESPACE: return "NAMESPACE";
|
case NodeKind.NAMESPACE: return "NAMESPACE";
|
||||||
|
case NodeKind.NULL: return "NULL";
|
||||||
case NodeKind.FIELD: return "PROPERTY";
|
case NodeKind.FIELD: return "PROPERTY";
|
||||||
case NodeKind.RETURN: return "RETURN";
|
case NodeKind.RETURN: return "RETURN";
|
||||||
|
case NodeKind.SUPER: return "SUPER";
|
||||||
case NodeKind.SWITCH: return "SWITCH";
|
case NodeKind.SWITCH: return "SWITCH";
|
||||||
|
case NodeKind.THIS: return "THIS";
|
||||||
case NodeKind.THROW: return "THROW";
|
case NodeKind.THROW: return "THROW";
|
||||||
|
case NodeKind.TRUE: return "TRUE";
|
||||||
case NodeKind.TRY: return "TRY";
|
case NodeKind.TRY: return "TRY";
|
||||||
case NodeKind.VARIABLE: return "VARIABLE";
|
case NodeKind.VARIABLE: return "VARIABLE";
|
||||||
case NodeKind.VARIABLEDECLARATION: return "VARIABLEDECLARATION";
|
case NodeKind.VARIABLEDECLARATION: return "VARIABLEDECLARATION";
|
||||||
@ -286,6 +296,12 @@ export abstract class Expression extends Node {
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static createFalse(range: Range): FalseExpression {
|
||||||
|
const expr: FalseExpression = new FalseExpression();
|
||||||
|
expr.range = range;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
static createFloatLiteral(value: f64, range: Range): FloatLiteralExpression {
|
static createFloatLiteral(value: f64, range: Range): FloatLiteralExpression {
|
||||||
const expr: FloatLiteralExpression = new FloatLiteralExpression();
|
const expr: FloatLiteralExpression = new FloatLiteralExpression();
|
||||||
expr.range = range;
|
expr.range = range;
|
||||||
@ -310,6 +326,12 @@ export abstract class Expression extends Node {
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static createNull(range: Range): NullExpression {
|
||||||
|
const expr: NullExpression = new NullExpression();
|
||||||
|
expr.range = range;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
static createParenthesized(expression: Expression, range: Range): ParenthesizedExpression {
|
static createParenthesized(expression: Expression, range: Range): ParenthesizedExpression {
|
||||||
const expr: ParenthesizedExpression = new ParenthesizedExpression();
|
const expr: ParenthesizedExpression = new ParenthesizedExpression();
|
||||||
expr.range = range;
|
expr.range = range;
|
||||||
@ -348,6 +370,24 @@ export abstract class Expression extends Node {
|
|||||||
return expr;
|
return expr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static createSuper(range: Range): SuperExpression {
|
||||||
|
const expr: SuperExpression = new SuperExpression();
|
||||||
|
expr.range = range;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static createThis(range: Range): ThisExpression {
|
||||||
|
const expr: ThisExpression = new ThisExpression();
|
||||||
|
expr.range = range;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static createTrue(range: Range): TrueExpression {
|
||||||
|
const expr: TrueExpression = new TrueExpression();
|
||||||
|
expr.range = range;
|
||||||
|
return expr;
|
||||||
|
}
|
||||||
|
|
||||||
static createUnaryPostfix(operator: Token, expression: Expression, range: Range): UnaryPostfixExpression {
|
static createUnaryPostfix(operator: Token, expression: Expression, range: Range): UnaryPostfixExpression {
|
||||||
const expr: UnaryPostfixExpression = new UnaryPostfixExpression();
|
const expr: UnaryPostfixExpression = new UnaryPostfixExpression();
|
||||||
expr.range = range;
|
expr.range = range;
|
||||||
@ -614,6 +654,11 @@ export class NewExpression extends CallExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class NullExpression extends IdentifierExpression {
|
||||||
|
kind = NodeKind.NULL;
|
||||||
|
name = "null";
|
||||||
|
}
|
||||||
|
|
||||||
export class ParenthesizedExpression extends Expression {
|
export class ParenthesizedExpression extends Expression {
|
||||||
|
|
||||||
kind = NodeKind.PARENTHESIZED;
|
kind = NodeKind.PARENTHESIZED;
|
||||||
@ -711,6 +756,26 @@ export class StringLiteralExpression extends LiteralExpression {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SuperExpression extends IdentifierExpression {
|
||||||
|
kind = NodeKind.SUPER;
|
||||||
|
name = "super";
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ThisExpression extends IdentifierExpression {
|
||||||
|
kind = NodeKind.THIS;
|
||||||
|
name = "this";
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TrueExpression extends IdentifierExpression {
|
||||||
|
kind = NodeKind.TRUE;
|
||||||
|
name = "true";
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FalseExpression extends IdentifierExpression {
|
||||||
|
kind = NodeKind.FALSE;
|
||||||
|
name = "false";
|
||||||
|
}
|
||||||
|
|
||||||
export abstract class UnaryExpression extends Expression {
|
export abstract class UnaryExpression extends Expression {
|
||||||
operator: Token;
|
operator: Token;
|
||||||
expression: Expression;
|
expression: Expression;
|
||||||
@ -798,7 +863,7 @@ export abstract class Statement extends Node {
|
|||||||
static createBlock(statements: Statement[], range: Range): BlockStatement {
|
static createBlock(statements: Statement[], range: Range): BlockStatement {
|
||||||
const stmt: BlockStatement = new BlockStatement();
|
const stmt: BlockStatement = new BlockStatement();
|
||||||
stmt.range = range;
|
stmt.range = range;
|
||||||
for (let i: i32 = 0, k = (stmt.statements = statements).length; i < k; ++i) statements[i].parent = stmt;
|
for (let i: i32 = 0, k: i32 = (stmt.statements = statements).length; i < k; ++i) statements[i].parent = stmt;
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1055,13 +1120,14 @@ export abstract class Statement extends Node {
|
|||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static createTry(statements: Statement[], catchVariable: VariableDeclaration, catchStatements: Statement[], range: Range): TryStatement {
|
static createTry(statements: Statement[], catchVariable: IdentifierExpression | null, catchStatements: Statement[] | null, finallyStatements: Statement[] | null, range: Range): TryStatement {
|
||||||
const stmt: TryStatement = new TryStatement();
|
const stmt: TryStatement = new TryStatement();
|
||||||
stmt.range = range;
|
stmt.range = range;
|
||||||
let i: i32, k: i32;
|
let i: i32, k: i32;
|
||||||
for (i = 0, k = (stmt.statements = statements).length; i < k; ++i) statements[i].parent = stmt;
|
for (i = 0, k = (stmt.statements = statements).length; i < k; ++i) statements[i].parent = stmt;
|
||||||
(stmt.catchVariable = catchVariable).parent = stmt;
|
if (stmt.catchVariable = catchVariable) (<IdentifierExpression>catchVariable).parent = stmt;
|
||||||
for (i = 0, k = (stmt.catchStatements = catchStatements).length; i < k; ++i) catchStatements[i].parent = stmt;
|
if (stmt.catchStatements = catchStatements) for (i = 0, k = (<Statement[]>catchStatements).length; i < k; ++i) (<Statement[]>catchStatements)[i].parent = stmt;
|
||||||
|
if (stmt.finallyStatements = finallyStatements) for (i = 0, k = (<Statement[]>finallyStatements).length; i < k; ++i) (<Statement[]>finallyStatements)[i].parent = stmt;
|
||||||
return stmt;
|
return stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1117,7 +1183,7 @@ export class Source extends Node {
|
|||||||
get isDeclaration(): bool { return !this.isEntry && this.path.endsWith(".d.ts"); }
|
get isDeclaration(): bool { return !this.isEntry && this.path.endsWith(".d.ts"); }
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
for (let i: i32 = 0, k = this.statements.length; i < k; ++i) {
|
for (let i: i32 = 0, k: i32 = this.statements.length; i < k; ++i) {
|
||||||
const statement: Statement = this.statements[i];
|
const statement: Statement = this.statements[i];
|
||||||
statement.serialize(sb);
|
statement.serialize(sb);
|
||||||
const last: string = sb[sb.length - 1];
|
const last: string = sb[sb.length - 1];
|
||||||
@ -1142,7 +1208,7 @@ export class BlockStatement extends Statement {
|
|||||||
sb.push("{\n");
|
sb.push("{\n");
|
||||||
for (let i: i32 = 0, k: i32 = this.statements.length; i < k; ++i) {
|
for (let i: i32 = 0, k: i32 = this.statements.length; i < k; ++i) {
|
||||||
this.statements[i].serialize(sb);
|
this.statements[i].serialize(sb);
|
||||||
if (builderEndsWith(CharCode.CLOSEBRACE, sb))
|
if (builderEndsWith(sb, CharCode.CLOSEBRACE))
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
else
|
else
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
@ -1211,7 +1277,7 @@ export class ClassDeclaration extends DeclarationStatement {
|
|||||||
sb.push(" {\n");
|
sb.push(" {\n");
|
||||||
for (i = 0, k = this.members.length; i < k; ++i) {
|
for (i = 0, k = this.members.length; i < k; ++i) {
|
||||||
this.members[i].serialize(sb);
|
this.members[i].serialize(sb);
|
||||||
if (builderEndsWith(CharCode.CLOSEBRACE, sb))
|
if (builderEndsWith(sb, CharCode.CLOSEBRACE))
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
else
|
else
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
@ -1493,7 +1559,7 @@ export class FunctionDeclaration extends DeclarationStatement {
|
|||||||
for (i = 0, k = (<Statement[]>this.statements).length; i < k; ++i) {
|
for (i = 0, k = (<Statement[]>this.statements).length; i < k; ++i) {
|
||||||
const statement: Statement = (<Statement[]>this.statements)[i];
|
const statement: Statement = (<Statement[]>this.statements)[i];
|
||||||
statement.serialize(sb);
|
statement.serialize(sb);
|
||||||
if (builderEndsWith(CharCode.CLOSEBRACE, sb))
|
if (builderEndsWith(sb, CharCode.CLOSEBRACE))
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
else
|
else
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
@ -1592,7 +1658,7 @@ export class InterfaceDeclaration extends DeclarationStatement {
|
|||||||
sb.push(" {\n");
|
sb.push(" {\n");
|
||||||
for (i = 0, k = this.members.length; i < k; ++i) {
|
for (i = 0, k = this.members.length; i < k; ++i) {
|
||||||
this.members[i].serialize(sb);
|
this.members[i].serialize(sb);
|
||||||
if (builderEndsWith(CharCode.CLOSEBRACE, sb))
|
if (builderEndsWith(sb, CharCode.CLOSEBRACE))
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
else
|
else
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
@ -1623,7 +1689,7 @@ export class NamespaceDeclaration extends DeclarationStatement {
|
|||||||
|
|
||||||
kind = NodeKind.NAMESPACE;
|
kind = NodeKind.NAMESPACE;
|
||||||
modifiers: Modifier[];
|
modifiers: Modifier[];
|
||||||
members: DeclarationStatement[];
|
members: Statement[];
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
let i: i32, k: i32;
|
let i: i32, k: i32;
|
||||||
@ -1636,7 +1702,7 @@ export class NamespaceDeclaration extends DeclarationStatement {
|
|||||||
sb.push(" {\n");
|
sb.push(" {\n");
|
||||||
for (i = 0, k = this.members.length; i < k; ++i) {
|
for (i = 0, k = this.members.length; i < k; ++i) {
|
||||||
this.members[i].serialize(sb);
|
this.members[i].serialize(sb);
|
||||||
if (builderEndsWith(CharCode.CLOSEBRACE, sb))
|
if (builderEndsWith(sb, CharCode.CLOSEBRACE))
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
else
|
else
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
@ -1720,7 +1786,7 @@ export class SwitchCase extends Node {
|
|||||||
if (i > 0)
|
if (i > 0)
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
this.statements[i].serialize(sb);
|
this.statements[i].serialize(sb);
|
||||||
if (builderEndsWith(CharCode.CLOSEBRACE, sb))
|
if (builderEndsWith(sb, CharCode.CLOSEBRACE))
|
||||||
sb.push("\n");
|
sb.push("\n");
|
||||||
else
|
else
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
@ -1761,8 +1827,9 @@ export class TryStatement extends Statement {
|
|||||||
|
|
||||||
kind = NodeKind.TRY;
|
kind = NodeKind.TRY;
|
||||||
statements: Statement[];
|
statements: Statement[];
|
||||||
catchVariable: VariableDeclaration;
|
catchVariable: IdentifierExpression | null;
|
||||||
catchStatements: Statement[];
|
catchStatements: Statement[] | null;
|
||||||
|
finallyStatements: Statement[] | null;
|
||||||
|
|
||||||
serialize(sb: string[]): void {
|
serialize(sb: string[]): void {
|
||||||
sb.push("try {\n");
|
sb.push("try {\n");
|
||||||
@ -1771,13 +1838,23 @@ export class TryStatement extends Statement {
|
|||||||
this.statements[i].serialize(sb);
|
this.statements[i].serialize(sb);
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
}
|
}
|
||||||
|
if (this.catchVariable) {
|
||||||
sb.push("} catch (");
|
sb.push("} catch (");
|
||||||
this.catchVariable.serialize(sb);
|
(<IdentifierExpression>this.catchVariable).serialize(sb);
|
||||||
sb.push(") {\n");
|
sb.push(") {\n");
|
||||||
for (i = 0, k = this.catchStatements.length; i < k; ++i) {
|
if (this.catchStatements)
|
||||||
this.catchStatements[i].serialize(sb);
|
for (i = 0, k = (<Statement[]>this.catchStatements).length; i < k; ++i) {
|
||||||
|
(<Statement[]>this.catchStatements)[i].serialize(sb);
|
||||||
sb.push(";\n");
|
sb.push(";\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (this.finallyStatements) {
|
||||||
|
sb.push("} finally {\n");
|
||||||
|
for (i = 0, k = (<Statement[]>this.finallyStatements).length; i < k; ++i) {
|
||||||
|
(<Statement[]>this.finallyStatements)[i].serialize(sb);
|
||||||
|
sb.push(";\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
sb.push("}");
|
sb.push("}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1857,7 +1934,7 @@ export function serialize(node: Node, indent: i32 = 0): string {
|
|||||||
return sb.join("");
|
return sb.join("");
|
||||||
}
|
}
|
||||||
|
|
||||||
function builderEndsWith(code: CharCode, sb: string[]): bool {
|
function builderEndsWith(sb: string[], code: CharCode): bool {
|
||||||
if (sb.length) {
|
if (sb.length) {
|
||||||
const last: string = sb[sb.length - 1];
|
const last: string = sb[sb.length - 1];
|
||||||
return last.length ? last.charCodeAt(last.length - 1) == code : false;
|
return last.length ? last.charCodeAt(last.length - 1) == code : false;
|
||||||
|
@ -172,11 +172,15 @@ export class Module {
|
|||||||
|
|
||||||
ref: BinaryenModuleRef;
|
ref: BinaryenModuleRef;
|
||||||
lit: BinaryenLiteral;
|
lit: BinaryenLiteral;
|
||||||
|
noEmit: bool;
|
||||||
|
|
||||||
|
static MAX_MEMORY_WASM32: BinaryenIndex = 0xffff;
|
||||||
|
|
||||||
static create(): Module {
|
static create(): Module {
|
||||||
const module: Module = new Module();
|
const module: Module = new Module();
|
||||||
module.ref = _BinaryenModuleCreate();
|
module.ref = _BinaryenModuleCreate();
|
||||||
module.lit = _malloc(16);
|
module.lit = _malloc(16);
|
||||||
|
module.noEmit = false;
|
||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,17 +190,27 @@ export class Module {
|
|||||||
const module: Module = new Module();
|
const module: Module = new Module();
|
||||||
module.ref = _BinaryenModuleRead(cArr, buffer.length);
|
module.ref = _BinaryenModuleRead(cArr, buffer.length);
|
||||||
module.lit = _malloc(16);
|
module.lit = _malloc(16);
|
||||||
|
module.noEmit = false;
|
||||||
return module;
|
return module;
|
||||||
} finally {
|
} finally {
|
||||||
_free(cArr);
|
_free(cArr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static MAX_MEMORY_WASM32: BinaryenIndex = 0xffff;
|
static createStub(): Module {
|
||||||
|
const module: Module = new Module();
|
||||||
|
module.ref = 0;
|
||||||
|
module.lit = 0;
|
||||||
|
module.noEmit = true;
|
||||||
|
return module;
|
||||||
|
}
|
||||||
|
|
||||||
|
private constructor() { }
|
||||||
|
|
||||||
// types
|
// types
|
||||||
|
|
||||||
addFunctionType(name: string, result: Type, paramTypes: Type[]): BinaryenFunctionRef {
|
addFunctionType(name: string, result: Type, paramTypes: Type[]): BinaryenFunctionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const cStr: CString = allocString(name);
|
const cStr: CString = allocString(name);
|
||||||
const cArr: CArray<i32> = allocI32Array(paramTypes);
|
const cArr: CArray<i32> = allocI32Array(paramTypes);
|
||||||
try {
|
try {
|
||||||
@ -208,6 +222,7 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getFunctionTypeBySignature(result: Type, paramTypes: Type[]): BinaryenFunctionTypeRef {
|
getFunctionTypeBySignature(result: Type, paramTypes: Type[]): BinaryenFunctionTypeRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const cArr: CArray<i32> = allocI32Array(paramTypes);
|
const cArr: CArray<i32> = allocI32Array(paramTypes);
|
||||||
try {
|
try {
|
||||||
return _BinaryenGetFunctionTypeBySignature(this.ref, result, cArr, paramTypes.length);
|
return _BinaryenGetFunctionTypeBySignature(this.ref, result, cArr, paramTypes.length);
|
||||||
@ -219,34 +234,41 @@ export class Module {
|
|||||||
// expressions
|
// expressions
|
||||||
|
|
||||||
createI32(value: i32): BinaryenExpressionRef {
|
createI32(value: i32): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
_BinaryenLiteralInt32(this.lit, value);
|
_BinaryenLiteralInt32(this.lit, value);
|
||||||
return _BinaryenConst(this.ref, this.lit);
|
return _BinaryenConst(this.ref, this.lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
createI64(lo: i32, hi: i32): BinaryenExpressionRef {
|
createI64(lo: i32, hi: i32): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
_BinaryenLiteralInt64(this.lit, lo, hi);
|
_BinaryenLiteralInt64(this.lit, lo, hi);
|
||||||
return _BinaryenConst(this.ref, this.lit);
|
return _BinaryenConst(this.ref, this.lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
createF32(value: f32): BinaryenExpressionRef {
|
createF32(value: f32): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
_BinaryenLiteralFloat32(this.lit, value);
|
_BinaryenLiteralFloat32(this.lit, value);
|
||||||
return _BinaryenConst(this.ref, this.lit);
|
return _BinaryenConst(this.ref, this.lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
createF64(value: f64): BinaryenExpressionRef {
|
createF64(value: f64): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
_BinaryenLiteralFloat64(this.lit, value);
|
_BinaryenLiteralFloat64(this.lit, value);
|
||||||
return _BinaryenConst(this.ref, this.lit);
|
return _BinaryenConst(this.ref, this.lit);
|
||||||
}
|
}
|
||||||
|
|
||||||
createUnary(op: UnaryOp, expr: BinaryenExpressionRef): BinaryenExpressionRef {
|
createUnary(op: UnaryOp, expr: BinaryenExpressionRef): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
return _BinaryenUnary(this.ref, op, expr);
|
return _BinaryenUnary(this.ref, op, expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
createBinary(op: BinaryOp, left: BinaryenExpressionRef, right: BinaryenExpressionRef): BinaryenExpressionRef {
|
createBinary(op: BinaryOp, left: BinaryenExpressionRef, right: BinaryenExpressionRef): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
return _BinaryenBinary(this.ref, op, left, right);
|
return _BinaryenBinary(this.ref, op, left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
createHost(op: HostOp, name: string | null = null, operands: BinaryenExpressionRef[] | null = null): BinaryenExpressionRef {
|
createHost(op: HostOp, name: string | null = null, operands: BinaryenExpressionRef[] | null = null): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const cStr: CString = allocString(name);
|
const cStr: CString = allocString(name);
|
||||||
const cArr: CArray<i32> = allocI32Array(operands);
|
const cArr: CArray<i32> = allocI32Array(operands);
|
||||||
try {
|
try {
|
||||||
@ -258,14 +280,17 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createGetLocal(index: i32, type: Type): BinaryenExpressionRef {
|
createGetLocal(index: i32, type: Type): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
return _BinaryenGetLocal(this.ref, index, type);
|
return _BinaryenGetLocal(this.ref, index, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
createTeeLocal(index: i32, value: BinaryenExpressionRef): BinaryenExpressionRef {
|
createTeeLocal(index: i32, value: BinaryenExpressionRef): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
return _BinaryenTeeLocal(this.ref, index, value);
|
return _BinaryenTeeLocal(this.ref, index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
createGetGlobal(name: string, type: Type): BinaryenExpressionRef {
|
createGetGlobal(name: string, type: Type): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const cStr: CString = allocString(name);
|
const cStr: CString = allocString(name);
|
||||||
try {
|
try {
|
||||||
return _BinaryenGetGlobal(this.ref, cStr, type);
|
return _BinaryenGetGlobal(this.ref, cStr, type);
|
||||||
@ -274,21 +299,15 @@ export class Module {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
createTeeGlobal(name: string, value: BinaryenExpressionRef, type: Type): BinaryenExpressionRef {
|
|
||||||
// emulated, lives here for simplicity reasons
|
|
||||||
return this.createBlock(null, [
|
|
||||||
this.createSetGlobal(name, value),
|
|
||||||
this.createGetGlobal(name, type)
|
|
||||||
], type);
|
|
||||||
}
|
|
||||||
|
|
||||||
// statements
|
// statements
|
||||||
|
|
||||||
createSetLocal(index: i32, value: BinaryenExpressionRef): BinaryenExpressionRef {
|
createSetLocal(index: i32, value: BinaryenExpressionRef): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
return _BinaryenSetLocal(this.ref, index, value);
|
return _BinaryenSetLocal(this.ref, index, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
createSetGlobal(name: string, value: BinaryenExpressionRef): BinaryenExpressionRef {
|
createSetGlobal(name: string, value: BinaryenExpressionRef): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const cStr: CString = allocString(name);
|
const cStr: CString = allocString(name);
|
||||||
try {
|
try {
|
||||||
return _BinaryenSetGlobal(this.ref, cStr, value);
|
return _BinaryenSetGlobal(this.ref, cStr, value);
|
||||||
@ -298,6 +317,7 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createBlock(label: string | null, children: BinaryenExpressionRef[], type: Type = Type.Undefined): BinaryenExpressionRef {
|
createBlock(label: string | null, children: BinaryenExpressionRef[], type: Type = Type.Undefined): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const cStr: CString = allocString(label);
|
const cStr: CString = allocString(label);
|
||||||
const cArr: CArray<i32> = allocI32Array(children);
|
const cArr: CArray<i32> = allocI32Array(children);
|
||||||
try {
|
try {
|
||||||
@ -309,6 +329,7 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createBreak(label: string | null, condition: BinaryenExpressionRef = 0, value: BinaryenExpressionRef = 0): BinaryenExpressionRef {
|
createBreak(label: string | null, condition: BinaryenExpressionRef = 0, value: BinaryenExpressionRef = 0): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const cStr: CString = allocString(label);
|
const cStr: CString = allocString(label);
|
||||||
try {
|
try {
|
||||||
return _BinaryenBreak(this.ref, cStr, condition, value);
|
return _BinaryenBreak(this.ref, cStr, condition, value);
|
||||||
@ -318,10 +339,12 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createDrop(expression: BinaryenExpressionRef): BinaryenExpressionRef {
|
createDrop(expression: BinaryenExpressionRef): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
return _BinaryenDrop(this.ref, expression);
|
return _BinaryenDrop(this.ref, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
createLoop(label: string | null, body: BinaryenExpressionRef): BinaryenExpressionRef {
|
createLoop(label: string | null, body: BinaryenExpressionRef): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const cStr: CString = allocString(label);
|
const cStr: CString = allocString(label);
|
||||||
try {
|
try {
|
||||||
return _BinaryenLoop(this.ref, cStr, body);
|
return _BinaryenLoop(this.ref, cStr, body);
|
||||||
@ -331,22 +354,27 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createIf(condition: BinaryenExpressionRef, ifTrue: BinaryenExpressionRef, ifFalse: BinaryenExpressionRef = 0): BinaryenExpressionRef {
|
createIf(condition: BinaryenExpressionRef, ifTrue: BinaryenExpressionRef, ifFalse: BinaryenExpressionRef = 0): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
return _BinaryenIf(this.ref, condition, ifTrue, ifFalse);
|
return _BinaryenIf(this.ref, condition, ifTrue, ifFalse);
|
||||||
}
|
}
|
||||||
|
|
||||||
createNop(): BinaryenExpressionRef {
|
createNop(): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
return _BinaryenNop(this.ref);
|
return _BinaryenNop(this.ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
createReturn(expression: BinaryenExpressionRef = 0): BinaryenExpressionRef {
|
createReturn(expression: BinaryenExpressionRef = 0): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
return _BinaryenReturn(this.ref, expression);
|
return _BinaryenReturn(this.ref, expression);
|
||||||
}
|
}
|
||||||
|
|
||||||
createSelect(condition: BinaryenExpressionRef, ifTrue: BinaryenExpressionRef, ifFalse: BinaryenExpressionRef): BinaryenExpressionRef {
|
createSelect(condition: BinaryenExpressionRef, ifTrue: BinaryenExpressionRef, ifFalse: BinaryenExpressionRef): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
return _BinaryenSelect(this.ref, condition, ifTrue, ifFalse);
|
return _BinaryenSelect(this.ref, condition, ifTrue, ifFalse);
|
||||||
}
|
}
|
||||||
|
|
||||||
createSwitch(names: string[], defaultName: string | null, condition: BinaryenExpressionRef, value: BinaryenExpressionRef = 0): BinaryenExpressionRef {
|
createSwitch(names: string[], defaultName: string | null, condition: BinaryenExpressionRef, value: BinaryenExpressionRef = 0): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const strs: CString[] = new Array(names.length);
|
const strs: CString[] = new Array(names.length);
|
||||||
let i: i32, k: i32 = names.length;
|
let i: i32, k: i32 = names.length;
|
||||||
for (i = 0; i < k; ++i) strs[i] = allocString(names[i]);
|
for (i = 0; i < k; ++i) strs[i] = allocString(names[i]);
|
||||||
@ -362,6 +390,7 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createCall(target: BinaryenFunctionRef, operands: BinaryenExpressionRef[], returnType: Type): BinaryenExpressionRef {
|
createCall(target: BinaryenFunctionRef, operands: BinaryenExpressionRef[], returnType: Type): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const cArr: CArray<i32> = allocI32Array(operands);
|
const cArr: CArray<i32> = allocI32Array(operands);
|
||||||
try {
|
try {
|
||||||
return _BinaryenCall(this.ref, target, cArr, operands.length, returnType);
|
return _BinaryenCall(this.ref, target, cArr, operands.length, returnType);
|
||||||
@ -371,6 +400,7 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createCallImport(target: BinaryenImportRef, operands: BinaryenExpressionRef[], returnType: Type): BinaryenExpressionRef {
|
createCallImport(target: BinaryenImportRef, operands: BinaryenExpressionRef[], returnType: Type): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const cArr: CArray<i32> = allocI32Array(operands);
|
const cArr: CArray<i32> = allocI32Array(operands);
|
||||||
try {
|
try {
|
||||||
return _BinaryenCallImport(this.ref, target, cArr, operands.length, returnType);
|
return _BinaryenCallImport(this.ref, target, cArr, operands.length, returnType);
|
||||||
@ -380,12 +410,14 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createUnreachable(): BinaryenExpressionRef {
|
createUnreachable(): BinaryenExpressionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
return _BinaryenUnreachable(this.ref);
|
return _BinaryenUnreachable(this.ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
// meta
|
// meta
|
||||||
|
|
||||||
addGlobal(name: string, type: Type, mutable: bool, initializer: BinaryenExpressionRef): BinaryenImportRef {
|
addGlobal(name: string, type: Type, mutable: bool, initializer: BinaryenExpressionRef): BinaryenImportRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const cStr: CString = allocString(name);
|
const cStr: CString = allocString(name);
|
||||||
try {
|
try {
|
||||||
return _BinaryenAddGlobal(this.ref, cStr, type, mutable ? 1 : 0, initializer);
|
return _BinaryenAddGlobal(this.ref, cStr, type, mutable ? 1 : 0, initializer);
|
||||||
@ -395,6 +427,7 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addFunction(name: string, type: BinaryenFunctionTypeRef, varTypes: Type[], body: BinaryenExpressionRef): BinaryenFunctionRef {
|
addFunction(name: string, type: BinaryenFunctionTypeRef, varTypes: Type[], body: BinaryenExpressionRef): BinaryenFunctionRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const cStr: CString = allocString(name);
|
const cStr: CString = allocString(name);
|
||||||
const cArr: CArray<i32> = allocI32Array(varTypes);
|
const cArr: CArray<i32> = allocI32Array(varTypes);
|
||||||
try {
|
try {
|
||||||
@ -406,6 +439,7 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addExport(internalName: string, externalName: string): BinaryenExportRef {
|
addExport(internalName: string, externalName: string): BinaryenExportRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const cStr1: CString = allocString(internalName);
|
const cStr1: CString = allocString(internalName);
|
||||||
const cStr2: CString = allocString(externalName);
|
const cStr2: CString = allocString(externalName);
|
||||||
try {
|
try {
|
||||||
@ -417,6 +451,7 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
removeExport(externalName: string): void {
|
removeExport(externalName: string): void {
|
||||||
|
if (this.noEmit) return;
|
||||||
const cStr = allocString(externalName);
|
const cStr = allocString(externalName);
|
||||||
try {
|
try {
|
||||||
_BinaryenRemoveExport(this.ref, cStr);
|
_BinaryenRemoveExport(this.ref, cStr);
|
||||||
@ -426,6 +461,7 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addImport(internalName: string, externalModuleName: string, externalBaseName: string, type: BinaryenFunctionTypeRef): BinaryenImportRef {
|
addImport(internalName: string, externalModuleName: string, externalBaseName: string, type: BinaryenFunctionTypeRef): BinaryenImportRef {
|
||||||
|
if (this.noEmit) return 0;
|
||||||
const cStr1: CString = allocString(internalName);
|
const cStr1: CString = allocString(internalName);
|
||||||
const cStr2: CString = allocString(externalModuleName);
|
const cStr2: CString = allocString(externalModuleName);
|
||||||
const cStr3: CString = allocString(externalBaseName);
|
const cStr3: CString = allocString(externalBaseName);
|
||||||
@ -439,6 +475,7 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
removeImport(internalName: string): void {
|
removeImport(internalName: string): void {
|
||||||
|
if (this.noEmit) return;
|
||||||
const cStr: CString = allocString(internalName);
|
const cStr: CString = allocString(internalName);
|
||||||
try {
|
try {
|
||||||
_BinaryenRemoveImport(this.ref, cStr);
|
_BinaryenRemoveImport(this.ref, cStr);
|
||||||
@ -448,6 +485,7 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setMemory(initial: BinaryenIndex, maximum: BinaryenIndex, segments: MemorySegment[], target: Target, exportName: string | null = null): void {
|
setMemory(initial: BinaryenIndex, maximum: BinaryenIndex, segments: MemorySegment[], target: Target, exportName: string | null = null): void {
|
||||||
|
if (this.noEmit) return;
|
||||||
const cStr: CString = allocString(exportName);
|
const cStr: CString = allocString(exportName);
|
||||||
let i: i32, k: i32 = segments.length;
|
let i: i32, k: i32 = segments.length;
|
||||||
const segs: CArray<u8>[] = new Array(k);
|
const segs: CArray<u8>[] = new Array(k);
|
||||||
@ -477,18 +515,22 @@ export class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setStart(func: BinaryenFunctionRef): void {
|
setStart(func: BinaryenFunctionRef): void {
|
||||||
|
if (this.noEmit) return;
|
||||||
_BinaryenSetStart(this.ref, func);
|
_BinaryenSetStart(this.ref, func);
|
||||||
}
|
}
|
||||||
|
|
||||||
optimize(): void {
|
optimize(): void {
|
||||||
|
if (this.noEmit) return;
|
||||||
_BinaryenModuleOptimize(this.ref);
|
_BinaryenModuleOptimize(this.ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
validate(): bool {
|
validate(): bool {
|
||||||
|
if (this.noEmit) return false;
|
||||||
return _BinaryenModuleValidate(this.ref) == 1;
|
return _BinaryenModuleValidate(this.ref) == 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
|
if (!this.ref) return; // sic
|
||||||
_BinaryenModuleDispose(this.ref);
|
_BinaryenModuleDispose(this.ref);
|
||||||
_free(this.lit);
|
_free(this.lit);
|
||||||
}
|
}
|
||||||
@ -547,7 +589,7 @@ function allocString(str: string | null): CString {
|
|||||||
if (!str) return 0;
|
if (!str) return 0;
|
||||||
const ptr: usize = _malloc(stringLengthUTF8((<string>str)) + 1);
|
const ptr: usize = _malloc(stringLengthUTF8((<string>str)) + 1);
|
||||||
let idx: usize = ptr;
|
let idx: usize = ptr;
|
||||||
for (let i: i32 = 0, k = (<string>str).length; i < k; ++i) {
|
for (let i: i32 = 0, k: i32 = (<string>str).length; i < k; ++i) {
|
||||||
let u: i32 = (<string>str).charCodeAt(i);
|
let u: i32 = (<string>str).charCodeAt(i);
|
||||||
if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k)
|
if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k)
|
||||||
u = 0x10000 + ((u & 0x3FF) << 10) | ((<string>str).charCodeAt(++i) & 0x3FF);
|
u = 0x10000 + ((u & 0x3FF) << 10) | ((<string>str).charCodeAt(++i) & 0x3FF);
|
||||||
|
472
src/compiler.ts
472
src/compiler.ts
@ -6,8 +6,10 @@ import { CharCode, I64, U64, normalizePath, sb } from "./util";
|
|||||||
import { Token } from "./tokenizer";
|
import { Token } from "./tokenizer";
|
||||||
import {
|
import {
|
||||||
|
|
||||||
|
Node,
|
||||||
NodeKind,
|
NodeKind,
|
||||||
TypeNode,
|
TypeNode,
|
||||||
|
TypeParameter,
|
||||||
Source,
|
Source,
|
||||||
|
|
||||||
// statements
|
// statements
|
||||||
@ -65,8 +67,10 @@ import {
|
|||||||
|
|
||||||
ClassType,
|
ClassType,
|
||||||
FunctionType,
|
FunctionType,
|
||||||
|
LocalType,
|
||||||
Type,
|
Type,
|
||||||
TypeKind
|
TypeKind,
|
||||||
|
typeArgumentsToString
|
||||||
|
|
||||||
} from "./types";
|
} from "./types";
|
||||||
|
|
||||||
@ -80,13 +84,15 @@ export class Options {
|
|||||||
noEmit: bool = false;
|
noEmit: bool = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const VOID: BinaryenExpressionRef = 0;
|
||||||
|
|
||||||
export class Compiler extends DiagnosticEmitter {
|
export class Compiler extends DiagnosticEmitter {
|
||||||
|
|
||||||
program: Program;
|
program: Program;
|
||||||
options: Options;
|
options: Options;
|
||||||
module: Module;
|
module: Module;
|
||||||
|
|
||||||
startFunction: FunctionType = new FunctionType(Type.void, new Array());
|
startFunction: FunctionType = new FunctionType([], [], Type.void);
|
||||||
startFunctionBody: BinaryenExpressionRef[] = new Array();
|
startFunctionBody: BinaryenExpressionRef[] = new Array();
|
||||||
|
|
||||||
currentType: Type = Type.void;
|
currentType: Type = Type.void;
|
||||||
@ -99,7 +105,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
classes: Map<string,ClassType> = new Map();
|
classes: Map<string,ClassType> = new Map();
|
||||||
enums: Set<string> = new Set();
|
enums: Set<string> = new Set();
|
||||||
functions: Map<string,FunctionType> = new Map();
|
functions: Map<string,FunctionType> = new Map();
|
||||||
globals: Set<string> = new Set();
|
globals: Map<string,Type> = new Map();
|
||||||
|
|
||||||
static compile(program: Program, options: Options | null = null): Module {
|
static compile(program: Program, options: Options | null = null): Module {
|
||||||
const compiler: Compiler = new Compiler(program, options);
|
const compiler: Compiler = new Compiler(program, options);
|
||||||
@ -110,7 +116,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
super(program.diagnostics);
|
super(program.diagnostics);
|
||||||
this.program = program;
|
this.program = program;
|
||||||
this.options = options ? options : new Options();
|
this.options = options ? options : new Options();
|
||||||
this.module = Module.create();
|
this.module = this.options.noEmit ? Module.createStub() : Module.create();
|
||||||
|
// noEmit performs compilation as usual but all binaryen methods are nops instead
|
||||||
}
|
}
|
||||||
|
|
||||||
compile(): Module {
|
compile(): Module {
|
||||||
@ -121,7 +128,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
// start by compiling entry file exports
|
// start by compiling entry file exports
|
||||||
const entrySource: Source = program.sources[0];
|
const entrySource: Source = program.sources[0];
|
||||||
for (let i: i32 = 0, k = entrySource.statements.length; i < k; ++i) {
|
for (let i: i32 = 0, k: i32 = entrySource.statements.length; i < k; ++i) {
|
||||||
const statement: Statement = entrySource.statements[i];
|
const statement: Statement = entrySource.statements[i];
|
||||||
switch (statement.kind) {
|
switch (statement.kind) {
|
||||||
|
|
||||||
@ -177,7 +184,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
if (!typeRef)
|
if (!typeRef)
|
||||||
typeRef = this.module.addFunctionType("v", BinaryenType.None, []);
|
typeRef = this.module.addFunctionType("v", BinaryenType.None, []);
|
||||||
this.module.setStart(
|
this.module.setStart(
|
||||||
this.module.addFunction(".start", typeRef, [], this.module.createBlock("", this.startFunctionBody))
|
this.module.addFunction("", typeRef, typesToBinaryenTypes(this.startFunction.additionalLocals), this.module.createBlock(null, this.startFunctionBody))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,43 +214,146 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
const valueDeclarations: EnumValueDeclaration[] = declaration.members;
|
const valueDeclarations: EnumValueDeclaration[] = declaration.members;
|
||||||
let previousValueName: string | null = null;
|
let previousValueName: string | null = null;
|
||||||
|
const isExport: bool = declaration.range.source.isEntry && hasModifier(ModifierKind.EXPORT, declaration.modifiers);
|
||||||
for (let i: i32 = 0, k: i32 = valueDeclarations.length; i < k; ++i)
|
for (let i: i32 = 0, k: i32 = valueDeclarations.length; i < k; ++i)
|
||||||
previousValueName = this.compileEnumValue(valueDeclarations[i], previousValueName);
|
previousValueName = this.compileEnumValue(valueDeclarations[i], previousValueName, isExport);
|
||||||
this.enums.add(name);
|
this.enums.add(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileEnumValue(declaration: EnumValueDeclaration, previousName: string | null): string {
|
compileEnumValue(declaration: EnumValueDeclaration, previousName: string | null, isExport: bool): string {
|
||||||
const name: string = this.program.mangleInternalName(declaration);
|
const name: string = this.program.mangleInternalName(declaration);
|
||||||
let initializer: BinaryenExpressionRef = declaration.value ? this.compileExpression(<Expression>declaration.value, Type.i32) : 0;
|
let initializer: BinaryenExpressionRef = declaration.value ? this.compileExpression(<Expression>declaration.value, Type.i32) : 0;
|
||||||
if (!this.options.noEmit) {
|
let initializeInStart: bool = declaration.value ? (<Expression>declaration.value).kind != NodeKind.LITERAL : true;
|
||||||
if (!initializer) initializer = previousName == null
|
// TODO: WASM does not support binary initializers for globals yet, hence me make them mutable and initialize in start
|
||||||
? this.module.createI32(0)
|
if (!initializer) {
|
||||||
: this.module.createBinary(BinaryOp.AddI32,
|
if (previousName == null) {
|
||||||
|
initializer = this.module.createI32(0);
|
||||||
|
initializeInStart = false;
|
||||||
|
} else {
|
||||||
|
initializer = this.module.createBinary(BinaryOp.AddI32,
|
||||||
this.module.createGetGlobal(previousName, BinaryenType.I32),
|
this.module.createGetGlobal(previousName, BinaryenType.I32),
|
||||||
this.module.createI32(1)
|
this.module.createI32(1)
|
||||||
);
|
);
|
||||||
this.module.addGlobal(name, BinaryenType.I32, false, initializer);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (initializeInStart) {
|
||||||
|
this.module.addGlobal(name, BinaryenType.I32, true, this.module.createI32(-1));
|
||||||
|
this.startFunctionBody.push(this.module.createSetGlobal(name, initializer));
|
||||||
|
} else
|
||||||
|
this.module.addGlobal(name, BinaryenType.I32, false, initializer);
|
||||||
|
// TODO: WASM does not support exporting globals yet (the following produces invalid code referencing a non-existent function)
|
||||||
|
// this.module.addExport(name, (<EnumDeclaration>declaration.parent).identifier.name + "." + declaration.identifier.name);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
compileFunction(declaration: FunctionDeclaration, typeArguments: Type[]): void {
|
checkTypeArguments(typeParameters: TypeParameter[], typeArguments: Type[], reportNode: Node | null = null): bool {
|
||||||
/* const binaryenResultType: BinaryenType = declaration.returnType ? this.resolveType(<TypeNode>declaration.returnType, true) : BinaryenType.None;
|
if (typeParameters.length != typeArguments.length) {
|
||||||
const binaryenParamTypes: BinaryenType[] = new Array();
|
if (reportNode)
|
||||||
|
this.error(DiagnosticCode.Expected_0_type_arguments_but_got_1, (<Node>reportNode).range, typeParameters.length.toString(10), typeArguments.length.toString(10));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// TODO: check TypeParameter#extendsType
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
compileFunction(declaration: FunctionDeclaration, typeArguments: Type[], inheritedTypeArgumentsMap: Map<string,Type> | null = null, reportNode: Node | null = null): void {
|
||||||
|
if (!declaration.statements) {
|
||||||
|
if (reportNode)
|
||||||
|
this.error(DiagnosticCode.Function_implementation_is_missing_or_not_immediately_following_the_declaration, (<Node>reportNode).range);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.checkTypeArguments(declaration.typeParameters, typeArguments, reportNode)) // reports if requested
|
||||||
|
return;
|
||||||
|
|
||||||
|
let globalName: string = this.program.mangleInternalName(declaration);
|
||||||
|
|
||||||
|
// inherit type arguments, i.e. from class
|
||||||
|
const typeArgumentsMap: Map<string,Type> = new Map();
|
||||||
|
if (inheritedTypeArgumentsMap)
|
||||||
|
for (let [key, val] of (<Map<string,Type>>inheritedTypeArgumentsMap))
|
||||||
|
typeArgumentsMap.set(key, val);
|
||||||
|
|
||||||
|
// set (possibly override) type arguments for this specific call
|
||||||
|
let i: i32, k: i32 = typeArguments.length;
|
||||||
|
if (k) {
|
||||||
|
for (i = 0; i < k; ++i)
|
||||||
|
typeArgumentsMap.set(declaration.typeParameters[i].identifier.name, typeArguments[i]);
|
||||||
|
globalName += typeArgumentsToString(typeArguments);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.functions.has(globalName)) {
|
||||||
|
if (reportNode)
|
||||||
|
this.error(DiagnosticCode.Duplicate_function_implementation, (<Node>reportNode).range);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve parameters
|
||||||
|
k = declaration.parameters.length;
|
||||||
|
const parameterNames: string[] = new Array(k);
|
||||||
|
const parameterTypes: Type[] = new Array(k);
|
||||||
|
for (i = 0; i < k; ++i) {
|
||||||
|
parameterNames[i] = declaration.parameters[i].identifier.name;
|
||||||
|
const typeNode: TypeNode | null = declaration.parameters[i].type;
|
||||||
|
if (typeNode) {
|
||||||
|
const type: Type | null = this.resolveType(<TypeNode>typeNode, typeArgumentsMap, true); // reports
|
||||||
|
if (type)
|
||||||
|
parameterTypes[i] = <Type>type;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
return; // TODO: infer type? (currently reported by parser)
|
||||||
|
}
|
||||||
|
|
||||||
|
// resolve return type
|
||||||
|
const typeNode: TypeNode | null = declaration.returnType;
|
||||||
|
let returnType: Type;
|
||||||
|
if (typeNode) {
|
||||||
|
const type: Type | null = this.resolveType(<TypeNode>typeNode, typeArgumentsMap, true); // reports
|
||||||
|
if (type)
|
||||||
|
returnType = <Type>type;
|
||||||
|
else
|
||||||
|
return;
|
||||||
|
} else
|
||||||
|
return; // TODO: infer type? (currently reported by parser)
|
||||||
|
|
||||||
|
// compile statements
|
||||||
|
const functionType: FunctionType = new FunctionType(typeArguments, parameterTypes, returnType, parameterNames);
|
||||||
|
this.functions.set(globalName, functionType);
|
||||||
|
const previousFunction: FunctionType = this.currentFunction;
|
||||||
|
this.currentFunction = functionType;
|
||||||
|
const statements: Statement[] = <Statement[]>declaration.statements;
|
||||||
|
k = statements.length;
|
||||||
|
const body: BinaryenExpressionRef[] = new Array(k);
|
||||||
|
let hasErrors: bool = false;
|
||||||
|
for (i = 0; i < k; ++i)
|
||||||
|
if (!(body[i] = this.compileStatement(statements[i])))
|
||||||
|
hasErrors = true;
|
||||||
|
this.currentFunction = previousFunction;
|
||||||
|
|
||||||
|
if (hasErrors)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// create function
|
||||||
|
const binaryenResultType: BinaryenType = typeToBinaryenType(returnType);
|
||||||
|
const binaryenParamTypes: BinaryenType[] = typesToBinaryenTypes(parameterTypes);
|
||||||
let binaryenTypeRef: BinaryenFunctionTypeRef = this.module.getFunctionTypeBySignature(binaryenResultType, binaryenParamTypes);
|
let binaryenTypeRef: BinaryenFunctionTypeRef = this.module.getFunctionTypeBySignature(binaryenResultType, binaryenParamTypes);
|
||||||
if (!binaryenTypeRef)
|
if (!binaryenTypeRef)
|
||||||
binaryenTypeRef = this.module.addFunctionType("", binaryenResultType, binaryenParamTypes); */
|
binaryenTypeRef = this.module.addFunctionType(typesToSignatureName(parameterTypes, returnType), binaryenResultType, binaryenParamTypes);
|
||||||
throw new Error("not implemented");
|
this.module.addFunction(globalName, binaryenTypeRef, typesToBinaryenTypes(functionType.additionalLocals), this.module.createBlock(null, body));
|
||||||
|
if (declaration.range.source.isEntry && hasModifier(ModifierKind.EXPORT, declaration.modifiers))
|
||||||
|
this.module.addExport(globalName, declaration.identifier.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileGlobals(statement: VariableStatement): void {
|
compileGlobals(statement: VariableStatement): void {
|
||||||
const declarations: VariableDeclaration[] = statement.declarations;
|
const declarations: VariableDeclaration[] = statement.declarations;
|
||||||
const isConst: bool = hasModifier(ModifierKind.CONST, statement.modifiers);
|
const isConst: bool = hasModifier(ModifierKind.CONST, statement.modifiers);
|
||||||
|
const isExport: bool = statement.range.source.isEntry && hasModifier(ModifierKind.EXPORT, statement.modifiers);
|
||||||
for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i)
|
for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i)
|
||||||
this.compileGlobal(declarations[i], isConst);
|
this.compileGlobal(declarations[i], isConst, isExport);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileGlobal(declaration: VariableDeclaration, isConst: bool): void {
|
compileGlobal(declaration: VariableDeclaration, isConst: bool, isExport: bool): void {
|
||||||
const type: Type | null = declaration.type ? this.resolveType(<TypeNode>declaration.type) : null; // reports
|
const type: Type | null = declaration.type ? this.resolveType(<TypeNode>declaration.type) : null; // reports
|
||||||
if (!type)
|
if (!type)
|
||||||
return;
|
return;
|
||||||
@ -252,15 +362,55 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, name);
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!this.options.noEmit) {
|
|
||||||
const binaryenType: BinaryenType = typeToBinaryenType(<Type>type);
|
const binaryenType: BinaryenType = typeToBinaryenType(<Type>type);
|
||||||
const initializer: BinaryenExpressionRef = declaration.initializer ? this.compileExpression(<Expression>declaration.initializer, <Type>type) : typeToBinaryenZero(this.module, <Type>type);
|
const initializer: BinaryenExpressionRef = declaration.initializer ? this.compileExpression(<Expression>declaration.initializer, <Type>type) : typeToBinaryenZero(this.module, <Type>type);
|
||||||
|
let initializeInStart: bool = declaration.initializer ? (<Expression>declaration.initializer).kind != NodeKind.LITERAL : false;
|
||||||
|
// TODO: WASM does not support binary initializers for globals yet, hence me make them mutable and initialize in start
|
||||||
|
if (initializeInStart) {
|
||||||
|
this.module.addGlobal(name, binaryenType, false, typeToBinaryenZero(this.module, <Type>type));
|
||||||
|
this.startFunctionBody.push(initializer);
|
||||||
|
} else
|
||||||
this.module.addGlobal(name, binaryenType, !isConst, initializer);
|
this.module.addGlobal(name, binaryenType, !isConst, initializer);
|
||||||
}
|
// TODO: WASM does not support exporting globals yet (the following produces invalid code referencing a non-existent function)
|
||||||
this.globals.add(name);
|
// this.module.addExport(name, declaration.identifier.name);
|
||||||
|
this.globals.set(name, <Type>type);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileNamespace(declaration: NamespaceDeclaration): void {
|
compileNamespace(declaration: NamespaceDeclaration): void {
|
||||||
|
const members: Statement[] = declaration.members;
|
||||||
|
for (let i: i32 = 0, k: i32 = members.length; i < k; ++i) {
|
||||||
|
const member: Statement = members[i];
|
||||||
|
switch (member.kind) {
|
||||||
|
|
||||||
|
case NodeKind.CLASS:
|
||||||
|
if (!(<ClassDeclaration>member).typeParameters.length)
|
||||||
|
this.compileClass(<ClassDeclaration>member, []);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NodeKind.ENUM:
|
||||||
|
this.compileEnum(<EnumDeclaration>member);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NodeKind.FUNCTION:
|
||||||
|
if (!(<FunctionDeclaration>member).typeParameters.length)
|
||||||
|
this.compileFunction(<FunctionDeclaration>member, []);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NodeKind.NAMESPACE:
|
||||||
|
this.compileNamespace(<NamespaceDeclaration>member);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case NodeKind.VARIABLE:
|
||||||
|
this.compileGlobals(<VariableStatement>member);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// TODO: some form of internal visibility?
|
||||||
|
// case NodeKind.EXPORT:
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Error("unexpected namespace member kind");
|
||||||
|
}
|
||||||
|
}
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,11 +446,11 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case NodeKind.VARIABLEDECLARATION:
|
case NodeKind.VARIABLEDECLARATION:
|
||||||
this.compileGlobal(<VariableDeclaration>declaration, hasModifier(ModifierKind.CONST, (<VariableStatement>declaration.parent).modifiers));
|
this.compileGlobal(<VariableDeclaration>declaration, hasModifier(ModifierKind.CONST, (<VariableStatement>declaration.parent).modifiers), member.range.source.isEntry);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw new Error("unexpected declaration kind");
|
throw new Error("unexpected export declaration kind");
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
throw new Error("unexpected missing declaration");
|
throw new Error("unexpected missing declaration");
|
||||||
@ -322,20 +472,96 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
// types
|
// types
|
||||||
|
|
||||||
resolveType(node: TypeNode, typeArgumentsMap: Map<string,Type> | null = null, reportNotFound: bool = true): Type | null {
|
resolveType(node: TypeNode, typeArgumentsMap: Map<string,Type> | null = null, reportNotFound: bool = true): Type | null {
|
||||||
// TODO: resolve node and its arguments using typeArgumentsMap
|
|
||||||
// TODO: make types for classes in program.ts
|
// resolve parameters
|
||||||
|
const k: i32 = node.parameters.length;
|
||||||
|
const paramTypes: Type[] = new Array(k);
|
||||||
|
for (let i: i32 = 0; i < k; ++i) {
|
||||||
|
const paramType: Type | null = this.resolveType(node.parameters[i], typeArgumentsMap, reportNotFound);
|
||||||
|
if (!paramType)
|
||||||
|
return null;
|
||||||
|
paramTypes[i] = <Type>paramType;
|
||||||
|
}
|
||||||
|
|
||||||
|
let globalName: string = node.identifier.name;
|
||||||
|
if (k) // not a placeholder
|
||||||
|
globalName += typeArgumentsToString(paramTypes);
|
||||||
|
else if (typeArgumentsMap && (<Map<string,Type>>typeArgumentsMap).has(globalName)) // possibly a placeholder
|
||||||
|
return <Type>(<Map<string,Type>>typeArgumentsMap).get(globalName);
|
||||||
|
|
||||||
const types: Map<string,Type> = this.program.types;
|
const types: Map<string,Type> = this.program.types;
|
||||||
const globalName: string = node.identifier.name;
|
|
||||||
|
// resolve local type
|
||||||
const localName: string = node.range.source.normalizedPath + "/" + globalName;
|
const localName: string = node.range.source.normalizedPath + "/" + globalName;
|
||||||
if (types.has(localName))
|
if (types.has(localName))
|
||||||
return <Type>types.get(localName);
|
return <Type>types.get(localName);
|
||||||
|
|
||||||
|
// resolve global type
|
||||||
if (types.has(globalName))
|
if (types.has(globalName))
|
||||||
return <Type>types.get(globalName);
|
return <Type>types.get(globalName);
|
||||||
|
|
||||||
if (reportNotFound)
|
if (reportNotFound)
|
||||||
this.error(DiagnosticCode.Cannot_find_name_0, node.identifier.range, globalName);
|
this.error(DiagnosticCode.Cannot_find_name_0, node.identifier.range, globalName);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolveExpressionType(expression: Expression, contextualType: Type): Type {
|
||||||
|
const previousType: Type = this.currentType;
|
||||||
|
const previousNoEmit: bool = this.module.noEmit;
|
||||||
|
this.module.noEmit = true;
|
||||||
|
this.compileExpression(expression, contextualType, false); // now performs a dry run
|
||||||
|
const type: Type = this.currentType;
|
||||||
|
this.currentType = previousType;
|
||||||
|
this.module.noEmit = previousNoEmit;
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveClassType(expression: Expression, typeArguments: TypeNode[], typeArgumentsMap: Map<string,Type> | null = null, create: bool = false): ClassType | null {
|
||||||
|
if (expression.kind == NodeKind.THIS) {
|
||||||
|
if (this.currentClass)
|
||||||
|
return <ClassType>this.currentClass;
|
||||||
|
this.error(DiagnosticCode._this_cannot_be_referenced_in_current_location, expression.range);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (expression.kind == NodeKind.IDENTIFIER) {
|
||||||
|
throw new Error("not implemented");
|
||||||
|
}
|
||||||
|
if (expression.kind == NodeKind.ELEMENTACCESS) {
|
||||||
|
throw new Error("not implemented");
|
||||||
|
}
|
||||||
|
if (expression.kind == NodeKind.PROPERTYACCESS) {
|
||||||
|
throw new Error("not implemented");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolveFunctionType(expression: Expression, typeArguments: TypeNode[], typeArgumentsMap: Map<string,Type> | null = null, create: bool = false): FunctionType | null {
|
||||||
|
const k: i32 = typeArguments.length;
|
||||||
|
const resolvedTypeArguments: Type[] = new Array(k);
|
||||||
|
for (let i: i32 = 0; i < k; ++i) {
|
||||||
|
const type: Type | null = this.resolveType(typeArguments[i], typeArgumentsMap, true); // reports
|
||||||
|
if (!type)
|
||||||
|
return null;
|
||||||
|
resolvedTypeArguments[i] = <Type>type;
|
||||||
|
}
|
||||||
|
if (expression.kind == NodeKind.IDENTIFIER) {
|
||||||
|
let globalName: string = (<IdentifierExpression>expression).name;
|
||||||
|
if (k)
|
||||||
|
globalName += typeArgumentsToString(resolvedTypeArguments);
|
||||||
|
const localName = expression.range.source.normalizedPath + "/" + globalName;
|
||||||
|
if (this.functions.has(localName))
|
||||||
|
return <FunctionType>this.functions.get(localName);
|
||||||
|
if (this.functions.has(globalName))
|
||||||
|
return <FunctionType>this.functions.get(globalName);
|
||||||
|
this.error(DiagnosticCode.Cannot_find_name_0, expression.range, globalName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (expression.kind == NodeKind.PROPERTYACCESS) {
|
||||||
|
throw new Error("not implemented");
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
// statements
|
// statements
|
||||||
|
|
||||||
compileStatement(statement: Statement): BinaryenExpressionRef {
|
compileStatement(statement: Statement): BinaryenExpressionRef {
|
||||||
@ -395,15 +621,35 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileBreakStatement(statement: BreakStatement): BinaryenExpressionRef {
|
compileBreakStatement(statement: BreakStatement): BinaryenExpressionRef {
|
||||||
throw new Error("not implemented");
|
const context: string | null = this.currentFunction.breakContext;
|
||||||
|
if (context)
|
||||||
|
return this.module.createBreak("break$" + (<string>context));
|
||||||
|
this.error(DiagnosticCode.A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement, statement.range);
|
||||||
|
return this.module.createUnreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
compileContinueStatement(statement: ContinueStatement): BinaryenExpressionRef {
|
compileContinueStatement(statement: ContinueStatement): BinaryenExpressionRef {
|
||||||
throw new Error("not implemented");
|
const context: string | null = this.currentFunction.breakContext;
|
||||||
|
if (context)
|
||||||
|
return this.module.createBreak("continue$" + (<string>context));
|
||||||
|
this.error(DiagnosticCode.A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement, statement.range);
|
||||||
|
return this.module.createUnreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
compileDoStatement(statement: DoStatement): BinaryenExpressionRef {
|
compileDoStatement(statement: DoStatement): BinaryenExpressionRef {
|
||||||
throw new Error("not implemented");
|
const label: string = this.currentFunction.enterBreakContext();
|
||||||
|
const condition: BinaryenExpressionRef = this.compileExpression(statement.condition, Type.i32);
|
||||||
|
const body: BinaryenExpressionRef = this.compileStatement(statement.statement);
|
||||||
|
this.currentFunction.leaveBreakContext();
|
||||||
|
const breakLabel: string = "break$" + label;
|
||||||
|
const continueLabel: string = "continue$" + label;
|
||||||
|
return this.module.createBlock(breakLabel, [
|
||||||
|
this.module.createLoop(continueLabel,
|
||||||
|
this.module.createBlock(null, [
|
||||||
|
body,
|
||||||
|
this.module.createBreak(continueLabel, condition)
|
||||||
|
]))
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileEmptyStatement(statement: EmptyStatement): BinaryenExpressionRef {
|
compileEmptyStatement(statement: EmptyStatement): BinaryenExpressionRef {
|
||||||
@ -415,10 +661,24 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileForStatement(statement: ForStatement): BinaryenExpressionRef {
|
compileForStatement(statement: ForStatement): BinaryenExpressionRef {
|
||||||
const initializer: BinaryenExpressionRef = statement.initializer ? this.compileStatement(<Statement>statement.initializer) : 0;
|
const context: string = this.currentFunction.enterBreakContext();
|
||||||
const condition: BinaryenExpressionRef = statement.condition ? this.compileExpression(<Expression>statement.condition, Type.i32) : 0;
|
const initializer: BinaryenExpressionRef = statement.initializer ? this.compileStatement(<Statement>statement.initializer) : this.module.createNop();
|
||||||
const incrementor: BinaryenExpressionRef = statement.incrementor ? this.compileExpression(<Expression>statement.incrementor, Type.void) : 0;
|
const condition: BinaryenExpressionRef = statement.condition ? this.compileExpression(<Expression>statement.condition, Type.i32) : this.module.createI32(1);
|
||||||
throw new Error("not implemented");
|
const incrementor: BinaryenExpressionRef = statement.incrementor ? this.compileExpression(<Expression>statement.incrementor, Type.void) : this.module.createNop();
|
||||||
|
const body: BinaryenExpressionRef = this.compileStatement(statement.statement);
|
||||||
|
this.currentFunction.leaveBreakContext();
|
||||||
|
const continueLabel: string = "continue$" + context;
|
||||||
|
const breakLabel: string = "break$" + context;
|
||||||
|
return this.module.createBlock(breakLabel, [
|
||||||
|
initializer,
|
||||||
|
this.module.createLoop(continueLabel, this.module.createBlock(null, [
|
||||||
|
this.module.createIf(condition, this.module.createBlock(null, [
|
||||||
|
body,
|
||||||
|
incrementor,
|
||||||
|
this.module.createBreak(continueLabel)
|
||||||
|
]))
|
||||||
|
]))
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileIfStatement(statement: IfStatement): BinaryenExpressionRef {
|
compileIfStatement(statement: IfStatement): BinaryenExpressionRef {
|
||||||
@ -446,10 +706,35 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
compileTryStatement(statement: TryStatement): BinaryenExpressionRef {
|
compileTryStatement(statement: TryStatement): BinaryenExpressionRef {
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
|
// can't yet support something like: try { return ... } finally { ... }
|
||||||
|
// worthwhile to investigate lowering returns to block results (here)?
|
||||||
}
|
}
|
||||||
|
|
||||||
compileVariableStatement(statement: VariableStatement): BinaryenExpressionRef {
|
compileVariableStatement(statement: VariableStatement): BinaryenExpressionRef {
|
||||||
throw new Error("not implemented");
|
// top-level variables become globals
|
||||||
|
if (this.currentFunction == this.startFunction) {
|
||||||
|
this.compileGlobals(statement);
|
||||||
|
return this.module.createNop();
|
||||||
|
}
|
||||||
|
// other variables become locals
|
||||||
|
const declarations: VariableDeclaration[] = statement.declarations;
|
||||||
|
const initializers: BinaryenExpressionRef[] = new Array();
|
||||||
|
for (let i: i32 = 0, k = declarations.length; i < k; ++i) {
|
||||||
|
const declaration: VariableDeclaration = declarations[i];
|
||||||
|
if (declaration.type) {
|
||||||
|
const name: string = declaration.identifier.name;
|
||||||
|
const type: Type | null = this.resolveType(<TypeNode>declaration.type, this.currentFunction.typeArgumentsMap, true); // reports
|
||||||
|
if (type) {
|
||||||
|
if (this.currentFunction.locals.has(name))
|
||||||
|
this.error(DiagnosticCode.Duplicate_identifier_0, declaration.identifier.range, name); // recoverable
|
||||||
|
else
|
||||||
|
this.currentFunction.addLocal(<Type>type, name);
|
||||||
|
if (declaration.initializer)
|
||||||
|
initializers.push(this.compileAssignment(declaration.identifier, <Expression>declaration.initializer, Type.void));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return initializers.length ? this.module.createBlock(null, initializers) : this.module.createNop();
|
||||||
}
|
}
|
||||||
|
|
||||||
compileWhileStatement(statement: WhileStatement): BinaryenExpressionRef {
|
compileWhileStatement(statement: WhileStatement): BinaryenExpressionRef {
|
||||||
@ -541,7 +826,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
|
|
||||||
// void to any
|
// void to any
|
||||||
if (fromType.kind == TypeKind.VOID)
|
if (fromType.kind == TypeKind.VOID)
|
||||||
throw new Error("illegal conversion");
|
throw new Error("unexpected conversion from void");
|
||||||
|
|
||||||
// any to void
|
// any to void
|
||||||
if (toType.kind == TypeKind.VOID)
|
if (toType.kind == TypeKind.VOID)
|
||||||
@ -773,6 +1058,9 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
this.currentType = Type.bool;
|
this.currentType = Type.bool;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case Token.EQUALS:
|
||||||
|
return this.compileAssignment(expression.left, expression.right, contextualType);
|
||||||
|
|
||||||
case Token.PLUS_EQUALS:
|
case Token.PLUS_EQUALS:
|
||||||
compound = Token.EQUALS;
|
compound = Token.EQUALS;
|
||||||
case Token.PLUS:
|
case Token.PLUS:
|
||||||
@ -835,7 +1123,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
left = this.compileExpression(expression.left, contextualType, false);
|
left = this.compileExpression(expression.left, contextualType, false);
|
||||||
right = this.compileExpression(expression.right, this.currentType);
|
right = this.compileExpression(expression.right, this.currentType);
|
||||||
if (this.currentType.isAnyFloat)
|
if (this.currentType.isAnyFloat)
|
||||||
throw new Error("not implemented"); // TODO: fmod
|
throw new Error("not implemented"); // TODO: internal fmod
|
||||||
op = this.currentType.isLongInteger
|
op = this.currentType.isLongInteger
|
||||||
? BinaryOp.RemI64
|
? BinaryOp.RemI64
|
||||||
: BinaryOp.RemI32;
|
: BinaryOp.RemI32;
|
||||||
@ -908,17 +1196,56 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
default:
|
default:
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
}
|
}
|
||||||
|
if (compound) {
|
||||||
return compound
|
right = this.module.createBinary(op, left, right);
|
||||||
? this.compileAssignment(expression.left, this.module.createBinary(op, left, right), this.currentType != Type.void)
|
return this.compileAssignmentWithValue(expression.left, right, contextualType != Type.void);
|
||||||
: this.module.createBinary(op, left, right);
|
}
|
||||||
|
return this.module.createBinary(op, left, right);
|
||||||
}
|
}
|
||||||
|
|
||||||
compileAssignment(expression: Expression, value: BinaryenExpressionRef, tee: bool = false): BinaryenExpressionRef {
|
compileAssignment(expression: Expression, valueExpression: Expression, contextualType: Type): BinaryenExpressionRef {
|
||||||
|
this.currentType = this.resolveExpressionType(expression, contextualType);
|
||||||
|
return this.compileAssignmentWithValue(expression, this.compileExpression(valueExpression, this.currentType), contextualType != Type.void);
|
||||||
|
}
|
||||||
|
|
||||||
|
compileAssignmentWithValue(expression: Expression, valueWithCorrectType: BinaryenExpressionRef, tee: bool = false): BinaryenExpressionRef {
|
||||||
|
if (expression.kind == NodeKind.IDENTIFIER) {
|
||||||
|
const name: string = (<IdentifierExpression>expression).name;
|
||||||
|
const locals: Map<string,LocalType> = this.currentFunction.locals;
|
||||||
|
if (locals.has(name)) {
|
||||||
|
const local: LocalType = <LocalType>locals.get(name);
|
||||||
|
if (tee) {
|
||||||
|
this.currentType = local.type;
|
||||||
|
return this.module.createTeeLocal(local.index, valueWithCorrectType);
|
||||||
|
}
|
||||||
|
this.currentType = Type.void;
|
||||||
|
return this.module.createSetLocal(local.index, valueWithCorrectType);
|
||||||
|
}
|
||||||
|
const globals: Map<string,Type> = this.globals;
|
||||||
|
if (globals.has(name)) {
|
||||||
|
const globalType: Type = <Type>globals.get(name);
|
||||||
|
if (tee) {
|
||||||
|
const globalBinaryenType: BinaryenType = typeToBinaryenType(globalType);
|
||||||
|
this.currentType = globalType;
|
||||||
|
return this.module.createBlock(null, [ // teeGlobal
|
||||||
|
this.module.createSetGlobal(name, valueWithCorrectType),
|
||||||
|
this.module.createGetGlobal(name, globalBinaryenType)
|
||||||
|
], globalBinaryenType);
|
||||||
|
}
|
||||||
|
this.currentType = Type.void;
|
||||||
|
return this.module.createSetGlobal(name, valueWithCorrectType);
|
||||||
|
}
|
||||||
|
}
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
compileCallExpression(expression: CallExpression, contextualType: Type): BinaryenExpressionRef {
|
compileCallExpression(expression: CallExpression, contextualType: Type): BinaryenExpressionRef {
|
||||||
|
const functionType: FunctionType | null = this.resolveFunctionType(expression.expression, expression.typeArguments, this.currentFunction.typeArgumentsMap, true);
|
||||||
|
if (!functionType)
|
||||||
|
return this.module.createUnreachable();
|
||||||
|
// TODO: compile if not yet compiled
|
||||||
|
// TODO: validate parameters and call
|
||||||
|
// this.module.createCall(functionType.ref, operands, typeToBinaryenType(functionType.returnType));
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -927,7 +1254,20 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileIdentifierExpression(expression: IdentifierExpression, contextualType: Type): BinaryenExpressionRef {
|
compileIdentifierExpression(expression: IdentifierExpression, contextualType: Type): BinaryenExpressionRef {
|
||||||
throw new Error("not implemented");
|
const name: string = expression.name;
|
||||||
|
const locals: Map<string,LocalType> = this.currentFunction.locals;
|
||||||
|
if (locals.has(name)) {
|
||||||
|
const local: LocalType = <LocalType>locals.get(name);
|
||||||
|
this.currentType = local.type;
|
||||||
|
return this.module.createGetLocal(local.index, typeToBinaryenType(this.currentType));
|
||||||
|
}
|
||||||
|
const globals: Map<string,Type> = this.globals;
|
||||||
|
if (globals.has(name)) {
|
||||||
|
this.currentType = <Type>globals.get(name);
|
||||||
|
return this.module.createGetGlobal(name, typeToBinaryenType(this.currentType));
|
||||||
|
}
|
||||||
|
this.error(DiagnosticCode.Cannot_find_name_0, expression.range, name);
|
||||||
|
return this.module.createUnreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
compileLiteralExpression(expression: LiteralExpression, contextualType: Type): BinaryenExpressionRef {
|
compileLiteralExpression(expression: LiteralExpression, contextualType: Type): BinaryenExpressionRef {
|
||||||
@ -1006,9 +1346,8 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
binaryenType = BinaryenType.I32;
|
binaryenType = BinaryenType.I32;
|
||||||
binaryenOne = this.module.createI32(1);
|
binaryenOne = this.module.createI32(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
const getValue: BinaryenExpressionRef = this.compileExpression(expression.expression, contextualType);
|
const getValue: BinaryenExpressionRef = this.compileExpression(expression.expression, contextualType);
|
||||||
const setValue: BinaryenExpressionRef = this.compileAssignment(expression.expression, this.module.createBinary(op, getValue, binaryenOne), false); // reports
|
const setValue: BinaryenExpressionRef = this.compileAssignmentWithValue(expression.expression, this.module.createBinary(op, getValue, binaryenOne), false); // reports
|
||||||
|
|
||||||
return this.module.createBlock(null, [
|
return this.module.createBlock(null, [
|
||||||
getValue,
|
getValue,
|
||||||
@ -1017,16 +1356,18 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileUnaryPrefixExpression(expression: UnaryPrefixExpression, contextualType: Type): BinaryenExpressionRef {
|
compileUnaryPrefixExpression(expression: UnaryPrefixExpression, contextualType: Type): BinaryenExpressionRef {
|
||||||
|
const operandExpression: Expression = expression.expression;
|
||||||
|
|
||||||
let operand: BinaryenExpressionRef;
|
let operand: BinaryenExpressionRef;
|
||||||
let op: UnaryOp;
|
let op: UnaryOp;
|
||||||
|
|
||||||
switch (expression.operator) {
|
switch (expression.operator) {
|
||||||
|
|
||||||
case Token.PLUS:
|
case Token.PLUS:
|
||||||
return this.compileExpression(expression.expression, contextualType); // noop
|
return this.compileExpression(operandExpression, contextualType);
|
||||||
|
|
||||||
case Token.MINUS:
|
case Token.MINUS:
|
||||||
operand = this.compileExpression(expression.expression, contextualType);
|
operand = this.compileExpression(operandExpression, contextualType);
|
||||||
if (this.currentType == Type.f32)
|
if (this.currentType == Type.f32)
|
||||||
op = UnaryOp.NegF32;
|
op = UnaryOp.NegF32;
|
||||||
else if (this.currentType == Type.f64)
|
else if (this.currentType == Type.f64)
|
||||||
@ -1038,27 +1379,27 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.PLUS_PLUS:
|
case Token.PLUS_PLUS:
|
||||||
operand = this.compileExpression(expression.expression, contextualType);
|
operand = this.compileExpression(operandExpression, contextualType);
|
||||||
return this.currentType == Type.f32
|
return this.currentType == Type.f32
|
||||||
? this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.AddF32, operand, this.module.createF32(1)), contextualType != Type.void)
|
? this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.AddF32, operand, this.module.createF32(1)), contextualType != Type.void)
|
||||||
: this.currentType == Type.f64
|
: this.currentType == Type.f64
|
||||||
? this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.AddF64, operand, this.module.createF64(1)), contextualType != Type.void)
|
? this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.AddF64, operand, this.module.createF64(1)), contextualType != Type.void)
|
||||||
: this.currentType.isLongInteger
|
: this.currentType.isLongInteger
|
||||||
? this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.AddI64, operand, this.module.createI64(1, 0)), contextualType != Type.void)
|
? this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.AddI64, operand, this.module.createI64(1, 0)), contextualType != Type.void)
|
||||||
: this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.AddI32, operand, this.module.createI32(1)), contextualType != Type.void);
|
: this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.AddI32, operand, this.module.createI32(1)), contextualType != Type.void);
|
||||||
|
|
||||||
case Token.MINUS_MINUS:
|
case Token.MINUS_MINUS:
|
||||||
operand = this.compileExpression(expression.expression, contextualType);
|
operand = this.compileExpression(operandExpression, contextualType);
|
||||||
return this.currentType == Type.f32
|
return this.currentType == Type.f32
|
||||||
? this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.SubF32, operand, this.module.createF32(1)), contextualType != Type.void)
|
? this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.SubF32, operand, this.module.createF32(1)), contextualType != Type.void)
|
||||||
: this.currentType == Type.f64
|
: this.currentType == Type.f64
|
||||||
? this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.SubF64, operand, this.module.createF64(1)), contextualType != Type.void)
|
? this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.SubF64, operand, this.module.createF64(1)), contextualType != Type.void)
|
||||||
: this.currentType.isLongInteger
|
: this.currentType.isLongInteger
|
||||||
? this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.SubI64, operand, this.module.createI64(1, 0)), contextualType != Type.void)
|
? this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.SubI64, operand, this.module.createI64(1, 0)), contextualType != Type.void)
|
||||||
: this.compileAssignment(expression.expression, this.module.createBinary(BinaryOp.SubI32, operand, this.module.createI32(1)), contextualType != Type.void);
|
: this.compileAssignmentWithValue(operandExpression, this.module.createBinary(BinaryOp.SubI32, operand, this.module.createI32(1)), contextualType != Type.void);
|
||||||
|
|
||||||
case Token.EXCLAMATION:
|
case Token.EXCLAMATION:
|
||||||
operand = this.compileExpression(expression.expression, Type.bool, false);
|
operand = this.compileExpression(operandExpression, Type.bool, false);
|
||||||
if (this.currentType == Type.f32) {
|
if (this.currentType == Type.f32) {
|
||||||
this.currentType = Type.bool;
|
this.currentType = Type.bool;
|
||||||
return this.module.createBinary(BinaryOp.EqF32, operand, this.module.createF32(0));
|
return this.module.createBinary(BinaryOp.EqF32, operand, this.module.createF32(0));
|
||||||
@ -1074,7 +1415,7 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case Token.TILDE:
|
case Token.TILDE:
|
||||||
operand = this.compileExpression(expression.expression, contextualType.isAnyFloat ? Type.i64 : contextualType);
|
operand = this.compileExpression(operandExpression, contextualType.isAnyFloat ? Type.i64 : contextualType);
|
||||||
return this.currentType.isLongInteger
|
return this.currentType.isLongInteger
|
||||||
? this.module.createBinary(BinaryOp.XorI64, operand, this.module.createI64(-1, -1))
|
? this.module.createBinary(BinaryOp.XorI64, operand, this.module.createI64(-1, -1))
|
||||||
: this.module.createBinary(BinaryOp.XorI32, operand, this.module.createI32(-1));
|
: this.module.createBinary(BinaryOp.XorI32, operand, this.module.createI32(-1));
|
||||||
@ -1082,7 +1423,6 @@ export class Compiler extends DiagnosticEmitter {
|
|||||||
default:
|
default:
|
||||||
throw new Error("not implemented");
|
throw new Error("not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.module.createUnary(op, operand);
|
return this.module.createUnary(op, operand);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1101,6 +1441,14 @@ function typeToBinaryenType(type: Type): BinaryenType {
|
|||||||
: BinaryenType.None;
|
: BinaryenType.None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function typesToBinaryenTypes(types: Type[]): BinaryenType[] {
|
||||||
|
const k: i32 = types.length;
|
||||||
|
const ret: BinaryenType[] = new Array(k);
|
||||||
|
for (let i: i32 = 0; i < k; ++i)
|
||||||
|
ret[i] = typeToBinaryenType(types[i]);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
function typeToBinaryenZero(module: Module, type: Type): BinaryenExpressionRef {
|
function typeToBinaryenZero(module: Module, type: Type): BinaryenExpressionRef {
|
||||||
return type.kind == TypeKind.F32
|
return type.kind == TypeKind.F32
|
||||||
? module.createF32(0)
|
? module.createF32(0)
|
||||||
@ -1135,7 +1483,7 @@ function typeToSignatureNamePart(type: Type): string {
|
|||||||
|
|
||||||
function typesToSignatureName(paramTypes: Type[], returnType: Type): string {
|
function typesToSignatureName(paramTypes: Type[], returnType: Type): string {
|
||||||
sb.length = 0;
|
sb.length = 0;
|
||||||
for (let i: i32 = 0, k = paramTypes.length; i < k; ++i)
|
for (let i: i32 = 0, k: i32 = paramTypes.length; i < k; ++i)
|
||||||
sb.push(typeToSignatureNamePart(paramTypes[i]));
|
sb.push(typeToSignatureNamePart(paramTypes[i]));
|
||||||
sb.push(typeToSignatureNamePart(returnType));
|
sb.push(typeToSignatureNamePart(returnType));
|
||||||
return sb.join("");
|
return sb.join("");
|
||||||
|
@ -19,6 +19,8 @@ export enum DiagnosticCode {
|
|||||||
An_accessor_cannot_have_type_parameters = 1094,
|
An_accessor_cannot_have_type_parameters = 1094,
|
||||||
A_set_accessor_cannot_have_a_return_type_annotation = 1095,
|
A_set_accessor_cannot_have_a_return_type_annotation = 1095,
|
||||||
Type_parameter_list_cannot_be_empty = 1098,
|
Type_parameter_list_cannot_be_empty = 1098,
|
||||||
|
A_continue_statement_can_only_be_used_within_an_enclosing_iteration_statement = 1104,
|
||||||
|
A_break_statement_can_only_be_used_within_an_enclosing_iteration_or_switch_statement = 1105,
|
||||||
A_return_statement_can_only_be_used_within_a_function_body = 1108,
|
A_return_statement_can_only_be_used_within_a_function_body = 1108,
|
||||||
Expression_expected = 1109,
|
Expression_expected = 1109,
|
||||||
Type_expected = 1110,
|
Type_expected = 1110,
|
||||||
@ -46,8 +48,11 @@ export enum DiagnosticCode {
|
|||||||
Generic_type_0_requires_1_type_argument_s = 2314,
|
Generic_type_0_requires_1_type_argument_s = 2314,
|
||||||
Type_0_is_not_generic = 2315,
|
Type_0_is_not_generic = 2315,
|
||||||
Type_0_is_not_assignable_to_type_1 = 2322,
|
Type_0_is_not_assignable_to_type_1 = 2322,
|
||||||
|
_this_cannot_be_referenced_in_current_location = 2332,
|
||||||
The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access = 2357,
|
The_operand_of_an_increment_or_decrement_operator_must_be_a_variable_or_a_property_access = 2357,
|
||||||
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391
|
Function_implementation_is_missing_or_not_immediately_following_the_declaration = 2391,
|
||||||
|
Duplicate_function_implementation = 2393,
|
||||||
|
Expected_0_type_arguments_but_got_1 = 2558
|
||||||
}
|
}
|
||||||
|
|
||||||
export function diagnosticCodeToString(code: DiagnosticCode): string {
|
export function diagnosticCodeToString(code: DiagnosticCode): string {
|
||||||
@ -70,6 +75,8 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
|||||||
case 1094: return "An accessor cannot have type parameters.";
|
case 1094: return "An accessor cannot have type parameters.";
|
||||||
case 1095: return "A 'set' accessor cannot have a return type annotation.";
|
case 1095: return "A 'set' accessor cannot have a return type annotation.";
|
||||||
case 1098: return "Type parameter list cannot be empty.";
|
case 1098: return "Type parameter list cannot be empty.";
|
||||||
|
case 1104: return "A 'continue' statement can only be used within an enclosing iteration statement.";
|
||||||
|
case 1105: return "A 'break' statement can only be used within an enclosing iteration or switch statement.";
|
||||||
case 1108: return "A 'return' statement can only be used within a function body.";
|
case 1108: return "A 'return' statement can only be used within a function body.";
|
||||||
case 1109: return "Expression expected.";
|
case 1109: return "Expression expected.";
|
||||||
case 1110: return "Type expected.";
|
case 1110: return "Type expected.";
|
||||||
@ -97,8 +104,11 @@ export function diagnosticCodeToString(code: DiagnosticCode): string {
|
|||||||
case 2314: return "Generic type '{0}' requires {1} type argument(s).";
|
case 2314: return "Generic type '{0}' requires {1} type argument(s).";
|
||||||
case 2315: return "Type '{0}' is not generic.";
|
case 2315: return "Type '{0}' is not generic.";
|
||||||
case 2322: return "Type '{0}' is not assignable to type '{1}'.";
|
case 2322: return "Type '{0}' is not assignable to type '{1}'.";
|
||||||
|
case 2332: return "'this' cannot be referenced in current location.";
|
||||||
case 2357: return "The operand of an increment or decrement operator must be a variable or a property access.";
|
case 2357: return "The operand of an increment or decrement operator must be a variable or a property access.";
|
||||||
case 2391: return "Function implementation is missing or not immediately following the declaration.";
|
case 2391: return "Function implementation is missing or not immediately following the declaration.";
|
||||||
|
case 2393: return "Duplicate function implementation.";
|
||||||
|
case 2558: return "Expected {0} type arguments, but got {1}.";
|
||||||
default: return "";
|
default: return "";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
"An accessor cannot have type parameters.": 1094,
|
"An accessor cannot have type parameters.": 1094,
|
||||||
"A 'set' accessor cannot have a return type annotation.": 1095,
|
"A 'set' accessor cannot have a return type annotation.": 1095,
|
||||||
"Type parameter list cannot be empty.": 1098,
|
"Type parameter list cannot be empty.": 1098,
|
||||||
|
"A 'continue' statement can only be used within an enclosing iteration statement.": 1104,
|
||||||
|
"A 'break' statement can only be used within an enclosing iteration or switch statement.": 1105,
|
||||||
"A 'return' statement can only be used within a function body.": 1108,
|
"A 'return' statement can only be used within a function body.": 1108,
|
||||||
"Expression expected.": 1109,
|
"Expression expected.": 1109,
|
||||||
"Type expected.": 1110,
|
"Type expected.": 1110,
|
||||||
@ -46,6 +48,9 @@
|
|||||||
"Generic type '{0}' requires {1} type argument(s).": 2314,
|
"Generic type '{0}' requires {1} type argument(s).": 2314,
|
||||||
"Type '{0}' is not generic.": 2315,
|
"Type '{0}' is not generic.": 2315,
|
||||||
"Type '{0}' is not assignable to type '{1}'.": 2322,
|
"Type '{0}' is not assignable to type '{1}'.": 2322,
|
||||||
|
"'this' cannot be referenced in current location.": 2332,
|
||||||
"The operand of an increment or decrement operator must be a variable or a property access.": 2357,
|
"The operand of an increment or decrement operator must be a variable or a property access.": 2357,
|
||||||
"Function implementation is missing or not immediately following the declaration.": 2391
|
"Function implementation is missing or not immediately following the declaration.": 2391,
|
||||||
|
"Duplicate function implementation.": 2393,
|
||||||
|
"Expected {0} type arguments, but got {1}.": 2558
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
import { Program } from "./program";
|
import { Program } from "./program";
|
||||||
import { Tokenizer, Token, Range } from "./tokenizer";
|
import { Tokenizer, Token, Range } from "./tokenizer";
|
||||||
import { DiagnosticCode, DiagnosticEmitter } from "./diagnostics";
|
import { DiagnosticCode, DiagnosticEmitter } from "./diagnostics";
|
||||||
import { normalizePath } from "./util";
|
import { normalizePath, I64 } from "./util";
|
||||||
import {
|
import {
|
||||||
|
|
||||||
NodeKind,
|
NodeKind,
|
||||||
@ -233,9 +233,9 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
|
|
||||||
// this
|
// this
|
||||||
} else if (token == Token.THIS) {
|
} else if (token == Token.THIS) {
|
||||||
type = TypeNode.create(Expression.createIdentifier("this", tn.range()), [], false, tn.range(startPos, tn.pos));
|
type = TypeNode.create(Expression.createThis(tn.range()), [], false, tn.range(startPos, tn.pos));
|
||||||
|
|
||||||
// true, false
|
// true
|
||||||
} else if (token == Token.TRUE || token == Token.FALSE) {
|
} else if (token == Token.TRUE || token == Token.FALSE) {
|
||||||
type = TypeNode.create(Expression.createIdentifier("bool", tn.range()), [], false, tn.range(startPos, tn.pos));
|
type = TypeNode.create(Expression.createIdentifier("bool", tn.range()), [], false, tn.range(startPos, tn.pos));
|
||||||
|
|
||||||
@ -951,6 +951,7 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseExpressionStatement(tn: Tokenizer): ExpressionStatement | null {
|
parseExpressionStatement(tn: Tokenizer): ExpressionStatement | null {
|
||||||
|
// at previous token
|
||||||
const expr: Expression | null = this.parseExpression(tn);
|
const expr: Expression | null = this.parseExpression(tn);
|
||||||
if (!expr)
|
if (!expr)
|
||||||
return null;
|
return null;
|
||||||
@ -961,7 +962,7 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
|
|
||||||
parseForStatement(tn: Tokenizer): ForStatement | null {
|
parseForStatement(tn: Tokenizer): ForStatement | null {
|
||||||
// at 'for': '(' Statement? Expression? ';' Expression? ')' Statement
|
// at 'for': '(' Statement? Expression? ';' Expression? ')' Statement
|
||||||
const startRange: Range = tn.range();
|
const startPos: i32 = tn.tokenPos;
|
||||||
if (tn.skip(Token.OPENPAREN)) {
|
if (tn.skip(Token.OPENPAREN)) {
|
||||||
const initializer: Statement | null = this.parseStatement(tn); // skips the semicolon (actually an expression)
|
const initializer: Statement | null = this.parseStatement(tn); // skips the semicolon (actually an expression)
|
||||||
if (!initializer)
|
if (!initializer)
|
||||||
@ -976,10 +977,13 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
const incrementor: Expression | null = this.parseExpression(tn);
|
const incrementor: Expression | null = this.parseExpression(tn);
|
||||||
if (!incrementor)
|
if (!incrementor)
|
||||||
return null;
|
return null;
|
||||||
|
if (tn.skip(Token.CLOSEPAREN)) {
|
||||||
const statement: Statement | null = this.parseStatement(tn);
|
const statement: Statement | null = this.parseStatement(tn);
|
||||||
if (!statement)
|
if (!statement)
|
||||||
return null;
|
return null;
|
||||||
return Statement.createFor(initializer, condition, incrementor, statement, Range.join(startRange, tn.range()));
|
return Statement.createFor(initializer, condition, incrementor, statement, tn.range(startPos, tn.pos));
|
||||||
|
} else
|
||||||
|
this.error(DiagnosticCode._0_expected, tn.range(), ")");
|
||||||
} else
|
} else
|
||||||
this.error(DiagnosticCode._0_expected, tn.range(), ";");
|
this.error(DiagnosticCode._0_expected, tn.range(), ";");
|
||||||
} else
|
} else
|
||||||
@ -1095,8 +1099,7 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parseTryStatement(tn: Tokenizer): TryStatement | null {
|
parseTryStatement(tn: Tokenizer): TryStatement | null {
|
||||||
// at 'try': '{' Statement* '}' 'catch' '(' VariableMember ')' '{' Statement* '}' ';'?
|
// at 'try': '{' Statement* '}' ('catch' '(' VariableMember ')' '{' Statement* '}')? ('finally' '{' Statement* '}'? ';'?
|
||||||
// TODO: 'finally' '{' Statement* '}'
|
|
||||||
const startRange: Range = tn.range();
|
const startRange: Range = tn.range();
|
||||||
if (tn.skip(Token.OPENBRACE)) {
|
if (tn.skip(Token.OPENBRACE)) {
|
||||||
const statements: Statement[] = new Array();
|
const statements: Statement[] = new Array();
|
||||||
@ -1106,33 +1109,57 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
return null;
|
return null;
|
||||||
statements.push(<Statement>stmt);
|
statements.push(<Statement>stmt);
|
||||||
}
|
}
|
||||||
|
let catchVariable: IdentifierExpression | null = null;
|
||||||
|
let catchStatements: Statement[] | null = null;
|
||||||
|
let finallyStatements: Statement[] | null = null;
|
||||||
if (tn.skip(Token.CATCH)) {
|
if (tn.skip(Token.CATCH)) {
|
||||||
if (tn.skip(Token.OPENPAREN)) {
|
if (!tn.skip(Token.OPENPAREN)) {
|
||||||
const catchVariable: VariableDeclaration | null = this.parseVariableDeclaration(tn);
|
this.error(DiagnosticCode._0_expected, tn.range(), "(");
|
||||||
if (!catchVariable)
|
|
||||||
return null;
|
return null;
|
||||||
if (tn.skip(Token.CLOSEPAREN)) {
|
}
|
||||||
if (tn.skip(Token.OPENBRACE)) {
|
if (!tn.skip(Token.IDENTIFIER)) {
|
||||||
const catchStatements: Statement[] = new Array();
|
this.error(DiagnosticCode.Identifier_expected, tn.range());
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catchVariable = Expression.createIdentifier(tn.readIdentifier(), tn.range());
|
||||||
|
if (!tn.skip(Token.CLOSEPAREN)) {
|
||||||
|
this.error(DiagnosticCode._0_expected, tn.range(), ")");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (!tn.skip(Token.OPENBRACE)) {
|
||||||
|
this.error(DiagnosticCode._0_expected, tn.range(), "{");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catchStatements = new Array();
|
||||||
while (!tn.skip(Token.CLOSEBRACE)) {
|
while (!tn.skip(Token.CLOSEBRACE)) {
|
||||||
const stmt: Statement | null = this.parseStatement(tn);
|
const stmt: Statement | null = this.parseStatement(tn);
|
||||||
if (!stmt)
|
if (!stmt)
|
||||||
return null;
|
return null;
|
||||||
catchStatements.push(<Statement>stmt);
|
catchStatements.push(<Statement>stmt);
|
||||||
}
|
}
|
||||||
const ret: TryStatement = Statement.createTry(statements, catchVariable, catchStatements, Range.join(startRange, tn.range()));
|
}
|
||||||
|
if (tn.skip(Token.FINALLY)) {
|
||||||
|
if (!tn.skip(Token.OPENBRACE)) {
|
||||||
|
this.error(DiagnosticCode._0_expected, tn.range(), "{");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
finallyStatements = new Array();
|
||||||
|
while (!tn.skip(Token.CLOSEBRACE)) {
|
||||||
|
const stmt: Statement | null = this.parseStatement(tn);
|
||||||
|
if (!stmt)
|
||||||
|
return null;
|
||||||
|
finallyStatements.push(<Statement>stmt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!(catchStatements || finallyStatements)) {
|
||||||
|
this.error(DiagnosticCode._0_expected, tn.range(), "catch");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const ret: TryStatement = Statement.createTry(statements, catchVariable, catchStatements, finallyStatements, Range.join(startRange, tn.range()));
|
||||||
tn.skip(Token.SEMICOLON);
|
tn.skip(Token.SEMICOLON);
|
||||||
return ret;
|
return ret;
|
||||||
} else
|
} else
|
||||||
this.error(DiagnosticCode._0_expected, tn.range(), "{");
|
this.error(DiagnosticCode._0_expected, tn.range(), "{");
|
||||||
} else
|
|
||||||
this.error(DiagnosticCode._0_expected, tn.range(), ")");
|
|
||||||
} else
|
|
||||||
this.error(DiagnosticCode._0_expected, tn.range(), "(");
|
|
||||||
} else
|
|
||||||
this.error(DiagnosticCode._0_expected, tn.range(), "catch");
|
|
||||||
} else
|
|
||||||
this.error(DiagnosticCode._0_expected, tn.range(), "{");
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1164,12 +1191,12 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
const token: Token = tn.next();
|
const token: Token = tn.next();
|
||||||
const startPos: i32 = tn.tokenPos;
|
const startPos: i32 = tn.tokenPos;
|
||||||
|
|
||||||
if (token == Token.FALSE)
|
|
||||||
return Expression.createIdentifier("false", tn.range());
|
|
||||||
if (token == Token.NULL)
|
if (token == Token.NULL)
|
||||||
return Expression.createIdentifier("null", tn.range());
|
return Expression.createNull(tn.range());
|
||||||
if (token == Token.TRUE)
|
if (token == Token.TRUE)
|
||||||
return Expression.createIdentifier("true", tn.range());
|
return Expression.createTrue(tn.range());
|
||||||
|
if (token == Token.FALSE)
|
||||||
|
return Expression.createFalse(tn.range());
|
||||||
|
|
||||||
let p: Precedence = determinePrecedencePrefix(token);
|
let p: Precedence = determinePrecedencePrefix(token);
|
||||||
if (p != Precedence.INVALID) {
|
if (p != Precedence.INVALID) {
|
||||||
@ -1262,6 +1289,10 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
return Expression.createAssertion(AssertionKind.PREFIX, <Expression>expr, <TypeNode>toType, tn.range(startPos, tn.pos));
|
return Expression.createAssertion(AssertionKind.PREFIX, <Expression>expr, <TypeNode>toType, tn.range(startPos, tn.pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IdentifierExpression
|
||||||
|
case Token.IDENTIFIER:
|
||||||
|
return Expression.createIdentifier(tn.readIdentifier(), tn.range(startPos, tn.pos));
|
||||||
|
|
||||||
// StringLiteralExpression
|
// StringLiteralExpression
|
||||||
case Token.STRINGLITERAL:
|
case Token.STRINGLITERAL:
|
||||||
return Expression.createStringLiteral(tn.readString(), tn.range(startPos, tn.pos));
|
return Expression.createStringLiteral(tn.readString(), tn.range(startPos, tn.pos));
|
||||||
@ -1278,10 +1309,6 @@ export class Parser extends DiagnosticEmitter {
|
|||||||
case Token.REGEXPLITERAL:
|
case Token.REGEXPLITERAL:
|
||||||
return Expression.createRegexpLiteral(tn.readRegexp(), tn.range(startPos, tn.pos));
|
return Expression.createRegexpLiteral(tn.readRegexp(), tn.range(startPos, tn.pos));
|
||||||
|
|
||||||
// IdentifierExpression
|
|
||||||
case Token.IDENTIFIER:
|
|
||||||
return Expression.createIdentifier(tn.readIdentifier(), tn.range(startPos, tn.pos));
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
this.error(DiagnosticCode.Expression_expected, tn.range());
|
this.error(DiagnosticCode.Expression_expected, tn.range());
|
||||||
return null;
|
return null;
|
||||||
|
@ -39,6 +39,8 @@ class QueuedImport {
|
|||||||
declaration: ImportDeclaration;
|
declaration: ImportDeclaration;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const typesStub: Map<string,Type> = new Map();
|
||||||
|
|
||||||
export class Program extends DiagnosticEmitter {
|
export class Program extends DiagnosticEmitter {
|
||||||
|
|
||||||
sources: Source[];
|
sources: Source[];
|
||||||
@ -48,7 +50,7 @@ export class Program extends DiagnosticEmitter {
|
|||||||
/** Internal map of names to declarations. */
|
/** Internal map of names to declarations. */
|
||||||
names: Map<string,DeclarationStatement> = new Map();
|
names: Map<string,DeclarationStatement> = new Map();
|
||||||
/** Separate map of internal type names to declarations. */
|
/** Separate map of internal type names to declarations. */
|
||||||
types: Map<string,Type> = new Map();
|
types: Map<string,Type> = typesStub;
|
||||||
/** Separate map of internal export names to declarations. */
|
/** Separate map of internal export names to declarations. */
|
||||||
exports: Map<string,DeclarationStatement> = new Map();
|
exports: Map<string,DeclarationStatement> = new Map();
|
||||||
|
|
||||||
@ -59,8 +61,22 @@ export class Program extends DiagnosticEmitter {
|
|||||||
|
|
||||||
initialize(target: Target): void {
|
initialize(target: Target): void {
|
||||||
this.target = target;
|
this.target = target;
|
||||||
|
this.types = new Map([
|
||||||
initializeBasicTypes(this.types, target);
|
["i8", Type.i8],
|
||||||
|
["i16", Type.i16],
|
||||||
|
["i32", Type.i32],
|
||||||
|
["i64", Type.i64],
|
||||||
|
["isize", target == Target.WASM64 ? Type.isize64 : Type.isize32],
|
||||||
|
["u8", Type.u8],
|
||||||
|
["u16", Type.u16],
|
||||||
|
["u32", Type.u32],
|
||||||
|
["u64", Type.u64],
|
||||||
|
["usize", target == Target.WASM64 ? Type.usize64 : Type.usize32],
|
||||||
|
["bool", Type.bool],
|
||||||
|
["f32", Type.f32],
|
||||||
|
["f64", Type.f64],
|
||||||
|
["void", Type.void]
|
||||||
|
]);
|
||||||
|
|
||||||
const queuedExports: Map<string,QueuedExport> = new Map();
|
const queuedExports: Map<string,QueuedExport> = new Map();
|
||||||
const queuedImports: QueuedImport[] = new Array();
|
const queuedImports: QueuedImport[] = new Array();
|
||||||
@ -127,8 +143,8 @@ export class Program extends DiagnosticEmitter {
|
|||||||
for (let i: i32 = 0, k: i32 = queuedImports.length; i < k; ++i) {
|
for (let i: i32 = 0, k: i32 = queuedImports.length; i < k; ++i) {
|
||||||
const queuedImport: QueuedImport = queuedImports[i];
|
const queuedImport: QueuedImport = queuedImports[i];
|
||||||
const internalName: string = queuedImport.internalName;
|
const internalName: string = queuedImport.internalName;
|
||||||
let importName: string = queuedImport.importName;
|
|
||||||
const seen: Set<QueuedExport> = new Set();
|
const seen: Set<QueuedExport> = new Set();
|
||||||
|
let importName: string = queuedImport.importName;
|
||||||
while (queuedExports.has(importName)) {
|
while (queuedExports.has(importName)) {
|
||||||
const queuedExport: QueuedExport = <QueuedExport>queuedExports.get(importName);
|
const queuedExport: QueuedExport = <QueuedExport>queuedExports.get(importName);
|
||||||
importName = queuedExport.importName;
|
importName = queuedExport.importName;
|
||||||
@ -327,7 +343,7 @@ export class Program extends DiagnosticEmitter {
|
|||||||
private initializeVariables(statement: VariableStatement, isNamespaceMember: bool = false): void {
|
private initializeVariables(statement: VariableStatement, isNamespaceMember: bool = false): void {
|
||||||
const declarations: VariableDeclaration[] = statement.declarations;
|
const declarations: VariableDeclaration[] = statement.declarations;
|
||||||
const isExport: bool = !isNamespaceMember && hasModifier(ModifierKind.EXPORT, statement.modifiers);
|
const isExport: bool = !isNamespaceMember && hasModifier(ModifierKind.EXPORT, statement.modifiers);
|
||||||
for (let i: i32 = 0, k = declarations.length; i < k; ++i) {
|
for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i) {
|
||||||
const declaration: VariableDeclaration = declarations[i];
|
const declaration: VariableDeclaration = declarations[i];
|
||||||
const internalName: string = this.mangleInternalName(declaration);
|
const internalName: string = this.mangleInternalName(declaration);
|
||||||
this.addName(internalName, declaration);
|
this.addName(internalName, declaration);
|
||||||
@ -394,20 +410,3 @@ export class Program extends DiagnosticEmitter {
|
|||||||
throw new Error("unexpected parent");
|
throw new Error("unexpected parent");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeBasicTypes(types: Map<string,Type>, target: Target): void {
|
|
||||||
types.set("i8", Type.i8);
|
|
||||||
types.set("i16", Type.i16);
|
|
||||||
types.set("i32", Type.i32);
|
|
||||||
types.set("i64", Type.i64);
|
|
||||||
types.set("isize", target == Target.WASM64 ? Type.isize64 : Type.isize32);
|
|
||||||
types.set("u8", Type.u8);
|
|
||||||
types.set("u16", Type.u16);
|
|
||||||
types.set("u32", Type.u32);
|
|
||||||
types.set("u64", Type.u64);
|
|
||||||
types.set("usize", target == Target.WASM64 ? Type.usize64 : Type.usize32);
|
|
||||||
types.set("bool", Type.bool);
|
|
||||||
types.set("f32", Type.f32);
|
|
||||||
types.set("f64", Type.f64);
|
|
||||||
types.set("void", Type.void);
|
|
||||||
}
|
|
||||||
|
@ -475,6 +475,9 @@ export class Tokenizer extends DiagnosticEmitter {
|
|||||||
case CharCode.SLASH:
|
case CharCode.SLASH:
|
||||||
if (++this.pos < this.end) {
|
if (++this.pos < this.end) {
|
||||||
if (text.charCodeAt(this.pos) == CharCode.SLASH) { // single-line comment
|
if (text.charCodeAt(this.pos) == CharCode.SLASH) { // single-line comment
|
||||||
|
if (this.pos + 1 < this.end && text.charCodeAt(this.pos + 1) == CharCode.SLASH) {
|
||||||
|
// TODO: triple-slash directives, i.e. '/// <reference path="some.d.ts" />'
|
||||||
|
}
|
||||||
while (++this.pos < this.end) {
|
while (++this.pos < this.end) {
|
||||||
if (isLineBreak(text.charCodeAt(this.pos)))
|
if (isLineBreak(text.charCodeAt(this.pos)))
|
||||||
break;
|
break;
|
||||||
@ -690,7 +693,7 @@ export class Tokenizer extends DiagnosticEmitter {
|
|||||||
const posBefore: i32 = this.pos;
|
const posBefore: i32 = this.pos;
|
||||||
const tokenBefore: Token = this.token;
|
const tokenBefore: Token = this.token;
|
||||||
const tokenPosBefore: i32 = this.tokenPos;
|
const tokenPosBefore: i32 = this.tokenPos;
|
||||||
if ((this.nextToken = this.unsafeNext(token == Token.IDENTIFIER)) == token) {
|
if ((this.token = this.unsafeNext(token == Token.IDENTIFIER)) == token) {
|
||||||
this.nextToken = -1;
|
this.nextToken = -1;
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -27,7 +27,6 @@
|
|||||||
"index.ts",
|
"index.ts",
|
||||||
"parser.ts",
|
"parser.ts",
|
||||||
"program.ts",
|
"program.ts",
|
||||||
"reflection.ts",
|
|
||||||
"tokenizer.ts",
|
"tokenizer.ts",
|
||||||
"types.ts",
|
"types.ts",
|
||||||
"util.ts",
|
"util.ts",
|
||||||
|
83
src/types.ts
83
src/types.ts
@ -1,3 +1,5 @@
|
|||||||
|
import { sb } from "./util";
|
||||||
|
|
||||||
export const enum TypeKind {
|
export const enum TypeKind {
|
||||||
|
|
||||||
// signed integers
|
// signed integers
|
||||||
@ -54,12 +56,14 @@ export class Type {
|
|||||||
}
|
}
|
||||||
|
|
||||||
asNullable(): Type {
|
asNullable(): Type {
|
||||||
|
if (this.kind != TypeKind.USIZE)
|
||||||
|
throw new Error("unexpected non-usize nullable");
|
||||||
if (!this.nullableType)
|
if (!this.nullableType)
|
||||||
(this.nullableType = new Type(this.kind, this.size)).nullable = true;
|
(this.nullableType = new Type(this.kind, this.size)).nullable = true;
|
||||||
return <Type>this.nullableType;
|
return <Type>this.nullableType;
|
||||||
}
|
}
|
||||||
|
|
||||||
toString(): string {
|
toString(kindOnly: bool = false): string {
|
||||||
switch (this.kind) {
|
switch (this.kind) {
|
||||||
case TypeKind.I8: return "i8";
|
case TypeKind.I8: return "i8";
|
||||||
case TypeKind.I16: return "i16";
|
case TypeKind.I16: return "i16";
|
||||||
@ -69,7 +73,7 @@ export class Type {
|
|||||||
case TypeKind.U16: return "u16";
|
case TypeKind.U16: return "u16";
|
||||||
case TypeKind.U32: return "u32";
|
case TypeKind.U32: return "u32";
|
||||||
case TypeKind.U64: return "u64";
|
case TypeKind.U64: return "u64";
|
||||||
case TypeKind.USIZE: return "usize";
|
case TypeKind.USIZE: return this.classType && !kindOnly ? this.classType.toString() : "usize";
|
||||||
case TypeKind.BOOL: return "bool";
|
case TypeKind.BOOL: return "bool";
|
||||||
case TypeKind.F32: return "f32";
|
case TypeKind.F32: return "f32";
|
||||||
case TypeKind.F64: return "f64";
|
case TypeKind.F64: return "f64";
|
||||||
@ -99,40 +103,99 @@ export class Type {
|
|||||||
|
|
||||||
export class FunctionType {
|
export class FunctionType {
|
||||||
|
|
||||||
returnType: Type;
|
typeArguments: Type[];
|
||||||
parameterTypes: Type[];
|
parameterTypes: Type[];
|
||||||
|
returnType: Type;
|
||||||
|
|
||||||
additionalLocals: Type[];
|
additionalLocals: Type[];
|
||||||
typeArgumentsMap: Map<string, Type> | null = null;
|
typeArgumentsMap: Map<string, Type> | null = null;
|
||||||
|
locals: Map<string, LocalType> = new Map();
|
||||||
|
breakContext: string | null = null;
|
||||||
|
|
||||||
private breakMajor: i32 = 0;
|
private breakMajor: i32 = 0;
|
||||||
private breakMinor: i32 = 0;
|
private breakMinor: i32 = 0;
|
||||||
|
|
||||||
constructor(returnType: Type, parameterTypes: Type[]) {
|
constructor(typeArguments: Type[], parameterTypes: Type[], returnType: Type, parameterNames: string[] | null = null) {
|
||||||
this.returnType = returnType;
|
this.typeArguments = typeArguments;
|
||||||
this.parameterTypes = parameterTypes;
|
this.parameterTypes = parameterTypes;
|
||||||
|
this.returnType = returnType;
|
||||||
this.additionalLocals = new Array();
|
this.additionalLocals = new Array();
|
||||||
|
if (parameterNames) {
|
||||||
|
if (parameterTypes.length != (<string[]>parameterNames).length)
|
||||||
|
throw new Error("unexpected parameter count mismatch");;
|
||||||
|
for (let i: i32 = 0, k: i32 = parameterTypes.length; i < k; ++i) {
|
||||||
|
const name: string = (<string[]>parameterNames)[i];
|
||||||
|
if (this.locals.has(name))
|
||||||
|
throw new Error("duplicate parameter name");
|
||||||
|
this.locals.set(name, new LocalType(i, parameterTypes[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enterBreakContext(): string {
|
enterBreakContext(): string {
|
||||||
if (!this.breakMinor)
|
if (!this.breakMinor)
|
||||||
this.breakMajor++;
|
this.breakMajor++;
|
||||||
return this.breakMajor.toString(10) + "." + (++this.breakMinor).toString(10);
|
return this.breakContext = this.breakMajor.toString(10) + "." + (++this.breakMinor).toString(10);
|
||||||
}
|
}
|
||||||
|
|
||||||
leaveBreakContext(): void {
|
leaveBreakContext(): void {
|
||||||
if (--this.breakMinor < 0)
|
if (--this.breakMinor < 0)
|
||||||
throw new Error("unexpected unbalanced break context");
|
throw new Error("unexpected unbalanced break context");
|
||||||
|
if (this.breakMinor == 0 && !--this.breakMajor)
|
||||||
|
this.breakContext = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
addLocal(type: Type, name: string | null = null): i32 {
|
||||||
|
// internal locals don't necessarily need names if referenced by index only
|
||||||
|
if (name && this.locals.has(<string>name))
|
||||||
|
throw new Error("duplicate local name");
|
||||||
|
const index: i32 = this.parameterTypes.length + this.additionalLocals.length;
|
||||||
|
this.additionalLocals.push(type);
|
||||||
|
if (name)
|
||||||
|
this.locals.set(<string>name, new LocalType(index, type));
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class LocalType {
|
||||||
|
|
||||||
|
index: i32;
|
||||||
|
type: Type;
|
||||||
|
|
||||||
|
constructor(index: i32, type: Type) {
|
||||||
|
this.index = index;
|
||||||
|
this.type = type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class ClassType {
|
export class ClassType {
|
||||||
|
|
||||||
type: Type;
|
name: string;
|
||||||
typeArgumentsMap: Map<string, Type> | null = null;
|
typeArguments: Type[];
|
||||||
base: ClassType | null;
|
base: ClassType | null;
|
||||||
|
|
||||||
constructor(usizeType: Type, base: ClassType | null = null) {
|
type: Type;
|
||||||
this.type = usizeType.asClass(this);
|
typeArgumentsMap: Map<string, Type> | null = null;
|
||||||
|
|
||||||
|
constructor(name: string, usizeType: Type, typeArguments: Type[], base: ClassType | null = null) {
|
||||||
|
this.name = name;
|
||||||
|
this.typeArguments = typeArguments;
|
||||||
this.base = base;
|
this.base = base;
|
||||||
|
this.type = usizeType.asClass(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
toString(): string {
|
||||||
|
let str: string = this.typeArguments.length ? this.name + typeArgumentsToString(this.typeArguments) : this.name;
|
||||||
|
return this.type.nullable ? str + " | null" : str;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function typeArgumentsToString(typeArguments: Type[]): string {
|
||||||
|
const k: i32 = typeArguments.length;
|
||||||
|
if (!k)
|
||||||
|
return "";
|
||||||
|
sb.length = 0;
|
||||||
|
for (let i: i32 = 0; i < k; ++i)
|
||||||
|
sb[i] = typeArguments[i].toString();
|
||||||
|
return "<" + sb.join(",") + ">";
|
||||||
|
}
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
export { I64, U64 } from "./util/i64";
|
|
||||||
export { CharCode, isLineBreak} from "./util/charcode";
|
export { CharCode, isLineBreak} from "./util/charcode";
|
||||||
|
|
||||||
|
export { I64, U64 } from "./util/i64";
|
||||||
|
|
||||||
export { normalize as normalizePath, resolve as resolvePath, dirname } from "./util/path";
|
export { normalize as normalizePath, resolve as resolvePath, dirname } from "./util/path";
|
||||||
|
|
||||||
export const sb: string[] = new Array(256); // shared string builder. 64-bit without growing: (4+4+8) + 8*256 = 16b + 2kb
|
export const sb: string[] = new Array(256); // shared string builder. 64-bit without growing: (4+4+8) + 8*256 = 16b + 2kb
|
||||||
|
@ -2,12 +2,18 @@ import "../src/glue/js";
|
|||||||
import { Compiler } from "../src/compiler";
|
import { Compiler } from "../src/compiler";
|
||||||
import { Parser } from "../src/parser";
|
import { Parser } from "../src/parser";
|
||||||
|
|
||||||
const files: Map<string,string> = new Map([
|
/* const files: Map<string,string> = new Map([
|
||||||
["main", `import { Test as TestAlias } from "./a"; export { TestAlias } from "./d"; if (1) {} export const a: i32 = 123;`],
|
["main", `import { Test as TestAlias } from "./a"; export { TestAlias } from "./d"; if (1) {} export const a: i32 = 123;`],
|
||||||
["a", `export { Test } from "./b";`],
|
["a", `export { Test } from "./b";`],
|
||||||
["b", `export { Test } from "./c";`],
|
["b", `export { Test } from "./c";`],
|
||||||
["c", `export enum Test { ONE = 1, TWO = 2 }`],
|
["c", `export enum Test { ONE = 1, TWO = 1 + 1 }`],
|
||||||
["d", `export { Test as TestAlias } from "./b";`]
|
["d", `export { Test as TestAlias } from "./b";`]
|
||||||
|
]); */
|
||||||
|
|
||||||
|
const files: Map<string,string> = new Map([
|
||||||
|
["main", `
|
||||||
|
export function add(a: i32, b: i32): i32 { let c: i32 = a + b; return c; }
|
||||||
|
`]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const parser = new Parser();
|
const parser = new Parser();
|
||||||
@ -27,8 +33,9 @@ const module = compiler.compile();
|
|||||||
console.log("names", program.names.keys());
|
console.log("names", program.names.keys());
|
||||||
console.log("exports", program.exports.keys());
|
console.log("exports", program.exports.keys());
|
||||||
|
|
||||||
// module.optimize();
|
module.optimize();
|
||||||
// module.validate(); // global initializers can't use i32.add etc. yet
|
// module.validate(); // global initializers can't use i32.add etc. yet
|
||||||
|
if (!module.noEmit)
|
||||||
_BinaryenModulePrint(module.ref);
|
_BinaryenModulePrint(module.ref);
|
||||||
|
|
||||||
/* console.log("--- statements ---");
|
/* console.log("--- statements ---");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user