diff --git a/package-lock.json b/package-lock.json index ec3879df..03e84af0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,14 +19,21 @@ "integrity": "sha512-q3zfJvaTroV5BjAAR+peTHEGAAhGrPX0z2EzCzpt2mwFA+qzUn2nigJLqSekXRtdULKmT8am7zjvTMZSapIgHw==", "dev": true }, + "@types/events": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-1.1.0.tgz", + "integrity": "sha512-y3bR98mzYOo0pAZuiLari+cQyiKk3UXRuT45h1RjhfeCzqkjaVsfZJNaxdgtk7/3tzOm1ozLTqEqMP3VbI48jw==", + "dev": true + }, "@types/glob": { - "version": "5.0.33", - "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.33.tgz", - "integrity": "sha512-BcD4yyWz+qmCggaYMSFF0Xn7GkO6tgwm3Fh9Gxk/kQmEU3Z7flQTnVlMyKBUNvXXNTCCyjqK4XT4/2hLd1gQ2A==", + "version": "5.0.34", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.34.tgz", + "integrity": "sha512-sUvpieq+HsWTLdkeOI8Mi8u22Ag3AoGuM3sv+XMP1bKtbaIAHpEA2f52K2mz6vK5PVhTa3bFyRZLZMqTxOo2Cw==", "dev": true, "requires": { - "@types/minimatch": "3.0.1", - "@types/node": "8.0.58" + "@types/events": "1.1.0", + "@types/minimatch": "3.0.2", + "@types/node": "8.5.1" } }, "@types/long": { @@ -36,9 +43,9 @@ "dev": true }, "@types/minimatch": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.1.tgz", - "integrity": "sha512-rUO/jz10KRSyA9SHoCWQ8WX9BICyj5jZYu1/ucKEJKb4KzLZCKMURdYbadP157Q6Zl1x0vHsrU+Z/O0XlhYQDw==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.2.tgz", + "integrity": "sha512-tctoxbfuMCxeI2CAsnwoZQfaBA+T7gPzDzDuiiFnyCSSyGYEB92cmRTh6E3tdR1hWsprbJ9IdbvX3PzLmJU/GA==", "dev": true }, "@types/minimist": { @@ -48,9 +55,21 @@ "dev": true }, "@types/node": { - "version": "8.0.58", - "resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.58.tgz", - "integrity": "sha512-V746iUU7eHNdzQipoACuguDlVhC7IHK8CES1jSkuFt352wwA84BCWPXaGekBd7R5XdNK5ReHONDVKxlL9IreAw==" + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.1.tgz", + "integrity": "sha512-SrmAO+NhnsuG/6TychSl2VdxBZiw/d6V+8j+DFo8O3PwFi+QeYXWHhAw+b170aSc6zYab6/PjEWRZHIDN9mNUw==" + }, + "@types/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-FKjsOVbC6B7bdSB5CuzyHCkK69I=", + "dev": true + }, + "@types/strip-json-comments": { + "version": "0.0.30", + "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", + "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", + "dev": true }, "acorn": { "version": "4.0.13", @@ -937,6 +956,15 @@ "minimalistic-crypto-utils": "1.0.1" } }, + "homedir-polyfill": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz", + "integrity": "sha1-TCu8inWJmP7r9e1oWA921GdotLw=", + "dev": true, + "requires": { + "parse-passwd": "1.0.0" + } + }, "hosted-git-info": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", @@ -1536,6 +1564,12 @@ "error-ex": "1.3.1" } }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, "path-browserify": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", @@ -2049,9 +2083,9 @@ } }, "ts-node": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-3.3.0.tgz", - "integrity": "sha1-wTxqMCTjC+EYDdUwOPwgkonUv2k=", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-4.0.2.tgz", + "integrity": "sha512-mg7l6ON8asjnfzkTi1LFWKaOGHl5Jf1+5ij0MQ502YfC6+4FBgh/idJgw9aN9kei1Rf4/pmFpNuFE1YbcQdOTA==", "dev": true, "requires": { "arrify": "1.0.1", @@ -2060,29 +2094,20 @@ "make-error": "1.3.0", "minimist": "1.2.0", "mkdirp": "0.5.1", - "source-map-support": "0.4.18", - "tsconfig": "6.0.0", - "v8flags": "3.0.0", + "source-map-support": "0.5.0", + "tsconfig": "7.0.0", + "v8flags": "3.0.1", "yn": "2.0.0" - }, - "dependencies": { - "source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "requires": { - "source-map": "0.5.7" - } - } } }, "tsconfig": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-6.0.0.tgz", - "integrity": "sha1-aw6DdgA9evGGT434+J3QBZ/80DI=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", + "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", "dev": true, "requires": { + "@types/strip-bom": "3.0.0", + "@types/strip-json-comments": "0.0.30", "strip-bom": "3.0.0", "strip-json-comments": "2.0.1" } @@ -2160,12 +2185,6 @@ } } }, - "user-home": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", - "dev": true - }, "util": { "version": "0.10.3", "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", @@ -2190,12 +2209,12 @@ "dev": true }, "v8flags": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.0.tgz", - "integrity": "sha512-AGl+C+4qpeSu2g3JxCD/mGFFOs/vVZ3XREkD3ibQXEqr4Y4zgIrPWW124/IKJFHOIVFIoH8miWrLf0o84HYjwA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.1.tgz", + "integrity": "sha1-3Oj8N5wX2fLJ6e142JzgAFKxt2s=", "dev": true, "requires": { - "user-home": "1.1.1" + "homedir-polyfill": "1.0.1" } }, "validate-npm-package-license": { diff --git a/package.json b/package.json index 0379e175..53e060f2 100644 --- a/package.json +++ b/package.json @@ -11,7 +11,7 @@ "url": "https://github.com/AssemblyScript/next/issues" }, "dependencies": { - "@types/node": "^8.0.58", + "@types/node": "^8.5.1", "binaryen": "40.0.0-nightly.20171209", "glob": "^7.1.2", "minimist": "^1.2.0", @@ -20,14 +20,14 @@ "devDependencies": { "@types/chalk": "^2.2.0", "@types/diff": "^3.2.2", - "@types/glob": "^5.0.33", + "@types/glob": "^5.0.34", "@types/long": "^3.0.32", "@types/minimist": "^1.2.0", "chalk": "^2.3.0", "diff": "^3.4.0", "long": "^3.2.0", "ts-loader": "^3.2.0", - "ts-node": "^3.3.0", + "ts-node": "^4.0.2", "typescript": "^2.6.2", "webpack": "^3.10.0" }, diff --git a/src/ast.ts b/src/ast.ts index 70c7bd0b..8c65beea 100644 --- a/src/ast.ts +++ b/src/ast.ts @@ -62,6 +62,7 @@ export enum NodeKind { SWITCH, THROW, TRY, + TYPEDECLARATION, VARIABLE, // wraps declarations VARIABLEDECLARATION, WHILE, @@ -542,6 +543,17 @@ export abstract class Node { return stmt; } + static createTypeDeclaration(identifier: IdentifierExpression, alias: TypeNode, modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): TypeDeclaration { + const stmt: TypeDeclaration = new TypeDeclaration(); + stmt.range = range; + (stmt.name = identifier).parent = stmt; + (stmt.alias = alias).parent = stmt; + let i: i32, k: i32; + if (stmt.modifiers = modifiers) for (i = 0, k = (modifiers).length; i < k; ++i) (modifiers)[i].parent = stmt; + if (stmt.decorators = decorators) for (i = 0, k = (decorators).length; i < k; ++i) (decorators)[i].parent = stmt; + return stmt; + } + static createVariable(declarations: VariableDeclaration[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): VariableStatement { const stmt: VariableStatement = new VariableStatement(); stmt.range = range; @@ -552,10 +564,10 @@ export abstract class Node { return stmt; } - static createVariableDeclaration(identifier: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): VariableDeclaration { + static createVariableDeclaration(name: IdentifierExpression, type: TypeNode | null, initializer: Expression | null, modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): VariableDeclaration { const elem: VariableDeclaration = new VariableDeclaration(); elem.range = range; - (elem.name = identifier).parent = elem; + (elem.name = name).parent = elem; if (elem.type = type) (type).parent = elem; if (elem.initializer = initializer) (initializer).parent = elem; elem.modifiers = modifiers; @@ -1864,6 +1876,33 @@ export class TryStatement extends Statement { } } +/** Represents a `type` declaration. */ +export class TypeDeclaration extends DeclarationStatement { + + kind = NodeKind.TYPEDECLARATION; + + /** Type being aliased. */ + alias: TypeNode; + + serialize(sb: string[]): void { + let i: i32, k: i32; + if (this.decorators) + for (i = 0, k = this.decorators.length; i < k; ++i) { + this.decorators[i].serialize(sb); + sb.push("\n"); + } + if (this.modifiers) + for (i = 0, k = (this.modifiers).length; i < k; ++i) { + (this.modifiers)[i].serialize(sb); + sb.push(" "); + } + sb.push("type "); + this.name.serialize(sb); + sb.push(" = "); + this.alias.serialize(sb); + } +} + /** Represents a single variable declaration within a {@link VariableStatement}. */ export class VariableDeclaration extends VariableLikeDeclarationStatement { diff --git a/src/builtins.ts b/src/builtins.ts index 03c95ec8..b84597be 100644 --- a/src/builtins.ts +++ b/src/builtins.ts @@ -42,6 +42,8 @@ export function initialize(program: Program): void { // host operations addFunction(program, "current_memory"); addFunction(program, "grow_memory"); + // addFunction(program, "move_memory"); + // addFunction(program, "set_memory"); // imported addFunction(program, "parseInt"); @@ -589,6 +591,29 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty arg0 = compiler.compileExpression(operands[0], Type.i32); return module.createHost(HostOp.GrowMemory, null, [ arg0 ]); + // see: https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md + /* + case "move_memory": // move_memory(dest: usize, src: usize: n: usize) -> void + compiler.currentType = Type.void; + if (!validateCall(compiler, typeArguments, 0, operands, 3, reportNode)) + return module.createUnreachable(); + arg0 = compiler.compileExpression(operands[0], usizeType); + arg1 = compiler.compileExpression(operands[1], usizeType); + arg2 = compiler.compileExpression(operands[2], usizeType); + compiler.currentType = Type.void; + return module.createHost(HostOp.MoveMemory, null, [ arg0, arg1, arg2 ]); + + case "set_memory": // set_memory(dest: usize, value: u32, n: usize) -> void + compiler.currentType = Type.void; + if (!validateCall(compiler, typeArguments, 0, operands, 3, reportNode)) + return module.createUnreachable(); + arg0 = compiler.compileExpression(operands[0], usizeType); + arg1 = compiler.compileExpression(operands[1], Type.u32); + arg2 = compiler.compileExpression(operands[2], usizeType); + compiler.currentType = Type.void; + return module.createHost(HostOp.SetMemory, null, [ arg0, arg1, arg2 ]); + */ + // imported case "parseInt": // takes a pointer to the string diff --git a/src/compiler.ts b/src/compiler.ts index fb629581..aa7b3221 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -1139,9 +1139,9 @@ export class Compiler extends DiagnosticEmitter { if (fromType.kind == TypeKind.F32) { if (toType.isSignedInteger) { if (toType.isLongInteger) - expr = mod.createUnary(UnaryOp.TruncF32_I64, expr); + expr = mod.createUnary(UnaryOp.TruncF32ToI64, expr); else { - expr = mod.createUnary(UnaryOp.TruncF32_I32, expr); + expr = mod.createUnary(UnaryOp.TruncF32ToI32, expr); if (toType.isSmallInteger) { expr = mod.createBinary(BinaryOp.ShlI32, expr, mod.createI32(toType.smallIntegerShift)); expr = mod.createBinary(BinaryOp.ShrI32, expr, mod.createI32(toType.smallIntegerShift)); @@ -1149,9 +1149,9 @@ export class Compiler extends DiagnosticEmitter { } } else { if (toType.isLongInteger) - expr = mod.createUnary(UnaryOp.TruncF32_U64, expr); + expr = mod.createUnary(UnaryOp.TruncF32ToU64, expr); else { - expr = mod.createUnary(UnaryOp.TruncF32_U32, expr); + expr = mod.createUnary(UnaryOp.TruncF32ToU32, expr); if (toType.isSmallInteger) expr = mod.createBinary(BinaryOp.AndI32, expr, mod.createI32(toType.smallIntegerMask)); } @@ -1161,9 +1161,9 @@ export class Compiler extends DiagnosticEmitter { } else { if (toType.isSignedInteger) { if (toType.isLongInteger) - expr = mod.createUnary(UnaryOp.TruncF64_I64, expr); + expr = mod.createUnary(UnaryOp.TruncF64ToI64, expr); else { - expr = mod.createUnary(UnaryOp.TruncF64_I32, expr); + expr = mod.createUnary(UnaryOp.TruncF64ToI32, expr); if (toType.isSmallInteger) { expr = mod.createBinary(BinaryOp.ShlI32, expr, mod.createI32(toType.smallIntegerShift)); expr = mod.createBinary(BinaryOp.ShrI32, expr, mod.createI32(toType.smallIntegerShift)); @@ -1171,9 +1171,9 @@ export class Compiler extends DiagnosticEmitter { } } else { if (toType.isLongInteger) - expr = mod.createUnary(UnaryOp.TruncF64_U64, expr); + expr = mod.createUnary(UnaryOp.TruncF64ToU64, expr); else { - expr = mod.createUnary(UnaryOp.TruncF64_U32, expr); + expr = mod.createUnary(UnaryOp.TruncF64ToU32, expr); if (toType.isSmallInteger) expr = mod.createBinary(BinaryOp.AndI32, expr, mod.createI32(toType.smallIntegerMask)); } @@ -1190,16 +1190,16 @@ export class Compiler extends DiagnosticEmitter { if (fromType.isLongInteger) { losesInformation = true; if (fromType.isSignedInteger) - expr = mod.createUnary(UnaryOp.ConvertI64_F32, expr); + expr = mod.createUnary(UnaryOp.ConvertI64ToF32, expr); else - expr = mod.createUnary(UnaryOp.ConvertU64_F32, expr); + expr = mod.createUnary(UnaryOp.ConvertU64ToF32, expr); } else { if (!fromType.isSmallInteger) losesInformation = true; if (fromType.isSignedInteger) - expr = mod.createUnary(UnaryOp.ConvertI32_F32, expr); + expr = mod.createUnary(UnaryOp.ConvertI32ToF32, expr); else - expr = mod.createUnary(UnaryOp.ConvertU32_F32, expr); + expr = mod.createUnary(UnaryOp.ConvertU32ToF32, expr); } // int to f64 @@ -1207,14 +1207,14 @@ export class Compiler extends DiagnosticEmitter { if (fromType.isLongInteger) { losesInformation = true; if (fromType.isSignedInteger) - expr = mod.createUnary(UnaryOp.ConvertI64_F64, expr); + expr = mod.createUnary(UnaryOp.ConvertI64ToF64, expr); else - expr = mod.createUnary(UnaryOp.ConvertU64_F64, expr); + expr = mod.createUnary(UnaryOp.ConvertU64ToF64, expr); } else if (fromType.isSignedInteger) - expr = mod.createUnary(UnaryOp.ConvertI32_F64, expr); + expr = mod.createUnary(UnaryOp.ConvertI32ToF64, expr); else - expr = mod.createUnary(UnaryOp.ConvertU32_F64, expr); + expr = mod.createUnary(UnaryOp.ConvertU32ToF64, expr); } // int to int diff --git a/src/decompiler.ts b/src/decompiler.ts index 64d0b228..482a4cb3 100644 --- a/src/decompiler.ts +++ b/src/decompiler.ts @@ -339,42 +339,42 @@ export class Decompiler { this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.TruncF32_I32: + case UnaryOp.TruncF32ToI32: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.TruncF32_I64: + case UnaryOp.TruncF32ToI64: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.TruncF32_U32: + case UnaryOp.TruncF32ToU32: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.TruncF32_U64: + case UnaryOp.TruncF32ToU64: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.TruncF64_I32: + case UnaryOp.TruncF64ToI32: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.TruncF64_I64: + case UnaryOp.TruncF64ToI64: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.TruncF64_U32: + case UnaryOp.TruncF64ToU32: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.TruncF64_U64: + case UnaryOp.TruncF64ToU64: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; @@ -391,42 +391,42 @@ export class Decompiler { this.push(")"); return; - case UnaryOp.ConvertI32_F32: + case UnaryOp.ConvertI32ToF32: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.ConvertI32_F64: + case UnaryOp.ConvertI32ToF64: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.ConvertU32_F32: + case UnaryOp.ConvertU32ToF32: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.ConvertU32_F64: + case UnaryOp.ConvertU32ToF64: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.ConvertI64_F32: + case UnaryOp.ConvertI64ToF32: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.ConvertI64_F64: + case UnaryOp.ConvertI64ToF64: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.ConvertU64_F32: + case UnaryOp.ConvertU64ToF32: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; - case UnaryOp.ConvertU64_F64: + case UnaryOp.ConvertU64ToF64: this.push(""); this.decompileExpression(_BinaryenUnaryGetValue(expr)); return; diff --git a/src/module.ts b/src/module.ts index 512a95b9..fa77a757 100644 --- a/src/module.ts +++ b/src/module.ts @@ -95,28 +95,45 @@ export enum UnaryOp { ExtendI32 = _BinaryenExtendSInt32(), ExtendU32 = _BinaryenExtendUInt32(), WrapI64 = _BinaryenWrapInt64(), - TruncF32_I32 = _BinaryenTruncSFloat32ToInt32(), - TruncF32_I64 = _BinaryenTruncSFloat32ToInt64(), - TruncF32_U32 = _BinaryenTruncUFloat32ToInt32(), - TruncF32_U64 = _BinaryenTruncUFloat32ToInt64(), - TruncF64_I32 = _BinaryenTruncSFloat64ToInt32(), - TruncF64_I64 = _BinaryenTruncSFloat64ToInt64(), - TruncF64_U32 = _BinaryenTruncUFloat64ToInt32(), - TruncF64_U64 = _BinaryenTruncUFloat64ToInt64(), + TruncF32ToI32 = _BinaryenTruncSFloat32ToInt32(), + TruncF32ToI64 = _BinaryenTruncSFloat32ToInt64(), + TruncF32ToU32 = _BinaryenTruncUFloat32ToInt32(), + TruncF32ToU64 = _BinaryenTruncUFloat32ToInt64(), + TruncF64ToI32 = _BinaryenTruncSFloat64ToInt32(), + TruncF64ToI64 = _BinaryenTruncSFloat64ToInt64(), + TruncF64ToU32 = _BinaryenTruncUFloat64ToInt32(), + TruncF64ToU64 = _BinaryenTruncUFloat64ToInt64(), ReinterpretF32 = _BinaryenReinterpretFloat32(), ReinterpretF64 = _BinaryenReinterpretFloat64(), - ConvertI32_F32 = _BinaryenConvertSInt32ToFloat32(), - ConvertI32_F64 = _BinaryenConvertSInt32ToFloat64(), - ConvertU32_F32 = _BinaryenConvertUInt32ToFloat32(), - ConvertU32_F64 = _BinaryenConvertUInt32ToFloat64(), - ConvertI64_F32 = _BinaryenConvertSInt64ToFloat32(), - ConvertI64_F64 = _BinaryenConvertSInt64ToFloat64(), - ConvertU64_F32 = _BinaryenConvertUInt64ToFloat32(), - ConvertU64_F64 = _BinaryenConvertUInt64ToFloat64(), + ConvertI32ToF32 = _BinaryenConvertSInt32ToFloat32(), + ConvertI32ToF64 = _BinaryenConvertSInt32ToFloat64(), + ConvertU32ToF32 = _BinaryenConvertUInt32ToFloat32(), + ConvertU32ToF64 = _BinaryenConvertUInt32ToFloat64(), + ConvertI64ToF32 = _BinaryenConvertSInt64ToFloat32(), + ConvertI64ToF64 = _BinaryenConvertSInt64ToFloat64(), + ConvertU64ToF32 = _BinaryenConvertUInt64ToFloat32(), + ConvertU64ToF64 = _BinaryenConvertUInt64ToFloat64(), PromoteF32 = _BinaryenPromoteFloat32(), DemoteF64 = _BinaryenDemoteFloat64(), ReinterpretI32 = _BinaryenReinterpretInt32(), ReinterpretI64 = _BinaryenReinterpretInt64() + + // see: https://github.com/WebAssembly/threads/blob/master/proposals/threads/Overview.md#new-sign-extending-operators + // ExtendI8ToI32 =_BinaryenExtendS8Int32() + // ExtendI16ToI32 = _BinaryenExtendS16Int32() + // ExtendI8ToI64 = _BinaryenExtendS8Int64() // operand is I64 + // ExtendI16ToI64 = _BinaryenExtendS16Int64() + // ExtendI32ToI64 = _BinaryenExtendS32Int64() + + // see: https://github.com/WebAssembly/nontrapping-float-to-int-conversions/blob/master/proposals/nontrapping-float-to-int-conversion/Overview.md#design + // TruncF32ToI32Sat + // TruncF32ToU32Sat + // TruncF64ToI32Sat + // TruncF64ToU32Sat + // TruncF32ToI64Sat + // TruncF32ToU64Sat + // TruncF64ToI64Sat + // TruncF64ToU64Sat } export enum BinaryOp { @@ -202,7 +219,11 @@ export enum HostOp { PageSize = _BinaryenPageSize(), CurrentMemory = _BinaryenCurrentMemory(), GrowMemory = _BinaryenGrowMemory(), - HasFeature = _BinaryenHasFeature() + HasFeature = _BinaryenHasFeature(), + + // see: https://github.com/WebAssembly/bulk-memory-operations/blob/master/proposals/bulk-memory-operations/Overview.md#design + // MoveMemory + // SetMemory } export enum AtomicRMWOp { diff --git a/src/parser.ts b/src/parser.ts index a6f71f1b..3859c4a0 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -59,6 +59,7 @@ import { SwitchStatement, ThrowStatement, TryStatement, + TypeDeclaration, TypeParameter, VariableStatement, VariableDeclaration, @@ -193,7 +194,9 @@ export class Parser extends DiagnosticEmitter { break; case Token.TYPE: - // TODO + statement = this.parseTypeDeclaration(tn, modifiers, decorators); + decorators = null; + break; default: if (hasModifier(ModifierKind.EXPORT, modifiers)) { @@ -718,7 +721,7 @@ export class Parser extends DiagnosticEmitter { isSetter = true; } - if (tn.skip(Token.IDENTIFIER) || tn.skip(Token.CONSTRUCTOR)) { + if (tn.skip(Token.CONSTRUCTOR) || tn.skip(Token.IDENTIFIER)) { // order is important const identifier: IdentifierExpression = tn.token == Token.CONSTRUCTOR ? Node.createConstructor(tn.range()) : Node.createIdentifier(tn.readIdentifier(), tn.range()); @@ -1017,6 +1020,9 @@ export class Parser extends DiagnosticEmitter { case Token.TRY: return this.parseTryStatement(tn); + case Token.TYPE: + return this.parseTypeDeclaration(tn, null); + case Token.WHILE: return this.parseWhileStatement(tn); @@ -1311,6 +1317,27 @@ export class Parser extends DiagnosticEmitter { return null; } + parseTypeDeclaration(tn: Tokenizer, modifiers: Modifier[] | null = null, decorators: Decorator[] | null = null): TypeDeclaration | null { + // at 'type': Identifier '=' Type ';'? + const startPos: i32 = decorators && decorators.length ? decorators[0].range.start + : modifiers && modifiers.length ? modifiers[0].range.start + : tn.tokenPos; + if (tn.skip(Token.IDENTIFIER)) { + const name: IdentifierExpression = Node.createIdentifier(tn.readIdentifier(), tn.range()); + if (tn.skip(Token.EQUALS)) { + const type: TypeNode | null = this.parseType(tn); + if (!type) + return null; + const ret: TypeDeclaration = Node.createTypeDeclaration(name, type, modifiers, decorators, tn.range(startPos, tn.pos)); + tn.skip(Token.SEMICOLON); + return ret; + } else + this.error(DiagnosticCode._0_expected, tn.range(), "="); + } else + this.error(DiagnosticCode.Identifier_expected, tn.range()); + return null; + } + parseWhileStatement(tn: Tokenizer): WhileStatement | null { // at 'while': '(' Expression ')' Statement ';'? const startRange: Range = tn.range(); @@ -1593,7 +1620,8 @@ export class Parser extends DiagnosticEmitter { } } -const enum Precedence { +/** Operator precedence from least to largest. */ +export const enum Precedence { COMMA, SPREAD, YIELD, diff --git a/src/program.ts b/src/program.ts index 8f7d1984..e15a6e9d 100644 --- a/src/program.ts +++ b/src/program.ts @@ -37,6 +37,7 @@ import { Modifier, NamespaceDeclaration, Statement, + TypeDeclaration, TypeParameter, VariableLikeDeclarationStatement, VariableDeclaration, @@ -148,6 +149,10 @@ export class Program extends DiagnosticEmitter { this.initializeNamespace(statement); break; + case NodeKind.TYPEDECLARATION: + this.initializeType(statement); + break; + case NodeKind.VARIABLE: this.initializeVariables(statement); break; @@ -641,6 +646,10 @@ export class Program extends DiagnosticEmitter { this.initializeNamespace(members[i], namespace); break; + case NodeKind.TYPEDECLARATION: + this.initializeType(members[i], namespace); + break; + case NodeKind.VARIABLE: this.initializeVariables(members[i], namespace); break; @@ -651,6 +660,17 @@ export class Program extends DiagnosticEmitter { } } + private initializeType(declaration: TypeDeclaration, namespace: Element | null = null): void { + // type aliases are program globals + const name: string = declaration.name.name; + if (this.types.has(name)) { + this.error(DiagnosticCode.Duplicate_identifier_0, declaration.name.range, name); + return; + } + // TODO: queue, then resolve + throw new Error("not implemented"); + } + private initializeVariables(statement: VariableStatement, namespace: Element | null = null): void { const declarations: VariableDeclaration[] = statement.declarations; for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i) { diff --git a/src/tokenizer.ts b/src/tokenizer.ts index 6d849de9..8aabaef0 100644 --- a/src/tokenizer.ts +++ b/src/tokenizer.ts @@ -24,6 +24,7 @@ import { Source } from "./ast"; import { CharCode, isLineBreak, isWhiteSpace, isIdentifierStart, isIdentifierPart, isDecimalDigit, isOctalDigit, isKeywordCharacter } from "./util/charcode"; import { I64 } from "./util/i64"; +/** Named token types. */ export enum Token { // keywords @@ -161,69 +162,72 @@ export enum Token { ENDOFFILE } -const textToKeywordToken: Map = new Map([ - ["abstract", Token.ABSTRACT], - ["as", Token.AS], - ["async", Token.ASYNC], - ["await", Token.AWAIT], - ["break", Token.BREAK], - ["case", Token.CASE], - ["catch", Token.CATCH], - ["class", Token.CLASS], - ["continue", Token.CONTINUE], - ["const", Token.CONST], - ["constructor", Token.CONSTRUCTOR], - ["debugger", Token.DEBUGGER], - ["declare", Token.DECLARE], - ["default", Token.DEFAULT], - ["delete", Token.DELETE], - ["do", Token.DO], - ["else", Token.ELSE], - ["enum", Token.ENUM], - ["export", Token.EXPORT], - ["extends", Token.EXTENDS], - ["false", Token.FALSE], - ["finally", Token.FINALLY], - ["for", Token.FOR], - ["from", Token.FROM], - ["function", Token.FUNCTION], - ["get", Token.GET], - ["if", Token.IF], - ["implements", Token.IMPLEMENTS], - ["import", Token.IMPORT], - ["in", Token.IN], - ["instanceof", Token.INSTANCEOF], - ["interface", Token.INTERFACE], - ["is", Token.IS], - ["keyof", Token.KEYOF], - ["let", Token.LET], - ["module", Token.MODULE], - ["namespace", Token.NAMESPACE], - ["new", Token.NEW], - ["null", Token.NULL], - ["of", Token.OF], - ["package", Token.PACKAGE], - ["private", Token.PRIVATE], - ["protected", Token.PROTECTED], - ["public", Token.PUBLIC], - ["readonly", Token.READONLY], - ["return", Token.RETURN], - ["set", Token.SET], - ["static", Token.STATIC], - ["super", Token.SUPER], - ["switch", Token.SWITCH], - ["this", Token.THIS], - ["throw", Token.THROW], - ["true", Token.TRUE], - ["try", Token.TRY], - ["type", Token.TYPE], - ["typeof", Token.TYPEOF], - ["var", Token.VAR], - ["void", Token.VOID], - ["while", Token.WHILE], - ["with", Token.WITH], - ["yield", Token.YIELD] -]); +function textToKeywordToken(text: string): 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 { switch (token) { @@ -279,13 +283,26 @@ export function operatorTokenToString(token: Token): string { } } -const possibleIdentifiers: Set = new Set([ - "from", - "global", - "module", - "namespace", - "type" -]); +function isPossibleIdentifier(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; + } +} export class Range { @@ -658,8 +675,9 @@ export class Tokenizer extends DiagnosticEmitter { } } const keywordText: string = text.substring(posBefore, this.pos); - if (textToKeywordToken.has(keywordText) && !(preferIdentifier && possibleIdentifiers.has(keywordText))) - return textToKeywordToken.get(keywordText); + const keywordToken: Token = textToKeywordToken(keywordText); + if (keywordToken != Token.INVALID && !(preferIdentifier && isPossibleIdentifier(keywordToken))) + return keywordToken; this.pos = posBefore; } return Token.IDENTIFIER; // expects a call to readIdentifier diff --git a/tests/parser/do.ts b/tests/parser/do.ts index f7c1dc71..f67e5098 100644 --- a/tests/parser/do.ts +++ b/tests/parser/do.ts @@ -1,3 +1,5 @@ do { ; } while (a != b); + +do b; while (a); diff --git a/tests/parser/do.ts.fixture.ts b/tests/parser/do.ts.fixture.ts index 900eeaad..38f6aeec 100644 --- a/tests/parser/do.ts.fixture.ts +++ b/tests/parser/do.ts.fixture.ts @@ -1,3 +1,5 @@ do { ; } while (a != b); +do b; +while (a); diff --git a/tests/parser/literals.ts b/tests/parser/literals.ts index 4795d626..f143c24b 100644 --- a/tests/parser/literals.ts +++ b/tests/parser/literals.ts @@ -8,6 +8,7 @@ 7; 8; 9; +2147483647; 0x0; 0x1; 0x2; @@ -24,12 +25,14 @@ 0xD; 0xE; 0xF; +0x7FFFFFFF; 0xa; 0xb; 0xc; 0xd; 0xe; 0xf; +0x7fffffff; 0o0; 0o1; 0o2; @@ -38,5 +41,7 @@ 0o5; 0o6; 0o7; +0o17777777777; 0b0; 0b1; +0b1111111111111111111111111111111; diff --git a/tests/parser/literals.ts.fixture.ts b/tests/parser/literals.ts.fixture.ts index 80d52713..d4baa600 100644 --- a/tests/parser/literals.ts.fixture.ts +++ b/tests/parser/literals.ts.fixture.ts @@ -8,6 +8,7 @@ 7; 8; 9; +2147483647; 0; 1; 2; @@ -24,12 +25,14 @@ 13; 14; 15; +2147483647; 10; 11; 12; 13; 14; 15; +2147483647; 0; 1; 2; @@ -38,5 +41,7 @@ 5; 6; 7; +2147483647; 0; 1; +2147483647; diff --git a/tests/parser/type.ts b/tests/parser/type.ts new file mode 100644 index 00000000..ed301e91 --- /dev/null +++ b/tests/parser/type.ts @@ -0,0 +1,3 @@ +type int32_t = i32; +@nonportable() +export type uint64_t = u64; diff --git a/tests/parser/type.ts.fixture.ts b/tests/parser/type.ts.fixture.ts new file mode 100644 index 00000000..ed301e91 --- /dev/null +++ b/tests/parser/type.ts.fixture.ts @@ -0,0 +1,3 @@ +type int32_t = i32; +@nonportable() +export type uint64_t = u64; diff --git a/tests/parser/while.ts b/tests/parser/while.ts index 1166ab96..709814c0 100644 --- a/tests/parser/while.ts +++ b/tests/parser/while.ts @@ -1,9 +1,10 @@ while (1) { ; } -while (true) { +while (false) { ; } while ("str") { ; } +while (1); diff --git a/tests/parser/while.ts.fixture.ts b/tests/parser/while.ts.fixture.ts index d3d34101..aae7ffd0 100644 --- a/tests/parser/while.ts.fixture.ts +++ b/tests/parser/while.ts.fixture.ts @@ -1,9 +1,10 @@ while (1) { ; } -while (true) { +while (false) { ; } while ("str") { ; } +while (1) ;