diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..efb5d586 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +dist: trusty +language: node_js +node_js: + - 8 +jobs: + include: + - stage: test + script: npm test + - stage: build + script: npm run build diff --git a/README.md b/README.md index f04dd021..e5943814 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ AssemblyScript NEXT =================== +[![Build Status](https://travis-ci.org/AssemblyScript/next.svg?branch=master)](https://travis-ci.org/AssemblyScript/next) + This repository contains compiler component prototypes for the next iteration of the AssemblyScript compiler written in AssemblyScript itself. Note that the code uses some features and standard library components that are not yet supported by any version of asc. To account for this, the code has been written in "portable AssemblyScript", a TypeScript-compatible subset of a subset of a superset of JavaScript, that also compiles to JavaScript using TSC. diff --git a/src/compiler.ts b/src/compiler.ts index 9686ff71..04389f46 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -766,17 +766,18 @@ export class Compiler extends DiagnosticEmitter { const breaks: ExpressionRef[] = new Array(1 + k); breaks[0] = this.module.createSetLocal(local.index, this.compileExpression(statement.expression, Type.i32)); // initializer - // make one br_if per (possibly dynamic) labeled case - // TODO: take advantage of br_table where labels are known to be (sequential) constant (ideally the optimizer would) + // make one br_if per (possibly dynamic) labeled case (binaryen optimizes to br_table where possible) let breakIndex: i32 = 1; let defaultIndex: i32 = -1; for (i = 0; i < k; ++i) { const case_: SwitchCase = statement.cases[i]; if (case_.label) { - breaks[breakIndex++] = this.module.createBreak("case" + i.toString(10) + "$" + context, this.module.createBinary(BinaryOp.EqI32, - this.module.createGetLocal(local.index, NativeType.I32), - this.compileExpression(case_.label, Type.i32) - )); + breaks[breakIndex++] = this.module.createBreak("case" + i.toString(10) + "$" + context, + this.module.createBinary(BinaryOp.EqI32, + this.module.createGetLocal(local.index, NativeType.I32), + this.compileExpression(case_.label, Type.i32) + ) + ); } else defaultIndex = i; } diff --git a/src/parser.ts b/src/parser.ts index df1a796d..0a8850ae 100644 --- a/src/parser.ts +++ b/src/parser.ts @@ -1118,8 +1118,7 @@ export class Parser extends DiagnosticEmitter { this.error(DiagnosticCode._0_expected, tn.range(), ":"); // 'default' ':' Statement* - } else if (tn.nextToken == Token.DEFAULT) { - tn.next(); + } else if (tn.skip(Token.DEFAULT)) { if (tn.skip(Token.COLON)) { const statements: Statement[] = new Array(); while (tn.peek() != Token.CASE && tn.nextToken != Token.DEFAULT && tn.nextToken != Token.CLOSEBRACE) { diff --git a/src/tsconfig.json b/src/tsconfig.json index 1472d176..bedfa6d4 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -28,7 +28,7 @@ "glue/js.d.ts", "glue/js.ts", "index.ts", - "moddule.ts", + "module.ts", "parser.ts", "program.ts", "tokenizer.ts", diff --git a/tests/compiler/switch.ts b/tests/compiler/switch.ts new file mode 100644 index 00000000..c787b9a7 --- /dev/null +++ b/tests/compiler/switch.ts @@ -0,0 +1,35 @@ +export function doSwitch(n: i32): i32 { + switch (n) { + case 1: + return 1; + case 0: + default: + return 0; + case 2: + case 3: + return 23; + } +} + +export function doSwitchDefaultFirst(n: i32): i32 { + switch (n) { + default: + return 0; + case 1: + return 1; + case 2: + case 3: + return 23; + } +} + +export function doSwitchDefaultOmitted(n: i32): i32 { + switch (n) { + case 1: + return 1; + case 2: + case 3: + return 23; + } + return 0; +} diff --git a/tests/compiler/switch.wast b/tests/compiler/switch.wast new file mode 100644 index 00000000..9f8f96f8 --- /dev/null +++ b/tests/compiler/switch.wast @@ -0,0 +1,170 @@ +(module + (type $ii (func (param i32) (result i32))) + (memory $0 1) + (data (i32.const 4) "\08\00\00\00") + (export "memory" (memory $0)) + (func $switch/doSwitch (; 0 ;) (type $ii) (param $0 i32) (result i32) + (local $1 i32) + (block $break$1.1 + (block $case4$1.1 + (block $case3$1.1 + (block $case2$1.1 + (block $case1$1.1 + (block $case0$1.1 + (set_local $1 + (get_local $0) + ) + (br_if $case0$1.1 + (i32.eq + (get_local $1) + (i32.const 1) + ) + ) + (br_if $case1$1.1 + (i32.eq + (get_local $1) + (i32.const 0) + ) + ) + (br_if $case3$1.1 + (i32.eq + (get_local $1) + (i32.const 2) + ) + ) + (br_if $case4$1.1 + (i32.eq + (get_local $1) + (i32.const 3) + ) + ) + (br $case2$1.1) + ) + (return + (i32.const 1) + ) + ) + ) + (return + (i32.const 0) + ) + ) + ) + (return + (i32.const 23) + ) + ) + ) + (func $switch/doSwitchDefaultFirst (; 1 ;) (type $ii) (param $0 i32) (result i32) + (local $1 i32) + (block $break$1.1 + (block $case3$1.1 + (block $case2$1.1 + (block $case1$1.1 + (block $case0$1.1 + (set_local $1 + (get_local $0) + ) + (br_if $case1$1.1 + (i32.eq + (get_local $1) + (i32.const 1) + ) + ) + (br_if $case2$1.1 + (i32.eq + (get_local $1) + (i32.const 2) + ) + ) + (br_if $case3$1.1 + (i32.eq + (get_local $1) + (i32.const 3) + ) + ) + (br $case0$1.1) + ) + (return + (i32.const 0) + ) + ) + (return + (i32.const 1) + ) + ) + ) + (return + (i32.const 23) + ) + ) + ) + (func $switch/doSwitchDefaultOmitted (; 2 ;) (type $ii) (param $0 i32) (result i32) + (local $1 i32) + (block $break$1.1 + (block $case2$1.1 + (block $case1$1.1 + (block $case0$1.1 + (set_local $1 + (get_local $0) + ) + (br_if $case0$1.1 + (i32.eq + (get_local $1) + (i32.const 1) + ) + ) + (br_if $case1$1.1 + (i32.eq + (get_local $1) + (i32.const 2) + ) + ) + (br_if $case2$1.1 + (i32.eq + (get_local $1) + (i32.const 3) + ) + ) + (br $break$1.1) + ) + (return + (i32.const 1) + ) + ) + ) + (return + (i32.const 23) + ) + ) + (return + (i32.const 0) + ) + ) +) +(; +[program.elements] + clz + ctz + popcnt + rotl + rotr + abs + ceil + copysign + floor + max + min + nearest + sqrt + trunc + isNaN + isFinite + switch/doSwitch + switch/doSwitchDefaultFirst + switch/doSwitchDefaultOmitted +[program.exports] + switch/doSwitch + switch/doSwitchDefaultFirst + switch/doSwitchDefaultOmitted +;)