Type declaration parsing; Future feature references

This commit is contained in:
dcodeIO 2017-12-19 17:49:15 +01:00
parent aa563a9a5a
commit 9632777842
18 changed files with 364 additions and 172 deletions

101
package-lock.json generated
View File

@ -19,14 +19,21 @@
"integrity": "sha512-q3zfJvaTroV5BjAAR+peTHEGAAhGrPX0z2EzCzpt2mwFA+qzUn2nigJLqSekXRtdULKmT8am7zjvTMZSapIgHw==", "integrity": "sha512-q3zfJvaTroV5BjAAR+peTHEGAAhGrPX0z2EzCzpt2mwFA+qzUn2nigJLqSekXRtdULKmT8am7zjvTMZSapIgHw==",
"dev": true "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": { "@types/glob": {
"version": "5.0.33", "version": "5.0.34",
"resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.33.tgz", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-5.0.34.tgz",
"integrity": "sha512-BcD4yyWz+qmCggaYMSFF0Xn7GkO6tgwm3Fh9Gxk/kQmEU3Z7flQTnVlMyKBUNvXXNTCCyjqK4XT4/2hLd1gQ2A==", "integrity": "sha512-sUvpieq+HsWTLdkeOI8Mi8u22Ag3AoGuM3sv+XMP1bKtbaIAHpEA2f52K2mz6vK5PVhTa3bFyRZLZMqTxOo2Cw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/minimatch": "3.0.1", "@types/events": "1.1.0",
"@types/node": "8.0.58" "@types/minimatch": "3.0.2",
"@types/node": "8.5.1"
} }
}, },
"@types/long": { "@types/long": {
@ -36,9 +43,9 @@
"dev": true "dev": true
}, },
"@types/minimatch": { "@types/minimatch": {
"version": "3.0.1", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.2.tgz",
"integrity": "sha512-rUO/jz10KRSyA9SHoCWQ8WX9BICyj5jZYu1/ucKEJKb4KzLZCKMURdYbadP157Q6Zl1x0vHsrU+Z/O0XlhYQDw==", "integrity": "sha512-tctoxbfuMCxeI2CAsnwoZQfaBA+T7gPzDzDuiiFnyCSSyGYEB92cmRTh6E3tdR1hWsprbJ9IdbvX3PzLmJU/GA==",
"dev": true "dev": true
}, },
"@types/minimist": { "@types/minimist": {
@ -48,9 +55,21 @@
"dev": true "dev": true
}, },
"@types/node": { "@types/node": {
"version": "8.0.58", "version": "8.5.1",
"resolved": "https://registry.npmjs.org/@types/node/-/node-8.0.58.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-8.5.1.tgz",
"integrity": "sha512-V746iUU7eHNdzQipoACuguDlVhC7IHK8CES1jSkuFt352wwA84BCWPXaGekBd7R5XdNK5ReHONDVKxlL9IreAw==" "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": { "acorn": {
"version": "4.0.13", "version": "4.0.13",
@ -937,6 +956,15 @@
"minimalistic-crypto-utils": "1.0.1" "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": { "hosted-git-info": {
"version": "2.5.0", "version": "2.5.0",
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz",
@ -1536,6 +1564,12 @@
"error-ex": "1.3.1" "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": { "path-browserify": {
"version": "0.0.0", "version": "0.0.0",
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz", "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",
@ -2049,9 +2083,9 @@
} }
}, },
"ts-node": { "ts-node": {
"version": "3.3.0", "version": "4.0.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-3.3.0.tgz", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-4.0.2.tgz",
"integrity": "sha1-wTxqMCTjC+EYDdUwOPwgkonUv2k=", "integrity": "sha512-mg7l6ON8asjnfzkTi1LFWKaOGHl5Jf1+5ij0MQ502YfC6+4FBgh/idJgw9aN9kei1Rf4/pmFpNuFE1YbcQdOTA==",
"dev": true, "dev": true,
"requires": { "requires": {
"arrify": "1.0.1", "arrify": "1.0.1",
@ -2060,29 +2094,20 @@
"make-error": "1.3.0", "make-error": "1.3.0",
"minimist": "1.2.0", "minimist": "1.2.0",
"mkdirp": "0.5.1", "mkdirp": "0.5.1",
"source-map-support": "0.4.18", "source-map-support": "0.5.0",
"tsconfig": "6.0.0", "tsconfig": "7.0.0",
"v8flags": "3.0.0", "v8flags": "3.0.1",
"yn": "2.0.0" "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": { "tsconfig": {
"version": "6.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-6.0.0.tgz", "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz",
"integrity": "sha1-aw6DdgA9evGGT434+J3QBZ/80DI=", "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/strip-bom": "3.0.0",
"@types/strip-json-comments": "0.0.30",
"strip-bom": "3.0.0", "strip-bom": "3.0.0",
"strip-json-comments": "2.0.1" "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": { "util": {
"version": "0.10.3", "version": "0.10.3",
"resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
@ -2190,12 +2209,12 @@
"dev": true "dev": true
}, },
"v8flags": { "v8flags": {
"version": "3.0.0", "version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.0.tgz", "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.0.1.tgz",
"integrity": "sha512-AGl+C+4qpeSu2g3JxCD/mGFFOs/vVZ3XREkD3ibQXEqr4Y4zgIrPWW124/IKJFHOIVFIoH8miWrLf0o84HYjwA==", "integrity": "sha1-3Oj8N5wX2fLJ6e142JzgAFKxt2s=",
"dev": true, "dev": true,
"requires": { "requires": {
"user-home": "1.1.1" "homedir-polyfill": "1.0.1"
} }
}, },
"validate-npm-package-license": { "validate-npm-package-license": {

View File

@ -11,7 +11,7 @@
"url": "https://github.com/AssemblyScript/next/issues" "url": "https://github.com/AssemblyScript/next/issues"
}, },
"dependencies": { "dependencies": {
"@types/node": "^8.0.58", "@types/node": "^8.5.1",
"binaryen": "40.0.0-nightly.20171209", "binaryen": "40.0.0-nightly.20171209",
"glob": "^7.1.2", "glob": "^7.1.2",
"minimist": "^1.2.0", "minimist": "^1.2.0",
@ -20,14 +20,14 @@
"devDependencies": { "devDependencies": {
"@types/chalk": "^2.2.0", "@types/chalk": "^2.2.0",
"@types/diff": "^3.2.2", "@types/diff": "^3.2.2",
"@types/glob": "^5.0.33", "@types/glob": "^5.0.34",
"@types/long": "^3.0.32", "@types/long": "^3.0.32",
"@types/minimist": "^1.2.0", "@types/minimist": "^1.2.0",
"chalk": "^2.3.0", "chalk": "^2.3.0",
"diff": "^3.4.0", "diff": "^3.4.0",
"long": "^3.2.0", "long": "^3.2.0",
"ts-loader": "^3.2.0", "ts-loader": "^3.2.0",
"ts-node": "^3.3.0", "ts-node": "^4.0.2",
"typescript": "^2.6.2", "typescript": "^2.6.2",
"webpack": "^3.10.0" "webpack": "^3.10.0"
}, },

View File

@ -62,6 +62,7 @@ export enum NodeKind {
SWITCH, SWITCH,
THROW, THROW,
TRY, TRY,
TYPEDECLARATION,
VARIABLE, // wraps declarations VARIABLE, // wraps declarations
VARIABLEDECLARATION, VARIABLEDECLARATION,
WHILE, WHILE,
@ -542,6 +543,17 @@ export abstract class Node {
return stmt; 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 = (<Modifier[]>modifiers).length; i < k; ++i) (<Modifier[]>modifiers)[i].parent = stmt;
if (stmt.decorators = decorators) for (i = 0, k = (<Decorator[]>decorators).length; i < k; ++i) (<Decorator[]>decorators)[i].parent = stmt;
return stmt;
}
static createVariable(declarations: VariableDeclaration[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): VariableStatement { static createVariable(declarations: VariableDeclaration[], modifiers: Modifier[] | null, decorators: Decorator[] | null, range: Range): VariableStatement {
const stmt: VariableStatement = new VariableStatement(); const stmt: VariableStatement = new VariableStatement();
stmt.range = range; stmt.range = range;
@ -552,10 +564,10 @@ export abstract class Node {
return stmt; 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(); const elem: VariableDeclaration = new VariableDeclaration();
elem.range = range; elem.range = range;
(elem.name = identifier).parent = elem; (elem.name = name).parent = elem;
if (elem.type = type) (<TypeNode>type).parent = elem; if (elem.type = type) (<TypeNode>type).parent = elem;
if (elem.initializer = initializer) (<Expression>initializer).parent = elem; if (elem.initializer = initializer) (<Expression>initializer).parent = elem;
elem.modifiers = modifiers; elem.modifiers = modifiers;
@ -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 = (<Modifier[]>this.modifiers).length; i < k; ++i) {
(<Modifier[]>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}. */ /** Represents a single variable declaration within a {@link VariableStatement}. */
export class VariableDeclaration extends VariableLikeDeclarationStatement { export class VariableDeclaration extends VariableLikeDeclarationStatement {

View File

@ -42,6 +42,8 @@ export function initialize(program: Program): void {
// host operations // host operations
addFunction(program, "current_memory"); addFunction(program, "current_memory");
addFunction(program, "grow_memory"); addFunction(program, "grow_memory");
// addFunction(program, "move_memory");
// addFunction(program, "set_memory");
// imported // imported
addFunction(program, "parseInt"); addFunction(program, "parseInt");
@ -589,6 +591,29 @@ export function compileCall(compiler: Compiler, prototype: FunctionPrototype, ty
arg0 = compiler.compileExpression(operands[0], Type.i32); arg0 = compiler.compileExpression(operands[0], Type.i32);
return module.createHost(HostOp.GrowMemory, null, [ arg0 ]); 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 // imported
case "parseInt": // takes a pointer to the string case "parseInt": // takes a pointer to the string

View File

@ -1139,9 +1139,9 @@ export class Compiler extends DiagnosticEmitter {
if (fromType.kind == TypeKind.F32) { if (fromType.kind == TypeKind.F32) {
if (toType.isSignedInteger) { if (toType.isSignedInteger) {
if (toType.isLongInteger) if (toType.isLongInteger)
expr = mod.createUnary(UnaryOp.TruncF32_I64, expr); expr = mod.createUnary(UnaryOp.TruncF32ToI64, expr);
else { else {
expr = mod.createUnary(UnaryOp.TruncF32_I32, expr); expr = mod.createUnary(UnaryOp.TruncF32ToI32, expr);
if (toType.isSmallInteger) { if (toType.isSmallInteger) {
expr = mod.createBinary(BinaryOp.ShlI32, expr, mod.createI32(toType.smallIntegerShift)); expr = mod.createBinary(BinaryOp.ShlI32, expr, mod.createI32(toType.smallIntegerShift));
expr = mod.createBinary(BinaryOp.ShrI32, 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 { } else {
if (toType.isLongInteger) if (toType.isLongInteger)
expr = mod.createUnary(UnaryOp.TruncF32_U64, expr); expr = mod.createUnary(UnaryOp.TruncF32ToU64, expr);
else { else {
expr = mod.createUnary(UnaryOp.TruncF32_U32, expr); expr = mod.createUnary(UnaryOp.TruncF32ToU32, expr);
if (toType.isSmallInteger) if (toType.isSmallInteger)
expr = mod.createBinary(BinaryOp.AndI32, expr, mod.createI32(toType.smallIntegerMask)); expr = mod.createBinary(BinaryOp.AndI32, expr, mod.createI32(toType.smallIntegerMask));
} }
@ -1161,9 +1161,9 @@ export class Compiler extends DiagnosticEmitter {
} else { } else {
if (toType.isSignedInteger) { if (toType.isSignedInteger) {
if (toType.isLongInteger) if (toType.isLongInteger)
expr = mod.createUnary(UnaryOp.TruncF64_I64, expr); expr = mod.createUnary(UnaryOp.TruncF64ToI64, expr);
else { else {
expr = mod.createUnary(UnaryOp.TruncF64_I32, expr); expr = mod.createUnary(UnaryOp.TruncF64ToI32, expr);
if (toType.isSmallInteger) { if (toType.isSmallInteger) {
expr = mod.createBinary(BinaryOp.ShlI32, expr, mod.createI32(toType.smallIntegerShift)); expr = mod.createBinary(BinaryOp.ShlI32, expr, mod.createI32(toType.smallIntegerShift));
expr = mod.createBinary(BinaryOp.ShrI32, 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 { } else {
if (toType.isLongInteger) if (toType.isLongInteger)
expr = mod.createUnary(UnaryOp.TruncF64_U64, expr); expr = mod.createUnary(UnaryOp.TruncF64ToU64, expr);
else { else {
expr = mod.createUnary(UnaryOp.TruncF64_U32, expr); expr = mod.createUnary(UnaryOp.TruncF64ToU32, expr);
if (toType.isSmallInteger) if (toType.isSmallInteger)
expr = mod.createBinary(BinaryOp.AndI32, expr, mod.createI32(toType.smallIntegerMask)); expr = mod.createBinary(BinaryOp.AndI32, expr, mod.createI32(toType.smallIntegerMask));
} }
@ -1190,16 +1190,16 @@ export class Compiler extends DiagnosticEmitter {
if (fromType.isLongInteger) { if (fromType.isLongInteger) {
losesInformation = true; losesInformation = true;
if (fromType.isSignedInteger) if (fromType.isSignedInteger)
expr = mod.createUnary(UnaryOp.ConvertI64_F32, expr); expr = mod.createUnary(UnaryOp.ConvertI64ToF32, expr);
else else
expr = mod.createUnary(UnaryOp.ConvertU64_F32, expr); expr = mod.createUnary(UnaryOp.ConvertU64ToF32, expr);
} else { } else {
if (!fromType.isSmallInteger) if (!fromType.isSmallInteger)
losesInformation = true; losesInformation = true;
if (fromType.isSignedInteger) if (fromType.isSignedInteger)
expr = mod.createUnary(UnaryOp.ConvertI32_F32, expr); expr = mod.createUnary(UnaryOp.ConvertI32ToF32, expr);
else else
expr = mod.createUnary(UnaryOp.ConvertU32_F32, expr); expr = mod.createUnary(UnaryOp.ConvertU32ToF32, expr);
} }
// int to f64 // int to f64
@ -1207,14 +1207,14 @@ export class Compiler extends DiagnosticEmitter {
if (fromType.isLongInteger) { if (fromType.isLongInteger) {
losesInformation = true; losesInformation = true;
if (fromType.isSignedInteger) if (fromType.isSignedInteger)
expr = mod.createUnary(UnaryOp.ConvertI64_F64, expr); expr = mod.createUnary(UnaryOp.ConvertI64ToF64, expr);
else else
expr = mod.createUnary(UnaryOp.ConvertU64_F64, expr); expr = mod.createUnary(UnaryOp.ConvertU64ToF64, expr);
} else } else
if (fromType.isSignedInteger) if (fromType.isSignedInteger)
expr = mod.createUnary(UnaryOp.ConvertI32_F64, expr); expr = mod.createUnary(UnaryOp.ConvertI32ToF64, expr);
else else
expr = mod.createUnary(UnaryOp.ConvertU32_F64, expr); expr = mod.createUnary(UnaryOp.ConvertU32ToF64, expr);
} }
// int to int // int to int

View File

@ -339,42 +339,42 @@ export class Decompiler {
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.TruncF32_I32: case UnaryOp.TruncF32ToI32:
this.push("<i32>"); this.push("<i32>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.TruncF32_I64: case UnaryOp.TruncF32ToI64:
this.push("<i64>"); this.push("<i64>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.TruncF32_U32: case UnaryOp.TruncF32ToU32:
this.push("<i32><u32>"); this.push("<i32><u32>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.TruncF32_U64: case UnaryOp.TruncF32ToU64:
this.push("<i64><u64>"); this.push("<i64><u64>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.TruncF64_I32: case UnaryOp.TruncF64ToI32:
this.push("<i32>"); this.push("<i32>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.TruncF64_I64: case UnaryOp.TruncF64ToI64:
this.push("<i64>"); this.push("<i64>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.TruncF64_U32: case UnaryOp.TruncF64ToU32:
this.push("<i32><u32>"); this.push("<i32><u32>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.TruncF64_U64: case UnaryOp.TruncF64ToU64:
this.push("<i64><u64>"); this.push("<i64><u64>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
@ -391,42 +391,42 @@ export class Decompiler {
this.push(")"); this.push(")");
return; return;
case UnaryOp.ConvertI32_F32: case UnaryOp.ConvertI32ToF32:
this.push("<f32>"); this.push("<f32>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.ConvertI32_F64: case UnaryOp.ConvertI32ToF64:
this.push("<f64>"); this.push("<f64>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.ConvertU32_F32: case UnaryOp.ConvertU32ToF32:
this.push("<f32><u32>"); this.push("<f32><u32>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.ConvertU32_F64: case UnaryOp.ConvertU32ToF64:
this.push("<f64><u32>"); this.push("<f64><u32>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.ConvertI64_F32: case UnaryOp.ConvertI64ToF32:
this.push("<f32>"); this.push("<f32>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.ConvertI64_F64: case UnaryOp.ConvertI64ToF64:
this.push("<f64>"); this.push("<f64>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.ConvertU64_F32: case UnaryOp.ConvertU64ToF32:
this.push("<f32><u64>"); this.push("<f32><u64>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;
case UnaryOp.ConvertU64_F64: case UnaryOp.ConvertU64ToF64:
this.push("<f64><u64>"); this.push("<f64><u64>");
this.decompileExpression(_BinaryenUnaryGetValue(expr)); this.decompileExpression(_BinaryenUnaryGetValue(expr));
return; return;

View File

@ -95,28 +95,45 @@ export enum UnaryOp {
ExtendI32 = _BinaryenExtendSInt32(), ExtendI32 = _BinaryenExtendSInt32(),
ExtendU32 = _BinaryenExtendUInt32(), ExtendU32 = _BinaryenExtendUInt32(),
WrapI64 = _BinaryenWrapInt64(), WrapI64 = _BinaryenWrapInt64(),
TruncF32_I32 = _BinaryenTruncSFloat32ToInt32(), TruncF32ToI32 = _BinaryenTruncSFloat32ToInt32(),
TruncF32_I64 = _BinaryenTruncSFloat32ToInt64(), TruncF32ToI64 = _BinaryenTruncSFloat32ToInt64(),
TruncF32_U32 = _BinaryenTruncUFloat32ToInt32(), TruncF32ToU32 = _BinaryenTruncUFloat32ToInt32(),
TruncF32_U64 = _BinaryenTruncUFloat32ToInt64(), TruncF32ToU64 = _BinaryenTruncUFloat32ToInt64(),
TruncF64_I32 = _BinaryenTruncSFloat64ToInt32(), TruncF64ToI32 = _BinaryenTruncSFloat64ToInt32(),
TruncF64_I64 = _BinaryenTruncSFloat64ToInt64(), TruncF64ToI64 = _BinaryenTruncSFloat64ToInt64(),
TruncF64_U32 = _BinaryenTruncUFloat64ToInt32(), TruncF64ToU32 = _BinaryenTruncUFloat64ToInt32(),
TruncF64_U64 = _BinaryenTruncUFloat64ToInt64(), TruncF64ToU64 = _BinaryenTruncUFloat64ToInt64(),
ReinterpretF32 = _BinaryenReinterpretFloat32(), ReinterpretF32 = _BinaryenReinterpretFloat32(),
ReinterpretF64 = _BinaryenReinterpretFloat64(), ReinterpretF64 = _BinaryenReinterpretFloat64(),
ConvertI32_F32 = _BinaryenConvertSInt32ToFloat32(), ConvertI32ToF32 = _BinaryenConvertSInt32ToFloat32(),
ConvertI32_F64 = _BinaryenConvertSInt32ToFloat64(), ConvertI32ToF64 = _BinaryenConvertSInt32ToFloat64(),
ConvertU32_F32 = _BinaryenConvertUInt32ToFloat32(), ConvertU32ToF32 = _BinaryenConvertUInt32ToFloat32(),
ConvertU32_F64 = _BinaryenConvertUInt32ToFloat64(), ConvertU32ToF64 = _BinaryenConvertUInt32ToFloat64(),
ConvertI64_F32 = _BinaryenConvertSInt64ToFloat32(), ConvertI64ToF32 = _BinaryenConvertSInt64ToFloat32(),
ConvertI64_F64 = _BinaryenConvertSInt64ToFloat64(), ConvertI64ToF64 = _BinaryenConvertSInt64ToFloat64(),
ConvertU64_F32 = _BinaryenConvertUInt64ToFloat32(), ConvertU64ToF32 = _BinaryenConvertUInt64ToFloat32(),
ConvertU64_F64 = _BinaryenConvertUInt64ToFloat64(), ConvertU64ToF64 = _BinaryenConvertUInt64ToFloat64(),
PromoteF32 = _BinaryenPromoteFloat32(), PromoteF32 = _BinaryenPromoteFloat32(),
DemoteF64 = _BinaryenDemoteFloat64(), DemoteF64 = _BinaryenDemoteFloat64(),
ReinterpretI32 = _BinaryenReinterpretInt32(), ReinterpretI32 = _BinaryenReinterpretInt32(),
ReinterpretI64 = _BinaryenReinterpretInt64() 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 { export enum BinaryOp {
@ -202,7 +219,11 @@ export enum HostOp {
PageSize = _BinaryenPageSize(), PageSize = _BinaryenPageSize(),
CurrentMemory = _BinaryenCurrentMemory(), CurrentMemory = _BinaryenCurrentMemory(),
GrowMemory = _BinaryenGrowMemory(), 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 { export enum AtomicRMWOp {

View File

@ -59,6 +59,7 @@ import {
SwitchStatement, SwitchStatement,
ThrowStatement, ThrowStatement,
TryStatement, TryStatement,
TypeDeclaration,
TypeParameter, TypeParameter,
VariableStatement, VariableStatement,
VariableDeclaration, VariableDeclaration,
@ -193,7 +194,9 @@ export class Parser extends DiagnosticEmitter {
break; break;
case Token.TYPE: case Token.TYPE:
// TODO statement = this.parseTypeDeclaration(tn, modifiers, decorators);
decorators = null;
break;
default: default:
if (hasModifier(ModifierKind.EXPORT, modifiers)) { if (hasModifier(ModifierKind.EXPORT, modifiers)) {
@ -718,7 +721,7 @@ export class Parser extends DiagnosticEmitter {
isSetter = true; 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 const identifier: IdentifierExpression = tn.token == Token.CONSTRUCTOR
? Node.createConstructor(tn.range()) ? Node.createConstructor(tn.range())
: Node.createIdentifier(tn.readIdentifier(), tn.range()); : Node.createIdentifier(tn.readIdentifier(), tn.range());
@ -1017,6 +1020,9 @@ export class Parser extends DiagnosticEmitter {
case Token.TRY: case Token.TRY:
return this.parseTryStatement(tn); return this.parseTryStatement(tn);
case Token.TYPE:
return this.parseTypeDeclaration(tn, null);
case Token.WHILE: case Token.WHILE:
return this.parseWhileStatement(tn); return this.parseWhileStatement(tn);
@ -1311,6 +1317,27 @@ export class Parser extends DiagnosticEmitter {
return null; 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 { parseWhileStatement(tn: Tokenizer): WhileStatement | null {
// at 'while': '(' Expression ')' Statement ';'? // at 'while': '(' Expression ')' Statement ';'?
const startRange: Range = tn.range(); 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, COMMA,
SPREAD, SPREAD,
YIELD, YIELD,

View File

@ -37,6 +37,7 @@ import {
Modifier, Modifier,
NamespaceDeclaration, NamespaceDeclaration,
Statement, Statement,
TypeDeclaration,
TypeParameter, TypeParameter,
VariableLikeDeclarationStatement, VariableLikeDeclarationStatement,
VariableDeclaration, VariableDeclaration,
@ -148,6 +149,10 @@ export class Program extends DiagnosticEmitter {
this.initializeNamespace(<NamespaceDeclaration>statement); this.initializeNamespace(<NamespaceDeclaration>statement);
break; break;
case NodeKind.TYPEDECLARATION:
this.initializeType(<TypeDeclaration>statement);
break;
case NodeKind.VARIABLE: case NodeKind.VARIABLE:
this.initializeVariables(<VariableStatement>statement); this.initializeVariables(<VariableStatement>statement);
break; break;
@ -641,6 +646,10 @@ export class Program extends DiagnosticEmitter {
this.initializeNamespace(<NamespaceDeclaration>members[i], namespace); this.initializeNamespace(<NamespaceDeclaration>members[i], namespace);
break; break;
case NodeKind.TYPEDECLARATION:
this.initializeType(<TypeDeclaration>members[i], namespace);
break;
case NodeKind.VARIABLE: case NodeKind.VARIABLE:
this.initializeVariables(<VariableStatement>members[i], namespace); this.initializeVariables(<VariableStatement>members[i], namespace);
break; 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 { private initializeVariables(statement: VariableStatement, namespace: Element | null = null): void {
const declarations: VariableDeclaration[] = statement.declarations; const declarations: VariableDeclaration[] = statement.declarations;
for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i) { for (let i: i32 = 0, k: i32 = declarations.length; i < k; ++i) {

View File

@ -24,6 +24,7 @@ import { Source } from "./ast";
import { CharCode, isLineBreak, isWhiteSpace, isIdentifierStart, isIdentifierPart, isDecimalDigit, isOctalDigit, isKeywordCharacter } from "./util/charcode"; import { CharCode, isLineBreak, isWhiteSpace, isIdentifierStart, isIdentifierPart, isDecimalDigit, isOctalDigit, isKeywordCharacter } from "./util/charcode";
import { I64 } from "./util/i64"; import { I64 } from "./util/i64";
/** Named token types. */
export enum Token { export enum Token {
// keywords // keywords
@ -161,69 +162,72 @@ export enum Token {
ENDOFFILE ENDOFFILE
} }
const textToKeywordToken: Map<string,Token> = new Map([ function textToKeywordToken(text: string): Token {
["abstract", Token.ABSTRACT], switch (text) {
["as", Token.AS], case "abstract": return Token.ABSTRACT;
["async", Token.ASYNC], case "as": return Token.AS;
["await", Token.AWAIT], case "async": return Token.ASYNC;
["break", Token.BREAK], case "await": return Token.AWAIT;
["case", Token.CASE], case "break": return Token.BREAK;
["catch", Token.CATCH], case "case": return Token.CASE;
["class", Token.CLASS], case "catch": return Token.CATCH;
["continue", Token.CONTINUE], case "class": return Token.CLASS;
["const", Token.CONST], case "continue": return Token.CONTINUE;
["constructor", Token.CONSTRUCTOR], case "const": return Token.CONST;
["debugger", Token.DEBUGGER], case "constructor": return Token.CONSTRUCTOR;
["declare", Token.DECLARE], case "debugger": return Token.DEBUGGER;
["default", Token.DEFAULT], case "declare": return Token.DECLARE;
["delete", Token.DELETE], case "default": return Token.DEFAULT;
["do", Token.DO], case "delete": return Token.DELETE;
["else", Token.ELSE], case "do": return Token.DO;
["enum", Token.ENUM], case "else": return Token.ELSE;
["export", Token.EXPORT], case "enum": return Token.ENUM;
["extends", Token.EXTENDS], case "export": return Token.EXPORT;
["false", Token.FALSE], case "extends": return Token.EXTENDS;
["finally", Token.FINALLY], case "false": return Token.FALSE;
["for", Token.FOR], case "finally": return Token.FINALLY;
["from", Token.FROM], case "for": return Token.FOR;
["function", Token.FUNCTION], case "from": return Token.FROM;
["get", Token.GET], case "function": return Token.FUNCTION;
["if", Token.IF], case "get": return Token.GET;
["implements", Token.IMPLEMENTS], case "if": return Token.IF;
["import", Token.IMPORT], case "implements": return Token.IMPLEMENTS;
["in", Token.IN], case "import": return Token.IMPORT;
["instanceof", Token.INSTANCEOF], case "in": return Token.IN;
["interface", Token.INTERFACE], case "instanceof": return Token.INSTANCEOF;
["is", Token.IS], case "interface": return Token.INTERFACE;
["keyof", Token.KEYOF], case "is": return Token.IS;
["let", Token.LET], case "keyof": return Token.KEYOF;
["module", Token.MODULE], case "let": return Token.LET;
["namespace", Token.NAMESPACE], case "module": return Token.MODULE;
["new", Token.NEW], case "namespace": return Token.NAMESPACE;
["null", Token.NULL], case "new": return Token.NEW;
["of", Token.OF], case "null": return Token.NULL;
["package", Token.PACKAGE], case "of": return Token.OF;
["private", Token.PRIVATE], case "package": return Token.PACKAGE;
["protected", Token.PROTECTED], case "private": return Token.PRIVATE;
["public", Token.PUBLIC], case "protected": return Token.PROTECTED;
["readonly", Token.READONLY], case "public": return Token.PUBLIC;
["return", Token.RETURN], case "readonly": return Token.READONLY;
["set", Token.SET], case "return": return Token.RETURN;
["static", Token.STATIC], case "set": return Token.SET;
["super", Token.SUPER], case "static": return Token.STATIC;
["switch", Token.SWITCH], case "super": return Token.SUPER;
["this", Token.THIS], case "switch": return Token.SWITCH;
["throw", Token.THROW], case "this": return Token.THIS;
["true", Token.TRUE], case "throw": return Token.THROW;
["try", Token.TRY], case "true": return Token.TRUE;
["type", Token.TYPE], case "try": return Token.TRY;
["typeof", Token.TYPEOF], case "type": return Token.TYPE;
["var", Token.VAR], case "typeof": return Token.TYPEOF;
["void", Token.VOID], case "var": return Token.VAR;
["while", Token.WHILE], case "void": return Token.VOID;
["with", Token.WITH], case "while": return Token.WHILE;
["yield", Token.YIELD] case "with": return Token.WITH;
]); case "yield": return Token.YIELD;
default: return Token.INVALID;
}
}
export function operatorTokenToString(token: Token): string { export function operatorTokenToString(token: Token): string {
switch (token) { switch (token) {
@ -279,13 +283,26 @@ export function operatorTokenToString(token: Token): string {
} }
} }
const possibleIdentifiers: Set<string> = new Set([ function isPossibleIdentifier(token: Token): bool {
"from", switch (token) {
"global", case Token.ABSTRACT:
"module", case Token.AS:
"namespace", case Token.CONSTRUCTOR:
"type" 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 { export class Range {
@ -658,8 +675,9 @@ export class Tokenizer extends DiagnosticEmitter {
} }
} }
const keywordText: string = text.substring(posBefore, this.pos); const keywordText: string = text.substring(posBefore, this.pos);
if (textToKeywordToken.has(keywordText) && !(preferIdentifier && possibleIdentifiers.has(keywordText))) const keywordToken: Token = textToKeywordToken(keywordText);
return <Token>textToKeywordToken.get(keywordText); if (keywordToken != Token.INVALID && !(preferIdentifier && isPossibleIdentifier(keywordToken)))
return keywordToken;
this.pos = posBefore; this.pos = posBefore;
} }
return Token.IDENTIFIER; // expects a call to readIdentifier return Token.IDENTIFIER; // expects a call to readIdentifier

View File

@ -1,3 +1,5 @@
do { do {
; ;
} while (a != b); } while (a != b);
do b; while (a);

View File

@ -1,3 +1,5 @@
do { do {
; ;
} while (a != b); } while (a != b);
do b;
while (a);

View File

@ -8,6 +8,7 @@
7; 7;
8; 8;
9; 9;
2147483647;
0x0; 0x0;
0x1; 0x1;
0x2; 0x2;
@ -24,12 +25,14 @@
0xD; 0xD;
0xE; 0xE;
0xF; 0xF;
0x7FFFFFFF;
0xa; 0xa;
0xb; 0xb;
0xc; 0xc;
0xd; 0xd;
0xe; 0xe;
0xf; 0xf;
0x7fffffff;
0o0; 0o0;
0o1; 0o1;
0o2; 0o2;
@ -38,5 +41,7 @@
0o5; 0o5;
0o6; 0o6;
0o7; 0o7;
0o17777777777;
0b0; 0b0;
0b1; 0b1;
0b1111111111111111111111111111111;

View File

@ -8,6 +8,7 @@
7; 7;
8; 8;
9; 9;
2147483647;
0; 0;
1; 1;
2; 2;
@ -24,12 +25,14 @@
13; 13;
14; 14;
15; 15;
2147483647;
10; 10;
11; 11;
12; 12;
13; 13;
14; 14;
15; 15;
2147483647;
0; 0;
1; 1;
2; 2;
@ -38,5 +41,7 @@
5; 5;
6; 6;
7; 7;
2147483647;
0; 0;
1; 1;
2147483647;

3
tests/parser/type.ts Normal file
View File

@ -0,0 +1,3 @@
type int32_t = i32;
@nonportable()
export type uint64_t = u64;

View File

@ -0,0 +1,3 @@
type int32_t = i32;
@nonportable()
export type uint64_t = u64;

View File

@ -1,9 +1,10 @@
while (1) { while (1) {
; ;
} }
while (true) { while (false) {
; ;
} }
while ("str") { while ("str") {
; ;
} }
while (1);

View File

@ -1,9 +1,10 @@
while (1) { while (1) {
; ;
} }
while (true) { while (false) {
; ;
} }
while ("str") { while ("str") {
; ;
} }
while (1) ;