Refactoring; Add tslint fwiw

This commit is contained in:
dcodeIO 2017-12-24 03:19:47 +01:00
parent d7c069b692
commit 4baff99125
15 changed files with 649 additions and 335 deletions

117
package-lock.json generated
View File

@ -57,7 +57,8 @@
"@types/node": { "@types/node": {
"version": "8.5.1", "version": "8.5.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.1.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.1.tgz",
"integrity": "sha512-SrmAO+NhnsuG/6TychSl2VdxBZiw/d6V+8j+DFo8O3PwFi+QeYXWHhAw+b170aSc6zYab6/PjEWRZHIDN9mNUw==" "integrity": "sha512-SrmAO+NhnsuG/6TychSl2VdxBZiw/d6V+8j+DFo8O3PwFi+QeYXWHhAw+b170aSc6zYab6/PjEWRZHIDN9mNUw==",
"dev": true
}, },
"@types/strip-bom": { "@types/strip-bom": {
"version": "3.0.0", "version": "3.0.0",
@ -202,6 +203,44 @@
"integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=",
"dev": true "dev": true
}, },
"babel-code-frame": {
"version": "6.26.0",
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
"dev": true,
"requires": {
"chalk": "1.1.3",
"esutils": "2.0.2",
"js-tokens": "3.0.2"
},
"dependencies": {
"ansi-styles": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
"dev": true
},
"chalk": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
"dev": true,
"requires": {
"ansi-styles": "2.2.1",
"escape-string-regexp": "1.0.5",
"has-ansi": "2.0.0",
"strip-ansi": "3.0.1",
"supports-color": "2.0.0"
}
},
"supports-color": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
"dev": true
}
}
},
"balanced-match": { "balanced-match": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
@ -441,6 +480,12 @@
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
"dev": true "dev": true
}, },
"commander": {
"version": "2.12.2",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz",
"integrity": "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA==",
"dev": true
},
"concat-map": { "concat-map": {
"version": "0.0.1", "version": "0.0.1",
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
@ -742,6 +787,12 @@
"integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
"dev": true "dev": true
}, },
"esutils": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
"integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
"dev": true
},
"event-emitter": { "event-emitter": {
"version": "0.3.5", "version": "0.3.5",
"resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
@ -920,6 +971,15 @@
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"dev": true "dev": true
}, },
"has-ansi": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
"dev": true,
"requires": {
"ansi-regex": "2.1.1"
}
},
"has-flag": { "has-flag": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz",
@ -1138,6 +1198,12 @@
"isarray": "1.0.0" "isarray": "1.0.0"
} }
}, },
"js-tokens": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
"dev": true
},
"json-loader": { "json-loader": {
"version": "0.5.7", "version": "0.5.7",
"resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz",
@ -1593,6 +1659,12 @@
"integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
"dev": true "dev": true
}, },
"path-parse": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
"integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=",
"dev": true
},
"path-type": { "path-type": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz",
@ -1829,6 +1901,15 @@
"integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
"dev": true "dev": true
}, },
"resolve": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz",
"integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==",
"dev": true,
"requires": {
"path-parse": "1.0.5"
}
},
"right-align": { "right-align": {
"version": "0.1.3", "version": "0.1.3",
"resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
@ -2112,6 +2193,40 @@
"strip-json-comments": "2.0.1" "strip-json-comments": "2.0.1"
} }
}, },
"tslib": {
"version": "1.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.8.1.tgz",
"integrity": "sha1-aUavLR1lGnsYY7Ux1uWvpBqkTqw=",
"dev": true
},
"tslint": {
"version": "5.8.0",
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.8.0.tgz",
"integrity": "sha1-H0mtWy53x2w69N3K5VKuTjYS6xM=",
"dev": true,
"requires": {
"babel-code-frame": "6.26.0",
"builtin-modules": "1.1.1",
"chalk": "2.3.0",
"commander": "2.12.2",
"diff": "3.4.0",
"glob": "7.1.2",
"minimatch": "3.0.4",
"resolve": "1.5.0",
"semver": "5.4.1",
"tslib": "1.8.1",
"tsutils": "2.14.0"
}
},
"tsutils": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.14.0.tgz",
"integrity": "sha512-f6axSMV0RoUufiKiRQgmRlN1c+Ag+mDaZjcd6bHdvplT/zyhuMCGqw3pJS8s3+0x4EVkdoQajs9PchdDZlguvw==",
"dev": true,
"requires": {
"tslib": "1.8.1"
}
},
"tty-browserify": { "tty-browserify": {
"version": "0.0.0", "version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",

View File

@ -28,6 +28,7 @@
"long": "^3.2.0", "long": "^3.2.0",
"ts-loader": "^3.2.0", "ts-loader": "^3.2.0",
"ts-node": "^4.0.2", "ts-node": "^4.0.2",
"tslint": "^5.8.0",
"typescript": "^2.6.2", "typescript": "^2.6.2",
"webpack": "^3.10.0" "webpack": "^3.10.0"
}, },
@ -45,7 +46,8 @@
"test:config:src": "tsc --noEmit -p src --diagnostics --listFiles", "test:config:src": "tsc --noEmit -p src --diagnostics --listFiles",
"test:parser": "node tests/parser", "test:parser": "node tests/parser",
"test:compiler": "node tests/compiler", "test:compiler": "node tests/compiler",
"test": "npm run test:config --scripts-prepend-node-path && npm run test:parser --scripts-prepend-node-path && npm run test:compiler --scripts-prepend-node-path" "test": "npm run test:config --scripts-prepend-node-path && npm run test:parser --scripts-prepend-node-path && npm run test:compiler --scripts-prepend-node-path",
"lint": "tslint --project src"
}, },
"files": [ "files": [
"bin/", "bin/",

View File

@ -1,8 +1,27 @@
import { GETTER_PREFIX, SETTER_PREFIX, PATH_DELIMITER, PARENT_SUBST, STATIC_DELIMITER, INSTANCE_DELIMITER } from "./constants"; import {
import { Token, Tokenizer, operatorTokenToString, Range } from "./tokenizer"; PATH_DELIMITER,
import { CharCode } from "./util/charcode"; STATIC_DELIMITER,
import { I64 } from "./util/i64"; INSTANCE_DELIMITER
import { normalize as normalizePath, resolve as resolvePath } from "./util/path"; } from "./constants";
import {
Token,
Tokenizer,
Range
} from "./tokenizer";
import{
CharCode
} from "./util/charcode";
import {
I64
} from "./util/i64";
import {
normalize as normalizePath,
resolve as resolvePath
} from "./util/path";
export { Range } from "./tokenizer"; export { Range } from "./tokenizer";
@ -489,7 +508,7 @@ export abstract class Node {
(stmt.name = identifier).parent = stmt; (stmt.name = identifier).parent = stmt;
for (i = 0, k = (stmt.typeParameters = typeParameters).length; i < k; ++i) typeParameters[i].parent = stmt; for (i = 0, k = (stmt.typeParameters = typeParameters).length; i < k; ++i) typeParameters[i].parent = stmt;
for (i = 0, k = (stmt.parameters = parameters).length; i < k; ++i) parameters[i].parent = stmt; for (i = 0, k = (stmt.parameters = parameters).length; i < k; ++i) parameters[i].parent = stmt;
if (stmt.returnType = returnType) (<TypeNode>returnType).parent = stmt;; if (stmt.returnType = returnType) (<TypeNode>returnType).parent = stmt;
if (stmt.statements = statements) for (i = 0, k = (<Statement[]>statements).length; i < k; ++i) (<Statement[]>statements)[i].parent = stmt; if (stmt.statements = statements) for (i = 0, k = (<Statement[]>statements).length; i < k; ++i) (<Statement[]>statements)[i].parent = stmt;
if (stmt.modifiers = modifiers) for (i = 0, k = (<Modifier[]>modifiers).length; i < k; ++i) (<Modifier[]>modifiers)[i].parent = stmt; if (stmt.modifiers = modifiers) for (i = 0, k = (<Modifier[]>modifiers).length; i < k; ++i) (<Modifier[]>modifiers)[i].parent = stmt;
if (stmt.decorators = decorators) for (i = 0, k = (<Decorator[]>decorators).length; i < k; ++i) (<Decorator[]>decorators)[i].parent = stmt; if (stmt.decorators = decorators) for (i = 0, k = (<Decorator[]>decorators).length; i < k; ++i) (<Decorator[]>decorators)[i].parent = stmt;
@ -750,7 +769,7 @@ export class BinaryExpression extends Expression {
serialize(sb: string[]): void { serialize(sb: string[]): void {
this.left.serialize(sb); this.left.serialize(sb);
sb.push(" "); sb.push(" ");
sb.push(operatorTokenToString(this.operator)); sb.push(Token.operatorToString(this.operator));
sb.push(" "); sb.push(" ");
this.right.serialize(sb); this.right.serialize(sb);
} }
@ -995,7 +1014,7 @@ export class UnaryPrefixExpression extends UnaryExpression {
kind = NodeKind.UNARYPREFIX; kind = NodeKind.UNARYPREFIX;
serialize(sb: string[]): void { serialize(sb: string[]): void {
sb.push(operatorTokenToString(this.operator)); sb.push(Token.operatorToString(this.operator));
this.operand.serialize(sb); this.operand.serialize(sb);
} }
} }

View File

@ -1,9 +1,38 @@
import { Compiler, Target, ConversionKind, typeToNativeType, typeToNativeOne, typeToNativeZero } from "./compiler"; import {
import { DiagnosticCode } from "./diagnostics"; Compiler,
import { Node, Expression, IdentifierExpression } from "./ast"; Target,
import { Type } from "./types"; ConversionKind
import { Module, ExpressionRef, UnaryOp, BinaryOp, HostOp, NativeType, FunctionTypeRef } from "./module"; } from "./compiler";
import { Program, ElementFlags, Element, Global, FunctionPrototype, Local } from "./program";
import {
DiagnosticCode
} from "./diagnostics";
import {
Node,
Expression
} from "./ast";
import {
Type
} from "./types";
import {
Module,
UnaryOp,
BinaryOp,
HostOp,
NativeType,
ExpressionRef,
FunctionTypeRef
} from "./module";
import {
Program,
Global,
FunctionPrototype,
Local
} from "./program";
/** Initializes the specified program with built-in functions. */ /** Initializes the specified program with built-in functions. */
export function initialize(program: Program): void { export function initialize(program: Program): void {
@ -149,7 +178,7 @@ export function compileGetGlobal(compiler: Compiler, global: Global): Expression
return compiler.module.createF64(Infinity); return compiler.module.createF64(Infinity);
case "HEAP_BASE": // constant, but never inlined case "HEAP_BASE": // constant, but never inlined
return compiler.module.createGetGlobal("HEAP_BASE", typeToNativeType(compiler.currentType = <Type>global.type)); return compiler.module.createGetGlobal("HEAP_BASE", (compiler.currentType = <Type>global.type).toNativeType());
default: default:
throw new Error("not implemented: " + global.internalName); throw new Error("not implemented: " + global.internalName);
@ -539,7 +568,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
return module.createUnreachable(); return module.createUnreachable();
arg0 = compiler.compileExpression(operands[0], usizeType); // reports arg0 = compiler.compileExpression(operands[0], usizeType); // reports
if ((compiler.currentType = typeArguments[0]) != Type.void) if ((compiler.currentType = typeArguments[0]) != Type.void)
return module.createLoad(typeArguments[0].byteSize, typeArguments[0].isSignedInteger, arg0, typeToNativeType(typeArguments[0])); return module.createLoad(typeArguments[0].byteSize, typeArguments[0].isSignedInteger, arg0, typeArguments[0].toNativeType());
break; break;
case "store": // store<T>(offset: usize, value: T) -> void case "store": // store<T>(offset: usize, value: T) -> void
@ -550,7 +579,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
arg1 = compiler.compileExpression(operands[1], typeArguments[0]); // reports arg1 = compiler.compileExpression(operands[1], typeArguments[0]); // reports
compiler.currentType = Type.void; compiler.currentType = Type.void;
if (typeArguments[0] != Type.void) if (typeArguments[0] != Type.void)
return module.createStore(typeArguments[0].byteSize, arg0, arg1, typeToNativeType(typeArguments[0])); return module.createStore(typeArguments[0].byteSize, arg0, arg1, typeArguments[0].toNativeType());
break; break;
case "sizeof": // sizeof<T>() -> usize case "sizeof": // sizeof<T>() -> usize
@ -685,7 +714,7 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
return module.createUnreachable(); return module.createUnreachable();
} }
arg0 = compiler.compileExpression(operands[0], Type.i32); // reports arg0 = compiler.compileExpression(operands[0], Type.i32); // reports
arg1 = operands.length > 1 ? compiler.compileExpression(operands[1], usizeType) : typeToNativeZero(module, usizeType); // TODO: string type arg1 = operands.length > 1 ? compiler.compileExpression(operands[1], usizeType) : usizeType.toNativeZero(module); // TODO: string type
compiler.currentType = Type.void; compiler.currentType = Type.void;
return compiler.options.noAssert return compiler.options.noAssert
? module.createNop() ? module.createNop()

View File

@ -1,8 +1,18 @@
import { compileCall as compileBuiltinCall, compileGetGlobal as compileBuiltinGetGlobal, initialize } from "./builtins";
import { PATH_DELIMITER } from "./constants";
import { DiagnosticCode, DiagnosticEmitter } from "./diagnostics";
import { import {
compileCall as compileBuiltinCall,
compileGetGlobal as compileBuiltinGetGlobal
} from "./builtins";
import {
PATH_DELIMITER
} from "./constants";
import {
DiagnosticCode,
DiagnosticEmitter
} from "./diagnostics";
import {
Module, Module,
MemorySegment, MemorySegment,
ExpressionRef, ExpressionRef,
@ -12,15 +22,14 @@ import {
FunctionTypeRef, FunctionTypeRef,
FunctionRef, FunctionRef,
ExpressionId ExpressionId
} from "./module"; } from "./module";
import {
import {
Program, Program,
ClassPrototype, ClassPrototype,
Class, Element, Class,
Element,
ElementKind, ElementKind,
ElementFlags,
Enum, Enum,
FunctionPrototype, FunctionPrototype,
Function, Function,
@ -29,17 +38,17 @@ import {
Namespace, Namespace,
Parameter, Parameter,
EnumValue EnumValue
} from "./program"; } from "./program";
import { Token } from "./tokenizer";
import {
import {
Token
} from "./tokenizer";
import {
Node, Node,
NodeKind, NodeKind,
TypeNode, TypeNode,
TypeParameter,
Source, Source,
// statements // statements
BlockStatement, BlockStatement,
BreakStatement, BreakStatement,
@ -53,13 +62,11 @@ import {
ExportMember, ExportMember,
ExportStatement, ExportStatement,
ExpressionStatement, ExpressionStatement,
FieldDeclaration,
FunctionDeclaration, FunctionDeclaration,
ForStatement, ForStatement,
IfStatement, IfStatement,
ImportStatement, ImportStatement,
InterfaceDeclaration, InterfaceDeclaration,
MethodDeclaration,
ModifierKind, ModifierKind,
NamespaceDeclaration, NamespaceDeclaration,
ReturnStatement, ReturnStatement,
@ -72,9 +79,7 @@ import {
VariableDeclaration, VariableDeclaration,
VariableStatement, VariableStatement,
WhileStatement, WhileStatement,
// expressions // expressions
ArrayLiteralExpression,
AssertionExpression, AssertionExpression,
BinaryExpression, BinaryExpression,
CallExpression, CallExpression,
@ -92,19 +97,24 @@ import {
StringLiteralExpression, StringLiteralExpression,
UnaryPostfixExpression, UnaryPostfixExpression,
UnaryPrefixExpression, UnaryPrefixExpression,
// utility // utility
hasModifier hasModifier
} from "./ast"; } from "./ast";
import {
import {
Type, Type,
TypeKind, TypeKind,
typesToNativeTypes
} from "./types"; } from "./types";
import { I64, U64 } from "./util/i64";
import { sb } from "./util/sb"; import {
I64,
U64
} from "./util/i64";
import {
sb
} from "./util/sb";
/** Compilation target. */ /** Compilation target. */
export enum Target { export enum Target {
@ -331,7 +341,6 @@ export class Compiler extends DiagnosticEmitter {
return true; return true;
const declaration: VariableLikeDeclarationStatement | null = global.declaration; const declaration: VariableLikeDeclarationStatement | null = global.declaration;
let type: Type | null = null;
let initExpr: ExpressionRef = 0; let initExpr: ExpressionRef = 0;
if (!global.type) { // infer type if (!global.type) { // infer type
@ -353,7 +362,7 @@ export class Compiler extends DiagnosticEmitter {
throw new Error("declaration expected"); throw new Error("declaration expected");
} }
const nativeType: NativeType = typeToNativeType(global.type); const nativeType: NativeType = global.type.toNativeType();
let initializeInStart: bool = false; let initializeInStart: bool = false;
if (global.hasConstantValue) { if (global.hasConstantValue) {
@ -386,13 +395,13 @@ export class Compiler extends DiagnosticEmitter {
initializeInStart = true; initializeInStart = true;
} }
} else } else
initExpr = typeToNativeZero(this.module, global.type); initExpr = global.type.toNativeZero(this.module);
} else } else
throw new Error("declaration expected"); throw new Error("declaration expected");
const internalName: string = global.internalName; const internalName: string = global.internalName;
if (initializeInStart) { if (initializeInStart) {
this.module.addGlobal(internalName, nativeType, true, typeToNativeZero(this.module, global.type)); this.module.addGlobal(internalName, nativeType, true, global.type.toNativeZero(this.module));
const setExpr: ExpressionRef = this.module.createSetGlobal(internalName, initExpr); const setExpr: ExpressionRef = this.module.createSetGlobal(internalName, initExpr);
if (!this.module.noEmit) if (!this.module.noEmit)
this.startFunctionBody.push(setExpr); this.startFunctionBody.push(setExpr);
@ -547,14 +556,14 @@ export class Compiler extends DiagnosticEmitter {
// create the function type // create the function type
let k: i32 = instance.parameters.length; let k: i32 = instance.parameters.length;
const nativeResultType: NativeType = typeToNativeType(instance.returnType); const nativeResultType: NativeType = instance.returnType.toNativeType();
const nativeParamTypes: NativeType[] = new Array(k); const nativeParamTypes: NativeType[] = new Array(k);
const signatureNameParts: string[] = new Array(k + 1); const signatureNameParts: string[] = new Array(k + 1);
for (let i: i32 = 0; i < k; ++i) { for (let i: i32 = 0; i < k; ++i) {
nativeParamTypes[i] = typeToNativeType(instance.parameters[i].type); nativeParamTypes[i] = instance.parameters[i].type.toNativeType();
signatureNameParts[i] = typeToSignatureNamePart(instance.parameters[i].type); signatureNameParts[i] = instance.parameters[i].type.toSignatureName();
} }
signatureNameParts[k] = typeToSignatureNamePart(instance.returnType); signatureNameParts[k] = instance.returnType.toSignatureName();
let typeRef: FunctionTypeRef = this.module.getFunctionTypeBySignature(nativeResultType, nativeParamTypes); let typeRef: FunctionTypeRef = this.module.getFunctionTypeBySignature(nativeResultType, nativeParamTypes);
if (!typeRef) if (!typeRef)
typeRef = this.module.addFunctionType(signatureNameParts.join(""), nativeResultType, nativeParamTypes); typeRef = this.module.addFunctionType(signatureNameParts.join(""), nativeResultType, nativeParamTypes);
@ -1101,10 +1110,10 @@ export class Compiler extends DiagnosticEmitter {
} }
precomputeExpressionRef(expr: ExpressionRef): ExpressionRef { precomputeExpressionRef(expr: ExpressionRef): ExpressionRef {
const nativeType: NativeType = typeToNativeType(this.currentType); const nativeType: NativeType = this.currentType.toNativeType();
let typeRef: FunctionTypeRef = this.module.getFunctionTypeBySignature(nativeType, []); let typeRef: FunctionTypeRef = this.module.getFunctionTypeBySignature(nativeType, []);
if (!typeRef) if (!typeRef)
typeRef = this.module.addFunctionType(typeToSignatureNamePart(this.currentType), nativeType, []); typeRef = this.module.addFunctionType(this.currentType.toSignatureName(), nativeType, []);
const funcRef: FunctionRef = this.module.addFunction("__precompute", typeRef, [], expr); const funcRef: FunctionRef = this.module.addFunction("__precompute", typeRef, [], expr);
this.module.runPasses([ "precompute" ], funcRef); this.module.runPasses([ "precompute" ], funcRef);
const ret: ExpressionRef = _BinaryenFunctionGetBody(funcRef); const ret: ExpressionRef = _BinaryenFunctionGetBody(funcRef);
@ -1564,7 +1573,7 @@ export class Compiler extends DiagnosticEmitter {
? this.module.createBinary(BinaryOp.NeF32, condition, this.module.createF32(0)) ? this.module.createBinary(BinaryOp.NeF32, condition, this.module.createF32(0))
: this.module.createTeeLocal(tempLocal.index, left), : this.module.createTeeLocal(tempLocal.index, left),
right, right,
this.module.createGetLocal(tempLocal.index, typeToNativeType(tempLocal.type)) this.module.createGetLocal(tempLocal.index, tempLocal.type.toNativeType())
); );
case Token.BAR_BAR: // left || right case Token.BAR_BAR: // left || right
@ -1596,7 +1605,7 @@ export class Compiler extends DiagnosticEmitter {
: this.currentType == Type.f32 : this.currentType == Type.f32
? this.module.createBinary(BinaryOp.NeF32, condition, this.module.createF32(0)) ? this.module.createBinary(BinaryOp.NeF32, condition, this.module.createF32(0))
: this.module.createTeeLocal(tempLocal.index, left), : this.module.createTeeLocal(tempLocal.index, left),
this.module.createGetLocal(tempLocal.index, typeToNativeType(tempLocal.type)), this.module.createGetLocal(tempLocal.index, tempLocal.type.toNativeType()),
right right
); );
@ -1665,7 +1674,7 @@ export class Compiler extends DiagnosticEmitter {
return this.module.createUnreachable(); return this.module.createUnreachable();
} }
if (tee) { if (tee) {
const globalNativeType: NativeType = typeToNativeType(<Type>(<Global>element).type); const globalNativeType: NativeType = (<Type>(<Global>element).type).toNativeType();
return this.module.createBlock(null, [ // teeGlobal return this.module.createBlock(null, [ // teeGlobal
this.module.createSetGlobal((<Global>element).internalName, valueWithCorrectType), this.module.createSetGlobal((<Global>element).internalName, valueWithCorrectType),
this.module.createGetGlobal((<Global>element).internalName, globalNativeType) this.module.createGetGlobal((<Global>element).internalName, globalNativeType)
@ -1724,7 +1733,6 @@ export class Compiler extends DiagnosticEmitter {
/** Compiles a call to a function. If an instance method, `this` is the first element in `argumentExpressions`. */ /** Compiles a call to a function. If an instance method, `this` is the first element in `argumentExpressions`. */
compileCall(functionInstance: Function, argumentExpressions: Expression[], reportNode: Node): ExpressionRef { compileCall(functionInstance: Function, argumentExpressions: Expression[], reportNode: Node): ExpressionRef {
const previousType: Type = this.currentType;
// validate and compile arguments // validate and compile arguments
const parameters: Parameter[] = functionInstance.parameters; const parameters: Parameter[] = functionInstance.parameters;
@ -1765,10 +1773,10 @@ export class Compiler extends DiagnosticEmitter {
// imported function // imported function
if (functionInstance.isDeclared) if (functionInstance.isDeclared)
return this.module.createCallImport(functionInstance.internalName, operands, typeToNativeType(functionInstance.returnType)); return this.module.createCallImport(functionInstance.internalName, operands, functionInstance.returnType.toNativeType());
// internal function // internal function
return this.module.createCall(functionInstance.internalName, operands, typeToNativeType(functionInstance.returnType)); return this.module.createCall(functionInstance.internalName, operands, functionInstance.returnType.toNativeType());
} }
compileElementAccessExpression(expression: ElementAccessExpression, contextualType: Type): ExpressionRef { compileElementAccessExpression(expression: ElementAccessExpression, contextualType: Type): ExpressionRef {
@ -1820,7 +1828,7 @@ export class Compiler extends DiagnosticEmitter {
// local // local
if (element.kind == ElementKind.LOCAL) { if (element.kind == ElementKind.LOCAL) {
this.currentType = (<Local>element).type; this.currentType = (<Local>element).type;
return this.module.createGetLocal((<Local>element).index, typeToNativeType(this.currentType)); return this.module.createGetLocal((<Local>element).index, this.currentType.toNativeType());
} }
// global // global
@ -1844,7 +1852,7 @@ export class Compiler extends DiagnosticEmitter {
else else
throw new Error("unexpected global type"); throw new Error("unexpected global type");
} else } else
return this.module.createGetGlobal((<Global>element).internalName, typeToNativeType(this.currentType)); return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType());
} }
// field // field
@ -1947,7 +1955,6 @@ export class Compiler extends DiagnosticEmitter {
// look up the property within the target to obtain the actual element // look up the property within the target to obtain the actual element
let element: Element | null; let element: Element | null;
let expr: ExpressionRef;
switch (target.kind) { switch (target.kind) {
case ElementKind.LOCAL: case ElementKind.LOCAL:
@ -1996,7 +2003,7 @@ export class Compiler extends DiagnosticEmitter {
switch (element.kind) { switch (element.kind) {
case ElementKind.LOCAL: case ElementKind.LOCAL:
return this.module.createGetLocal((<Local>element).index, typeToNativeType(this.currentType = (<Local>element).type)); return this.module.createGetLocal((<Local>element).index, (this.currentType = (<Local>element).type).toNativeType());
case ElementKind.GLOBAL: case ElementKind.GLOBAL:
if (!this.compileGlobal(<Global>element)) if (!this.compileGlobal(<Global>element))
@ -2010,7 +2017,7 @@ export class Compiler extends DiagnosticEmitter {
: this.currentType.isLongInteger : this.currentType.isLongInteger
? this.module.createI64((<I64>(<Global>element).constantIntegerValue).lo, (<I64>(<Global>element).constantIntegerValue).hi) ? this.module.createI64((<I64>(<Global>element).constantIntegerValue).lo, (<I64>(<Global>element).constantIntegerValue).hi)
: this.module.createI32((<I64>(<Global>element).constantIntegerValue).lo); : this.module.createI32((<I64>(<Global>element).constantIntegerValue).lo);
return this.module.createGetGlobal((<Global>element).internalName, typeToNativeType(this.currentType)); return this.module.createGetGlobal((<Global>element).internalName, this.currentType.toNativeType());
case ElementKind.FUNCTION: // getter case ElementKind.FUNCTION: // getter
if (!(<Function>element).prototype.isGetter) { if (!(<Function>element).prototype.isGetter) {
@ -2157,66 +2164,6 @@ export class Compiler extends DiagnosticEmitter {
// helpers // helpers
export function typeToNativeType(type: Type): NativeType {
return type.kind == TypeKind.F32
? NativeType.F32
: type.kind == TypeKind.F64
? NativeType.F64
: type.isLongInteger
? NativeType.I64
: type.isAnyInteger || type.kind == TypeKind.BOOL
? NativeType.I32
: NativeType.None;
}
export function typesToNativeTypes(types: Type[]): NativeType[] {
const k: i32 = types.length;
const ret: NativeType[] = new Array(k);
for (let i: i32 = 0; i < k; ++i)
ret[i] = typeToNativeType(types[i]);
return ret;
}
export function typeToNativeZero(module: Module, type: Type): ExpressionRef {
return type.kind == TypeKind.F32
? module.createF32(0)
: type.kind == TypeKind.F64
? module.createF64(0)
: type.isLongInteger
? module.createI64(0, 0)
: module.createI32(0);
}
export function typeToNativeOne(module: Module, type: Type): ExpressionRef {
return type.kind == TypeKind.F32
? module.createF32(1)
: type.kind == TypeKind.F64
? module.createF64(1)
: type.isLongInteger
? module.createI64(1, 0)
: module.createI32(1);
}
function typeToSignatureNamePart(type: Type): string {
return type.kind == TypeKind.VOID
? "v"
: type.kind == TypeKind.F32
? "f"
: type.kind == TypeKind.F64
? "F"
: type.isLongInteger
? "I"
: "i";
}
function typesToSignatureName(paramTypes: Type[], returnType: Type): string {
sb.length = 0;
for (let i: i32 = 0, k: i32 = paramTypes.length; i < k; ++i)
sb.push(typeToSignatureNamePart(paramTypes[i]));
sb.push(typeToSignatureNamePart(returnType));
return sb.join("");
}
function isModuleExport(element: Element, declaration: DeclarationStatement): bool { function isModuleExport(element: Element, declaration: DeclarationStatement): bool {
if (!element.isExported) if (!element.isExported)
return false; return false;

View File

@ -1,20 +1,19 @@
import { import {
Module, Module,
NativeType, NativeType,
ExpressionId, ExpressionId,
UnaryOp, UnaryOp,
BinaryOp, BinaryOp,
HostOp, HostOp,
FunctionTypeRef,
FunctionRef, FunctionRef,
ExpressionRef, ExpressionRef,
Index, Index,
readString readString
} from "./module"; } from "./module";
import { I64 } from "./util/i64";
import {
I64
} from "./util/i64";
// TODO :-) // TODO :-)
@ -40,7 +39,7 @@ export class Decompiler {
} }
decompileFunction(func: FunctionRef): void { decompileFunction(func: FunctionRef): void {
const name: string = readString(_BinaryenFunctionGetName(func)) || "$" + this.functionId.toString(10) const name: string = readString(_BinaryenFunctionGetName(func)) || "$" + this.functionId.toString(10);
const body: ExpressionRef = _BinaryenFunctionGetBody(func); const body: ExpressionRef = _BinaryenFunctionGetBody(func);
this.push("function "); this.push("function ");
this.push(name); this.push(name);
@ -560,7 +559,7 @@ export class Decompiler {
return; return;
case BinaryOp.RotlI32: case BinaryOp.RotlI32:
this.push("rotl<i32>(") this.push("rotl<i32>(");
this.decompileExpression(_BinaryenBinaryGetLeft(expr)); this.decompileExpression(_BinaryenBinaryGetLeft(expr));
this.push(", "); this.push(", ");
this.decompileExpression(_BinaryenBinaryGetRight(expr)); this.decompileExpression(_BinaryenBinaryGetRight(expr));
@ -568,7 +567,7 @@ export class Decompiler {
return; return;
case BinaryOp.RotrI32: case BinaryOp.RotrI32:
this.push("rotr<i32>(") this.push("rotr<i32>(");
this.decompileExpression(_BinaryenBinaryGetLeft(expr)); this.decompileExpression(_BinaryenBinaryGetLeft(expr));
this.push(", "); this.push(", ");
this.decompileExpression(_BinaryenBinaryGetRight(expr)); this.decompileExpression(_BinaryenBinaryGetRight(expr));
@ -821,7 +820,7 @@ export class Decompiler {
case ExpressionId.AtomicWake: case ExpressionId.AtomicWake:
} }
throw new Error("not implemented: " + id); throw new Error("not implemented");
} }
private push(text: string): void { private push(text: string): void {

View File

@ -1,9 +1,25 @@
import { Range } from "./ast"; import {
import { DiagnosticCode, diagnosticCodeToString } from "./diagnosticMessages.generated"; Range
import { CharCode, isLineBreak } from "./util/charcode"; } from "./ast";
import { sb } from "./util/sb";
export { DiagnosticCode, diagnosticCodeToString } from "./diagnosticMessages.generated"; import {
DiagnosticCode,
diagnosticCodeToString
} from "./diagnosticMessages.generated";
import {
CharCode,
isLineBreak
} from "./util/charcode";
import {
sb
} from "./util/sb";
export {
DiagnosticCode,
diagnosticCodeToString
} from "./diagnosticMessages.generated";
export enum DiagnosticCategory { export enum DiagnosticCategory {
INFO, INFO,
@ -75,8 +91,8 @@ export class DiagnosticMessage {
toString(): string { toString(): string {
if (this.range) if (this.range)
return diagnosticCategoryToString(this.category) + " " + this.code + ": \"" + this.message + "\" in " + this.range.source.path + " @ " + this.range.start + "," + this.range.end; return diagnosticCategoryToString(this.category) + " " + this.code.toString(10) + ": \"" + this.message + "\" in " + this.range.source.path + " @ " + this.range.start.toString(10) + "," + this.range.end.toString(10);
return diagnosticCategoryToString(this.category) + " " + this.code + ": " + this.message; return diagnosticCategoryToString(this.category) + " " + this.code.toString(10) + ": " + this.message;
} }
} }
@ -84,7 +100,7 @@ export function formatDiagnosticMessage(message: DiagnosticMessage, useColors: b
// format context first (uses same string builder) // format context first (uses same string builder)
let context: string = ""; let context: string = "";
if (message.range && showContext) if (message.range && showContext)
context = formatDiagnosticContext(message.range, useColors) context = formatDiagnosticContext(message.range, useColors);
// general information // general information
sb.length = 0; sb.length = 0;

View File

@ -22,12 +22,33 @@
*/ */
import { Module } from "./module"; import {
import { Compiler, Options, Target } from "./compiler"; Module
import { DiagnosticMessage, DiagnosticCategory, formatDiagnosticMessage } from "./diagnostics"; } from "./module";
import { Parser } from "./parser";
import { Program } from "./program"; import {
import { Decompiler } from "./decompiler"; Compiler,
Options,
Target
} from "./compiler";
import {
DiagnosticMessage,
DiagnosticCategory,
formatDiagnosticMessage
} from "./diagnostics";
import {
Parser
} from "./parser";
import {
Program
} from "./program";
import {
Decompiler
} from "./decompiler";
/** Parses a single source file. If `parser` has been omitted a new one is created. */ /** Parses a single source file. If `parser` has been omitted a new one is created. */
export function parseFile(text: string, path: string, parser: Parser | null = null, isEntry: bool = false): Parser { export function parseFile(text: string, path: string, parser: Parser | null = null, isEntry: bool = false): Parser {

View File

@ -1,5 +1,10 @@
import { Target } from "./compiler"; import {
import { I64, U64 } from "./util/i64"; Target
} from "./compiler";
import {
U64
} from "./util/i64";
export type ModuleRef = usize; export type ModuleRef = usize;
export type FunctionTypeRef = usize; export type FunctionTypeRef = usize;
@ -917,7 +922,7 @@ function allocU8Array(u8s: Uint8Array | null): usize {
const ptr: usize = Heap.allocate((<Uint8Array>u8s).length); const ptr: usize = Heap.allocate((<Uint8Array>u8s).length);
let idx: usize = ptr; let idx: usize = ptr;
for (let i: i32 = 0, k: i32 = (<Uint8Array>u8s).length; i < k; ++i) for (let i: i32 = 0, k: i32 = (<Uint8Array>u8s).length; i < k; ++i)
store<u8>(idx++, (<Uint8Array>u8s)[i]) store<u8>(idx++, (<Uint8Array>u8s)[i]);
return ptr; return ptr;
} }

View File

@ -7,27 +7,36 @@
*/ */
import { Program } from "./program";
import { Tokenizer, Token, Range } from "./tokenizer";
import { DiagnosticCode, DiagnosticEmitter } from "./diagnostics";
import { I64 } from "./util/i64";
import { normalize as normalizePath } from "./util/path";
import { import {
Program
} from "./program";
import {
Tokenizer,
Token,
Range
} from "./tokenizer";
import {
DiagnosticCode,
DiagnosticEmitter
} from "./diagnostics";
import {
normalize as normalizePath
} from "./util/path";
import {
Node, Node,
NodeKind, NodeKind,
Source, Source,
// types
TypeNode, TypeNode,
// expressions // expressions
AssertionKind, AssertionKind,
CallExpression, CallExpression,
Expression, Expression,
IdentifierExpression, IdentifierExpression,
StringLiteralExpression, StringLiteralExpression,
// statements // statements
BlockStatement, BlockStatement,
BreakStatement, BreakStatement,
@ -64,12 +73,11 @@ import {
VariableStatement, VariableStatement,
VariableDeclaration, VariableDeclaration,
WhileStatement, WhileStatement,
// utility
addModifier, addModifier,
getModifier, getModifier,
hasModifier, hasModifier,
setReusableModifiers setReusableModifiers
} from "./ast"; } from "./ast";
/** Parser interface. */ /** Parser interface. */
@ -1402,7 +1410,7 @@ export class Parser extends DiagnosticEmitter {
let p: Precedence = determinePrecedenceStart(token); let p: Precedence = determinePrecedenceStart(token);
if (p != Precedence.INVALID) { if (p != Precedence.INVALID) {
let operand: Expression | null let operand: Expression | null;
// TODO: SpreadExpression, YieldExpression (currently become unsupported UnaryPrefixExpressions) // TODO: SpreadExpression, YieldExpression (currently become unsupported UnaryPrefixExpressions)

View File

@ -1,29 +1,49 @@
import { initialize as initializeBuiltins } from "./builtins";
import { Target, typeToNativeType } from "./compiler";
import { GETTER_PREFIX, SETTER_PREFIX, PATH_DELIMITER } from "./constants";
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter } from "./diagnostics";
import { Type, typesToString } from "./types";
import { I64 } from "./util/i64";
import { import {
initialize as initializeBuiltins
} from "./builtins";
import {
Target
} from "./compiler";
import {
PATH_DELIMITER
} from "./constants";
import {
DiagnosticCode,
DiagnosticMessage,
DiagnosticEmitter
} from "./diagnostics";
import {
Type,
typesToString
} from "./types";
import {
I64
} from "./util/i64";
import {
ModifierKind, ModifierKind,
Node, Node,
NodeKind, NodeKind,
Source, Source,
Range, Range,
TypeNode, TypeNode,
TypeParameter,
Decorator,
Expression, Expression,
IdentifierExpression, IdentifierExpression,
LiteralExpression,
LiteralKind,
PropertyAccessExpression, PropertyAccessExpression,
StringLiteralExpression, StringLiteralExpression,
CallExpression, CallExpression,
Statement,
ClassDeclaration, ClassDeclaration,
DeclarationStatement, DeclarationStatement,
Decorator,
EnumDeclaration, EnumDeclaration,
EnumValueDeclaration, EnumValueDeclaration,
ExportMember, ExportMember,
@ -34,20 +54,18 @@ import {
ImportStatement, ImportStatement,
InterfaceDeclaration, InterfaceDeclaration,
MethodDeclaration, MethodDeclaration,
Modifier,
NamespaceDeclaration, NamespaceDeclaration,
Statement,
TypeDeclaration, TypeDeclaration,
TypeParameter,
VariableLikeDeclarationStatement, VariableLikeDeclarationStatement,
VariableDeclaration, VariableDeclaration,
VariableStatement, VariableStatement,
hasModifier, hasModifier
mangleInternalName
} from "./ast"; } from "./ast";
import { NativeType } from "./module";
import {
NativeType
} from "./module";
class QueuedExport { class QueuedExport {
isReExport: bool; isReExport: bool;
@ -845,7 +863,7 @@ export class Program extends DiagnosticEmitter {
return this.resolveElement((<CallExpression>expression).expression, contextualFunction); return this.resolveElement((<CallExpression>expression).expression, contextualFunction);
} }
throw new Error("not implemented: " + expression.kind); throw new Error("not implemented");
} }
} }
@ -1229,9 +1247,9 @@ export class FunctionPrototype extends Element {
k = declaration.parameters.length; k = declaration.parameters.length;
const parameters: Parameter[] = new Array(k); const parameters: Parameter[] = new Array(k);
const parameterTypes: Type[] = new Array(k); const parameterTypes: Type[] = new Array(k);
for (let i = 0; i < k; ++i) { let typeNode: TypeNode | null ;
const typeNode: TypeNode | null = declaration.parameters[i].type; for (i = 0; i < k; ++i) {
if (typeNode) { if (typeNode = declaration.parameters[i].type) {
const type: Type | null = this.program.resolveType(<TypeNode>typeNode, contextualTypeArguments, true); // reports const type: Type | null = this.program.resolveType(<TypeNode>typeNode, contextualTypeArguments, true); // reports
if (type) { if (type) {
parameters[i] = new Parameter(declaration.parameters[i].name.name, type); parameters[i] = new Parameter(declaration.parameters[i].name.name, type);
@ -1243,9 +1261,8 @@ export class FunctionPrototype extends Element {
} }
// resolve return type // resolve return type
const typeNode: TypeNode | null = declaration.returnType;
let returnType: Type; let returnType: Type;
if (typeNode) { if (typeNode = declaration.returnType) {
const type: Type | null = this.program.resolveType(<TypeNode>typeNode, contextualTypeArguments, true); // reports const type: Type | null = this.program.resolveType(<TypeNode>typeNode, contextualTypeArguments, true); // reports
if (type) if (type)
returnType = <Type>type; returnType = <Type>type;
@ -1265,7 +1282,7 @@ export class FunctionPrototype extends Element {
resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null, alternativeReportNode: Node | null): Function | null { resolveInclTypeArguments(typeArgumentNodes: TypeNode[] | null, contextualTypeArguments: Map<string,Type> | null, alternativeReportNode: Node | null): Function | null {
let resolvedTypeArguments: Type[] | null; let resolvedTypeArguments: Type[] | null;
if (this.isGeneric) { if (this.isGeneric) {
assert(typeArgumentNodes != null && typeArgumentNodes.length != 0, "" + this); assert(typeArgumentNodes != null && typeArgumentNodes.length != 0);
if (!this.declaration) if (!this.declaration)
throw new Error("missing declaration"); throw new Error("missing declaration");
resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode); resolvedTypeArguments = this.program.resolveTypeArguments(this.declaration.typeParameters, typeArgumentNodes, contextualTypeArguments, alternativeReportNode);
@ -1357,7 +1374,7 @@ export class Function extends Element {
/** Gets a free temporary local of the specified type. */ /** Gets a free temporary local of the specified type. */
getTempLocal(type: Type): Local { getTempLocal(type: Type): Local {
let temps: Local[] | null; let temps: Local[] | null;
switch (typeToNativeType(type)) { switch (type.toNativeType()) {
case NativeType.I32: temps = this.tempI32s; break; case NativeType.I32: temps = this.tempI32s; break;
case NativeType.I64: temps = this.tempI64s; break; case NativeType.I64: temps = this.tempI64s; break;
case NativeType.F32: temps = this.tempF32s; break; case NativeType.F32: temps = this.tempF32s; break;
@ -1372,7 +1389,7 @@ export class Function extends Element {
/** Frees the temporary local for reuse. */ /** Frees the temporary local for reuse. */
freeTempLocal(local: Local): void { freeTempLocal(local: Local): void {
let temps: Local[]; let temps: Local[];
switch (typeToNativeType(local.type)) { switch (local.type.toNativeType()) {
case NativeType.I32: temps = this.tempI32s || (this.tempI32s = []); break; case NativeType.I32: temps = this.tempI32s || (this.tempI32s = []); break;
case NativeType.I64: temps = this.tempI64s || (this.tempI64s = []); break; case NativeType.I64: temps = this.tempI64s || (this.tempI64s = []); break;
case NativeType.F32: temps = this.tempF32s || (this.tempF32s = []); break; case NativeType.F32: temps = this.tempF32s || (this.tempF32s = []); break;
@ -1385,7 +1402,7 @@ export class Function extends Element {
/** Gets and immediately frees a temporary local of the specified type. */ /** Gets and immediately frees a temporary local of the specified type. */
getAndFreeTempLocal(type: Type): Local { getAndFreeTempLocal(type: Type): Local {
let temps: Local[]; let temps: Local[];
switch (typeToNativeType(type)) { switch (type.toNativeType()) {
case NativeType.I32: temps = this.tempI32s || (this.tempI32s = []); break; case NativeType.I32: temps = this.tempI32s || (this.tempI32s = []); break;
case NativeType.I64: temps = this.tempI64s || (this.tempI64s = []); break; case NativeType.I64: temps = this.tempI64s || (this.tempI64s = []); break;
case NativeType.F32: temps = this.tempF32s || (this.tempF32s = []); break; case NativeType.F32: temps = this.tempF32s || (this.tempF32s = []); break;
@ -1416,7 +1433,7 @@ export class Function extends Element {
assert(length > 0); assert(length > 0);
(<i32[]>this.breakStack).pop(); (<i32[]>this.breakStack).pop();
if (length > 1) { if (length > 1) {
this.breakContext = (<i32[]>this.breakStack)[length - 2].toString(10) this.breakContext = (<i32[]>this.breakStack)[length - 2].toString(10);
} else { } else {
this.breakContext = null; this.breakContext = null;
this.breakStack = null; this.breakStack = null;
@ -1461,7 +1478,7 @@ export class FieldPrototype extends Element {
case ModifierKind.PROTECTED: case ModifierKind.PROTECTED:
case ModifierKind.PUBLIC: case ModifierKind.PUBLIC:
case ModifierKind.STATIC: break; // already handled case ModifierKind.STATIC: break; // already handled
default: throw new Error("unexpected modifier: " + this.declaration.modifiers[i]); default: assert(false);
} }
} }
} }

View File

@ -19,10 +19,30 @@
*/ */
import { DiagnosticCode, DiagnosticMessage, DiagnosticEmitter, formatDiagnosticMessage } from "./diagnostics"; import {
import { Source } from "./ast"; DiagnosticCode,
import { CharCode, isLineBreak, isWhiteSpace, isIdentifierStart, isIdentifierPart, isDecimalDigit, isOctalDigit, isKeywordCharacter } from "./util/charcode"; DiagnosticMessage,
import { I64 } from "./util/i64"; DiagnosticEmitter
} from "./diagnostics";
import {
Source
} from "./ast";
import {
CharCode,
isLineBreak,
isWhiteSpace,
isIdentifierStart,
isIdentifierPart,
isDecimalDigit,
isOctalDigit,
isKeywordCharacter
} from "./util/charcode";
import {
I64
} from "./util/i64";
/** Named token types. */ /** Named token types. */
export enum Token { export enum Token {
@ -162,145 +182,148 @@ export enum Token {
ENDOFFILE ENDOFFILE
} }
function textToKeywordToken(text: string): Token { export namespace Token {
switch (text) {
case "abstract": return Token.ABSTRACT;
case "as": return Token.AS;
case "async": return Token.ASYNC;
case "await": return Token.AWAIT;
case "break": return Token.BREAK;
case "case": return Token.CASE;
case "catch": return Token.CATCH;
case "class": return Token.CLASS;
case "continue": return Token.CONTINUE;
case "const": return Token.CONST;
case "constructor": return Token.CONSTRUCTOR;
case "debugger": return Token.DEBUGGER;
case "declare": return Token.DECLARE;
case "default": return Token.DEFAULT;
case "delete": return Token.DELETE;
case "do": return Token.DO;
case "else": return Token.ELSE;
case "enum": return Token.ENUM;
case "export": return Token.EXPORT;
case "extends": return Token.EXTENDS;
case "false": return Token.FALSE;
case "finally": return Token.FINALLY;
case "for": return Token.FOR;
case "from": return Token.FROM;
case "function": return Token.FUNCTION;
case "get": return Token.GET;
case "if": return Token.IF;
case "implements": return Token.IMPLEMENTS;
case "import": return Token.IMPORT;
case "in": return Token.IN;
case "instanceof": return Token.INSTANCEOF;
case "interface": return Token.INTERFACE;
case "is": return Token.IS;
case "keyof": return Token.KEYOF;
case "let": return Token.LET;
case "module": return Token.MODULE;
case "namespace": return Token.NAMESPACE;
case "new": return Token.NEW;
case "null": return Token.NULL;
case "of": return Token.OF;
case "package": return Token.PACKAGE;
case "private": return Token.PRIVATE;
case "protected": return Token.PROTECTED;
case "public": return Token.PUBLIC;
case "readonly": return Token.READONLY;
case "return": return Token.RETURN;
case "set": return Token.SET;
case "static": return Token.STATIC;
case "super": return Token.SUPER;
case "switch": return Token.SWITCH;
case "this": return Token.THIS;
case "throw": return Token.THROW;
case "true": return Token.TRUE;
case "try": return Token.TRY;
case "type": return Token.TYPE;
case "typeof": return Token.TYPEOF;
case "var": return Token.VAR;
case "void": return Token.VOID;
case "while": return Token.WHILE;
case "with": return Token.WITH;
case "yield": return Token.YIELD;
default: return Token.INVALID;
}
}
export function operatorTokenToString(token: Token): string { export function fromKeyword(text: string): Token {
switch (token) { switch (text) {
case Token.DELETE: return "delete"; case "abstract": return Token.ABSTRACT;
case Token.IN: return "in"; case "as": return Token.AS;
case Token.INSTANCEOF: return "instanceof"; case "async": return Token.ASYNC;
case Token.NEW: return "new"; case "await": return Token.AWAIT;
case Token.TYPEOF: return "typeof"; case "break": return Token.BREAK;
case Token.VOID: return "void"; case "case": return Token.CASE;
case Token.YIELD: return "yield"; case "catch": return Token.CATCH;
case Token.DOT_DOT_DOT: return "..."; case "class": return Token.CLASS;
case Token.COMMA: return ","; case "continue": return Token.CONTINUE;
case Token.LESSTHAN: return "<"; case "const": return Token.CONST;
case Token.GREATERTHAN: return ">"; case "constructor": return Token.CONSTRUCTOR;
case Token.LESSTHAN_EQUALS: return "<="; case "debugger": return Token.DEBUGGER;
case Token.GREATERTHAN_EQUALS: return ">="; case "declare": return Token.DECLARE;
case Token.EQUALS_EQUALS: return "=="; case "default": return Token.DEFAULT;
case Token.EXCLAMATION_EQUALS: return "!="; case "delete": return Token.DELETE;
case Token.EQUALS_EQUALS_EQUALS: return "==="; case "do": return Token.DO;
case Token.EXCLAMATION_EQUALS_EQUALS: return "!=="; case "else": return Token.ELSE;
case Token.PLUS: return "+"; case "enum": return Token.ENUM;
case Token.MINUS: return "-"; case "export": return Token.EXPORT;
case Token.ASTERISK_ASTERISK: return "**"; case "extends": return Token.EXTENDS;
case Token.ASTERISK: return "*"; case "false": return Token.FALSE;
case Token.SLASH: return "/"; case "finally": return Token.FINALLY;
case Token.PERCENT: return "%"; case "for": return Token.FOR;
case Token.PLUS_PLUS: return "++"; case "from": return Token.FROM;
case Token.MINUS_MINUS: return "--"; case "function": return Token.FUNCTION;
case Token.LESSTHAN_LESSTHAN: return "<<"; case "get": return Token.GET;
case Token.GREATERTHAN_GREATERTHAN: return ">>"; case "if": return Token.IF;
case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN: return ">>>"; case "implements": return Token.IMPLEMENTS;
case Token.AMPERSAND: return "&"; case "import": return Token.IMPORT;
case Token.BAR: return "|"; case "in": return Token.IN;
case Token.CARET: return "^"; case "instanceof": return Token.INSTANCEOF;
case Token.EXCLAMATION: return "!"; case "interface": return Token.INTERFACE;
case Token.TILDE: return "~"; case "is": return Token.IS;
case Token.AMPERSAND_AMPERSAND: return "&&"; case "keyof": return Token.KEYOF;
case Token.BAR_BAR: return "||"; case "let": return Token.LET;
case Token.EQUALS: return "="; case "module": return Token.MODULE;
case Token.PLUS_EQUALS: return "+="; case "namespace": return Token.NAMESPACE;
case Token.MINUS_EQUALS: return "-="; case "new": return Token.NEW;
case Token.ASTERISK_EQUALS: return "*="; case "null": return Token.NULL;
case Token.ASTERISK_ASTERISK_EQUALS: return "**="; case "of": return Token.OF;
case Token.SLASH_EQUALS: return "/="; case "package": return Token.PACKAGE;
case Token.PERCENT_EQUALS: return "%="; case "private": return Token.PRIVATE;
case Token.LESSTHAN_LESSTHAN_EQUALS: return "<<="; case "protected": return Token.PROTECTED;
case Token.GREATERTHAN_GREATERTHAN_EQUALS: return ">>="; case "public": return Token.PUBLIC;
case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN_EQUALS: return ">>>="; case "readonly": return Token.READONLY;
case Token.AMPERSAND_EQUALS: return "&="; case "return": return Token.RETURN;
case Token.BAR_EQUALS: return "|="; case "set": return Token.SET;
case Token.CARET_EQUALS: return "^="; case "static": return Token.STATIC;
default: assert(false); return ""; case "super": return Token.SUPER;
case "switch": return Token.SWITCH;
case "this": return Token.THIS;
case "throw": return Token.THROW;
case "true": return Token.TRUE;
case "try": return Token.TRY;
case "type": return Token.TYPE;
case "typeof": return Token.TYPEOF;
case "var": return Token.VAR;
case "void": return Token.VOID;
case "while": return Token.WHILE;
case "with": return Token.WITH;
case "yield": return Token.YIELD;
default: return Token.INVALID;
}
} }
}
function isPossibleIdentifier(token: Token): bool { export function operatorToString(token: Token): string {
switch (token) { switch (token) {
case Token.ABSTRACT: case Token.DELETE: return "delete";
case Token.AS: case Token.IN: return "in";
case Token.CONSTRUCTOR: case Token.INSTANCEOF: return "instanceof";
case Token.DECLARE: case Token.NEW: return "new";
case Token.FROM: case Token.TYPEOF: return "typeof";
case Token.GET: case Token.VOID: return "void";
case Token.IS: case Token.YIELD: return "yield";
case Token.KEYOF: case Token.DOT_DOT_DOT: return "...";
case Token.MODULE: case Token.COMMA: return ",";
case Token.NAMESPACE: case Token.LESSTHAN: return "<";
case Token.READONLY: case Token.GREATERTHAN: return ">";
case Token.SET: case Token.LESSTHAN_EQUALS: return "<=";
case Token.TYPE: case Token.GREATERTHAN_EQUALS: return ">=";
return true; case Token.EQUALS_EQUALS: return "==";
default: case Token.EXCLAMATION_EQUALS: return "!=";
return false; case Token.EQUALS_EQUALS_EQUALS: return "===";
case Token.EXCLAMATION_EQUALS_EQUALS: return "!==";
case Token.PLUS: return "+";
case Token.MINUS: return "-";
case Token.ASTERISK_ASTERISK: return "**";
case Token.ASTERISK: return "*";
case Token.SLASH: return "/";
case Token.PERCENT: return "%";
case Token.PLUS_PLUS: return "++";
case Token.MINUS_MINUS: return "--";
case Token.LESSTHAN_LESSTHAN: return "<<";
case Token.GREATERTHAN_GREATERTHAN: return ">>";
case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN: return ">>>";
case Token.AMPERSAND: return "&";
case Token.BAR: return "|";
case Token.CARET: return "^";
case Token.EXCLAMATION: return "!";
case Token.TILDE: return "~";
case Token.AMPERSAND_AMPERSAND: return "&&";
case Token.BAR_BAR: return "||";
case Token.EQUALS: return "=";
case Token.PLUS_EQUALS: return "+=";
case Token.MINUS_EQUALS: return "-=";
case Token.ASTERISK_EQUALS: return "*=";
case Token.ASTERISK_ASTERISK_EQUALS: return "**=";
case Token.SLASH_EQUALS: return "/=";
case Token.PERCENT_EQUALS: return "%=";
case Token.LESSTHAN_LESSTHAN_EQUALS: return "<<=";
case Token.GREATERTHAN_GREATERTHAN_EQUALS: return ">>=";
case Token.GREATERTHAN_GREATERTHAN_GREATERTHAN_EQUALS: return ">>>=";
case Token.AMPERSAND_EQUALS: return "&=";
case Token.BAR_EQUALS: return "|=";
case Token.CARET_EQUALS: return "^=";
default: assert(false); return "";
}
}
export function isAlsoIdentifier(token: Token): bool {
switch (token) {
case Token.ABSTRACT:
case Token.AS:
case Token.CONSTRUCTOR:
case Token.DECLARE:
case Token.FROM:
case Token.GET:
case Token.IS:
case Token.KEYOF:
case Token.MODULE:
case Token.NAMESPACE:
case Token.READONLY:
case Token.SET:
case Token.TYPE:
return true;
default:
return false;
}
} }
} }
@ -675,8 +698,8 @@ export class Tokenizer extends DiagnosticEmitter {
} }
} }
const keywordText: string = text.substring(posBefore, this.pos); const keywordText: string = text.substring(posBefore, this.pos);
const keywordToken: Token = textToKeywordToken(keywordText); const keywordToken: Token = Token.fromKeyword(keywordText);
if (keywordToken != Token.INVALID && !(preferIdentifier && isPossibleIdentifier(keywordToken))) if (keywordToken != Token.INVALID && !(preferIdentifier && Token.isAlsoIdentifier(keywordToken)))
return keywordToken; return keywordToken;
this.pos = posBefore; this.pos = posBefore;
} }

View File

@ -1,5 +1,15 @@
import { Class, Function } from "./program"; import {
import { sb } from "./util/sb"; Class,
Function
} from "./program";
import {
sb
} from "./util/sb";
import {
NativeType, ExpressionRef, Module
} from "./module";
/** Indicates the kind of a type. */ /** Indicates the kind of a type. */
export const enum TypeKind { export const enum TypeKind {
@ -123,6 +133,48 @@ export class Type {
} }
} }
// Binaryen specific
/** Converts this type to its respective native type. */
toNativeType(): NativeType {
return this.kind == TypeKind.F32
? NativeType.F32
: this.kind == TypeKind.F64
? NativeType.F64
: this.isLongInteger
? NativeType.I64
: this.isAnyInteger || this.kind == TypeKind.BOOL
? NativeType.I32
: NativeType.None;
}
/** Converts this type to its native `0` value. */
toNativeZero(module: Module): ExpressionRef {
return this.kind == TypeKind.F32 ? module.createF32(0)
: this.kind == TypeKind.F64 ? module.createF64(0)
: this.isLongInteger ? module.createI64(0, 0)
: module.createI32(0);
}
/** Converts this type to its native `1` value. */
toNativeOne(module: Module): ExpressionRef {
return this.kind == TypeKind.F32 ? module.createF32(1)
: this.kind == TypeKind.F64 ? module.createF64(1)
: this.isLongInteger ? module.createI64(1, 0)
: module.createI32(1);
}
/** Converts this type to its signature name. */
toSignatureName(): string {
return this.kind == TypeKind.VOID ? "v"
: this.kind == TypeKind.F32 ? "f"
: this.kind == TypeKind.F64 ? "F"
: this.isLongInteger ? "I"
: "i";
}
// Types
/** An 8-bit signed integer. */ /** An 8-bit signed integer. */
static readonly i8: Type = new Type(TypeKind.I8, 8); static readonly i8: Type = new Type(TypeKind.I8, 8);
/** A 16-bit signed integer. */ /** A 16-bit signed integer. */
@ -157,6 +209,15 @@ export class Type {
static readonly void: Type = new Type(TypeKind.VOID, 0); static readonly void: Type = new Type(TypeKind.VOID, 0);
} }
/** Converts an array of types to an array of native types. */
export function typesToNativeTypes(types: Type[]): NativeType[] {
const k: i32 = types.length;
const ret: NativeType[] = new Array(k);
for (let i: i32 = 0; i < k; ++i)
ret[i] = types[i].toNativeType();
return ret;
}
/** Converts an array of types to its combined string representation. Usually type arguments. */ /** Converts an array of types to its combined string representation. Usually type arguments. */
export function typesToString(types: Type[], prefix: string = "<", postfix: string = ">"): string { export function typesToString(types: Type[], prefix: string = "<", postfix: string = ">"): string {
const k: i32 = types.length; const k: i32 = types.length;

View File

@ -1,4 +1,6 @@
import { CharCode } from "./charcode"; import {
CharCode
} from "./charcode";
/** Normalizes the specified path, removing interior placeholders. Expects a posix-formatted string / not Windows compatible. */ /** Normalizes the specified path, removing interior placeholders. Expects a posix-formatted string / not Windows compatible. */
export function normalize(path: string, trimExtension: bool = false, separator: CharCode = CharCode.SLASH): string { export function normalize(path: string, trimExtension: bool = false, separator: CharCode = CharCode.SLASH): string {

50
tslint.json Normal file
View File

@ -0,0 +1,50 @@
{
"defaultSeverity": "warning",
"rules": {
"adjacent-overload-signatures": true,
"ban-types": [ true, ["Object"], ["any"], ["undefined"], ["never"] ],
"deprecation": true,
"encoding": true,
"eofline": true,
"indent": [true, "spaces", 2],
"label-position": true,
"member-access": [ true, "no-public" ],
"new-parens": true,
"no-any": true,
"no-arg": true,
"no-consecutive-blank-lines": true,
"no-debugger": true,
"no-default-export": true,
"no-duplicate-imports": true,
"no-duplicate-super": true,
"no-duplicate-switch-case": true,
"no-duplicate-variable": true,
"no-eval": true,
"no-inferred-empty-object-type": true,
"no-internal-module": true,
"no-invalid-template-strings": true,
"no-invalid-this": true,
"no-irregular-whitespace": true,
"no-mergeable-namespace": true,
"no-misused-new": true,
"no-object-literal-type-assertion": true,
"no-parameter-properties": true,
"no-require-imports": true,
"no-shadowed-variable": true,
"no-sparse-arrays": true,
"no-string-literal": true,
"no-string-throw": true,
"no-this-assignment": true,
"no-trailing-whitespace": true,
"no-unbound-method": true,
"no-unsafe-any": true,
"no-unused-variable": true,
"no-void-expression": true,
"object-literal-shorthand": [true, "never"],
"prefer-method-signature": true,
"quotemark": [true, "double"],
"radix": true,
"restrict-plus-operands": true,
"semicolon": [true, "always"]
}
}