diff --git a/package.json b/package.json index 51fa40cd..500528c6 100644 --- a/package.json +++ b/package.json @@ -44,8 +44,7 @@ "build": "webpack", "clean": "node scripts/clean", "lint": "tslint --project src", - "test:config": "npm run test:config:assembly --scripts-prepend-node-path && npm run test:config:portable --scripts-prepend-node-path && npm run test:config:src --scripts-prepend-node-path", - "test:config:assembly": "tsc --noEmit -p std/assembly --diagnostics --listFiles", + "test:config": "npm run test:config:portable --scripts-prepend-node-path && npm run test:config:src --scripts-prepend-node-path", "test:config:portable": "tsc --noEmit -p std/portable --diagnostics --listFiles", "test:config:src": "tsc --noEmit -p src --diagnostics --listFiles", "test:parser": "node tests/parser", diff --git a/std/assembly.d.ts b/std/assembly.d.ts index 7946d2f6..63900de6 100644 --- a/std/assembly.d.ts +++ b/std/assembly.d.ts @@ -193,6 +193,8 @@ declare function isFinite(value: T): bool; declare function assert(isTrueish: T, message?: string): T & object; // any better way to model `: T != null`? /** Parses an integer string to a 64-bit float. */ declare function parseInt(str: string, radix?: i32): f64; +/** Parses an integer string to a 32-bit integer. */ +declare function parseI32(str: string, radix?: i32): i32; /** Parses an integer string to a 64-bit integer. */ declare function parseI64(str: string, radix?: i32): i64; /** Parses a string to a 64-bit float. */ diff --git a/std/assembly/string.ts b/std/assembly/string.ts index 861dd182..dfd8befa 100644 --- a/std/assembly/string.ts +++ b/std/assembly/string.ts @@ -351,45 +351,34 @@ const enum CharCode { } export function parseInt(str: String, radix: i32 = 0): f64 { - var len: i32 = str.length; - if (!len) - return NaN; - var ptr = changetype(str) /* + HEAD -> offset */; - var code = load(ptr, HEAD); + return parse(str, radix); +} - // pre-check sign - if (code == CharCode.MINUS) { - if (!--len) - return NaN; - } else if (code == CharCode.PLUS) { - if (!--len) - return NaN; - } - - // pre-check radix - if (radix && (radix < 2 || radix > 36)) - return NaN; - - return parseI64(str, radix); +export function parseI32(str: String, radix: i32 = 0): i32 { + return parse(str, radix); } export function parseI64(str: String, radix: i32 = 0): i64 { + return parse(str, radix); +} + +function parse(str: String, radix: i32 = 0): T { var len: i32 = str.length; if (!len) - return 0; // (NaN) + return NaN; var ptr = changetype(str) /* + HEAD -> offset */; var code = load(ptr, HEAD); // determine sign - var sign: i64; + var sign: T; if (code == CharCode.MINUS) { if (!--len) - return 0; // (NaN) + return NaN; code = load(ptr += 2, HEAD); sign = -1; } else if (code == CharCode.PLUS) { if (!--len) - return 0; // (NaN) + return NaN; code = load(ptr += 2, HEAD); sign = 1; } else @@ -423,10 +412,10 @@ export function parseI64(str: String, radix: i32 = 0): i64 { } } else radix = 10; } else if (radix < 2 || radix > 36) - return 0; // (NaN) + return NaN; // calculate value - var num: i64 = 0; + var num: T = 0; while (len--) { code = load(ptr, HEAD); if (code >= CharCode._0 && code <= CharCode._9) diff --git a/std/portable.d.ts b/std/portable.d.ts index 1f4a5ae3..3fe2a859 100644 --- a/std/portable.d.ts +++ b/std/portable.d.ts @@ -135,6 +135,8 @@ declare function changetype(value: any): T; declare function assert(isTrueish: T, message?: string): T & object; // any better way to model `: T != null`? /** Parses an integer string to a 64-bit float. */ declare function parseInt(str: string, radix?: i32): f64; +/** Parses an integer string to a 32-bit integer. */ +declare function parseI32(str: string, radix?: i32): i32; /** Parses a floating point string to a 64-bit float. */ declare function parseFloat(str: string): f64; diff --git a/std/portable.js b/std/portable.js index cda83fe6..f575c91c 100644 --- a/std/portable.js +++ b/std/portable.js @@ -98,3 +98,7 @@ globalScope["changetype"] = function changetype(value) { return value; } String["fromCharCodes"] = function fromCharCodes(arr) { return String.fromCharCode.apply(String, arr); } String["fromCodePoints"] = function fromCodePoints(arr) { return String.fromCodePoint.apply(String, arr); } + +globalScope["parseI32"] = function parseI32(str, radix) { + return parseInt(str) | 0; +}; diff --git a/tests/compiler/std/array.wast b/tests/compiler/std/array.wast index 3e0db620..87798d17 100644 --- a/tests/compiler/std/array.wast +++ b/tests/compiler/std/array.wast @@ -4077,8 +4077,11 @@ ENUM: std:string/CharCode FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: parseInt + FUNCTION_PROTOTYPE: std:string/parseI32 + FUNCTION_PROTOTYPE: parseI32 FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseI64 + FUNCTION_PROTOTYPE: std:string/parse FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: parseFloat GLOBAL: std/array/arr @@ -4118,6 +4121,8 @@ CLASS_PROTOTYPE: String FUNCTION_PROTOTYPE: parseInt FUNCTION_PROTOTYPE: std:string/parseInt + FUNCTION_PROTOTYPE: parseI32 + FUNCTION_PROTOTYPE: std:string/parseI32 FUNCTION_PROTOTYPE: parseI64 FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseFloat diff --git a/tests/compiler/std/carray.wast b/tests/compiler/std/carray.wast index ef42ffdf..969796e6 100644 --- a/tests/compiler/std/carray.wast +++ b/tests/compiler/std/carray.wast @@ -284,8 +284,11 @@ ENUM: std:string/CharCode FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: parseInt + FUNCTION_PROTOTYPE: std:string/parseI32 + FUNCTION_PROTOTYPE: parseI32 FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseI64 + FUNCTION_PROTOTYPE: std:string/parse FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: parseFloat GLOBAL: std/carray/arr @@ -314,6 +317,8 @@ CLASS_PROTOTYPE: String FUNCTION_PROTOTYPE: parseInt FUNCTION_PROTOTYPE: std:string/parseInt + FUNCTION_PROTOTYPE: parseI32 + FUNCTION_PROTOTYPE: std:string/parseI32 FUNCTION_PROTOTYPE: parseI64 FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseFloat diff --git a/tests/compiler/std/heap.wast b/tests/compiler/std/heap.wast index 6e6a99fb..b7d92c06 100644 --- a/tests/compiler/std/heap.wast +++ b/tests/compiler/std/heap.wast @@ -2893,8 +2893,11 @@ ENUM: std:string/CharCode FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: parseInt + FUNCTION_PROTOTYPE: std:string/parseI32 + FUNCTION_PROTOTYPE: parseI32 FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseI64 + FUNCTION_PROTOTYPE: std:string/parse FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: parseFloat GLOBAL: std/heap/size @@ -2936,6 +2939,8 @@ CLASS_PROTOTYPE: String FUNCTION_PROTOTYPE: parseInt FUNCTION_PROTOTYPE: std:string/parseInt + FUNCTION_PROTOTYPE: parseI32 + FUNCTION_PROTOTYPE: std:string/parseI32 FUNCTION_PROTOTYPE: parseI64 FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseFloat diff --git a/tests/compiler/std/new.wast b/tests/compiler/std/new.wast index d5213004..51dc0f6f 100644 --- a/tests/compiler/std/new.wast +++ b/tests/compiler/std/new.wast @@ -234,8 +234,11 @@ ENUM: std:string/CharCode FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: parseInt + FUNCTION_PROTOTYPE: std:string/parseI32 + FUNCTION_PROTOTYPE: parseI32 FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseI64 + FUNCTION_PROTOTYPE: std:string/parse FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: parseFloat CLASS_PROTOTYPE: std/new/AClass @@ -276,6 +279,8 @@ CLASS_PROTOTYPE: String FUNCTION_PROTOTYPE: parseInt FUNCTION_PROTOTYPE: std:string/parseInt + FUNCTION_PROTOTYPE: parseI32 + FUNCTION_PROTOTYPE: std:string/parseI32 FUNCTION_PROTOTYPE: parseI64 FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseFloat diff --git a/tests/compiler/std/set.wast b/tests/compiler/std/set.wast index bbaf156f..566aab41 100644 --- a/tests/compiler/std/set.wast +++ b/tests/compiler/std/set.wast @@ -2802,8 +2802,11 @@ ENUM: std:string/CharCode FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: parseInt + FUNCTION_PROTOTYPE: std:string/parseI32 + FUNCTION_PROTOTYPE: parseI32 FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseI64 + FUNCTION_PROTOTYPE: std:string/parse FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: parseFloat GLOBAL: std/set/set @@ -2842,6 +2845,8 @@ CLASS_PROTOTYPE: String FUNCTION_PROTOTYPE: parseInt FUNCTION_PROTOTYPE: std:string/parseInt + FUNCTION_PROTOTYPE: parseI32 + FUNCTION_PROTOTYPE: std:string/parseI32 FUNCTION_PROTOTYPE: parseI64 FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseFloat diff --git a/tests/compiler/std/string.optimized.wast b/tests/compiler/std/string.optimized.wast index 4424003a..a8777bc2 100644 --- a/tests/compiler/std/string.optimized.wast +++ b/tests/compiler/std/string.optimized.wast @@ -2,7 +2,6 @@ (type $i (func (result i32))) (type $iii (func (param i32 i32) (result i32))) (type $iiii (func (param i32 i32 i32) (result i32))) - (type $iiI (func (param i32 i32) (result i64))) (type $iiF (func (param i32 i32) (result f64))) (type $iF (func (param i32) (result f64))) (type $v (func)) @@ -375,11 +374,11 @@ (func $std/string/getString (; 5 ;) (type $i) (result i32) (get_global $std/string/str) ) - (func $std:string/parseI64 (; 6 ;) (type $iiI) (param $0 i32) (param $1 i32) (result i64) + (func $std:string/parse (; 6 ;) (type $iiF) (param $0 i32) (param $1 i32) (result f64) (local $2 i32) (local $3 i32) - (local $4 i64) - (local $5 i64) + (local $4 f64) + (local $5 f64) (if (i32.eqz (tee_local $3 @@ -389,11 +388,11 @@ ) ) (return - (i64.const 0) + (f64.const nan:0x8000000000000) ) ) (set_local $5 - (if (result i64) + (if (result f64) (i32.eq (tee_local $2 (i32.load16_u offset=4 @@ -402,7 +401,7 @@ ) (i32.const 45) ) - (block (result i64) + (block (result f64) (if (i32.eqz (tee_local $3 @@ -413,7 +412,7 @@ ) ) (return - (i64.const 0) + (f64.const nan:0x8000000000000) ) ) (set_local $2 @@ -426,14 +425,14 @@ ) ) ) - (i64.const -1) + (f64.const -1) ) - (if (result i64) + (if (result f64) (i32.eq (get_local $2) (i32.const 43) ) - (block (result i64) + (block (result f64) (if (i32.eqz (tee_local $3 @@ -444,7 +443,7 @@ ) ) (return - (i64.const 0) + (f64.const nan:0x8000000000000) ) ) (set_local $2 @@ -457,9 +456,9 @@ ) ) ) - (i64.const 1) + (f64.const 1) ) - (i64.const 1) + (f64.const 1) ) ) ) @@ -484,7 +483,7 @@ (i32.const 1) ) (return - (i64.const 0) + (f64.const nan:0x8000000000000) ) ) (set_local $1 @@ -714,14 +713,14 @@ ) ) (set_local $4 - (i64.add - (i64.mul + (f64.add + (f64.mul (get_local $4) - (i64.extend_s/i32 + (f64.convert_s/i32 (get_local $1) ) ) - (i64.extend_s/i32 + (f64.convert_s/i32 (get_local $2) ) ) @@ -737,95 +736,15 @@ ) ) ) - (i64.mul + (f64.mul (get_local $5) (get_local $4) ) ) (func $std:string/parseInt (; 7 ;) (type $iiF) (param $0 i32) (param $1 i32) (result f64) - (local $2 i32) - (local $3 i32) - (if - (i32.eqz - (tee_local $2 - (i32.load - (get_local $0) - ) - ) - ) - (return - (f64.const nan:0x8000000000000) - ) - ) - (if - (i32.eq - (tee_local $3 - (i32.load16_u offset=4 - (get_local $0) - ) - ) - (i32.const 45) - ) - (if - (i32.eqz - (i32.sub - (get_local $2) - (i32.const 1) - ) - ) - (return - (f64.const nan:0x8000000000000) - ) - ) - (if - (i32.eq - (get_local $3) - (i32.const 43) - ) - (if - (i32.eqz - (i32.sub - (get_local $2) - (i32.const 1) - ) - ) - (return - (f64.const nan:0x8000000000000) - ) - ) - ) - ) - (if - (select - (i32.and - (select - (i32.lt_s - (get_local $1) - (i32.const 2) - ) - (i32.gt_s - (get_local $1) - (i32.const 36) - ) - (i32.lt_s - (get_local $1) - (i32.const 2) - ) - ) - (i32.const 1) - ) - (get_local $1) - (get_local $1) - ) - (return - (f64.const nan:0x8000000000000) - ) - ) - (f64.convert_s/i64 - (call $std:string/parseI64 - (get_local $0) - (get_local $1) - ) + (call $std:string/parse + (get_local $0) + (get_local $1) ) ) (func $std:string/parseFloat (; 8 ;) (type $iF) (param $0 i32) (result f64) diff --git a/tests/compiler/std/string.wast b/tests/compiler/std/string.wast index 9a02085b..e8754d40 100644 --- a/tests/compiler/std/string.wast +++ b/tests/compiler/std/string.wast @@ -2,7 +2,6 @@ (type $i (func (result i32))) (type $iii (func (param i32 i32) (result i32))) (type $iiii (func (param i32 i32 i32) (result i32))) - (type $iiI (func (param i32 i32) (result i64))) (type $iiF (func (param i32 i32) (result f64))) (type $iF (func (param i32) (result f64))) (type $v (func)) @@ -500,13 +499,13 @@ (get_global $std/string/str) ) ) - (func $std:string/parseI64 (; 7 ;) (type $iiI) (param $0 i32) (param $1 i32) (result i64) + (func $std:string/parse (; 7 ;) (type $iiF) (param $0 i32) (param $1 i32) (result f64) (local $2 i32) (local $3 i32) (local $4 i32) - (local $5 i64) + (local $5 f64) (local $6 i32) - (local $7 i64) + (local $7 f64) (set_local $2 (i32.load (get_local $0) @@ -517,7 +516,7 @@ (get_local $2) ) (return - (i64.const 0) + (f64.const nan:0x8000000000000) ) ) (set_local $3 @@ -545,7 +544,7 @@ ) ) (return - (i64.const 0) + (f64.const nan:0x8000000000000) ) ) (set_local $4 @@ -559,9 +558,8 @@ ) ) (set_local $5 - (i64.sub - (i64.const 0) - (i64.const 1) + (f64.neg + (f64.const 1) ) ) ) @@ -581,7 +579,7 @@ ) ) (return - (i64.const 0) + (f64.const nan:0x8000000000000) ) ) (set_local $4 @@ -595,11 +593,11 @@ ) ) (set_local $5 - (i64.const 1) + (f64.const 1) ) ) (set_local $5 - (i64.const 1) + (f64.const 1) ) ) ) @@ -766,12 +764,12 @@ (i32.const 1) ) (return - (i64.const 0) + (f64.const nan:0x8000000000000) ) ) ) (set_local $7 - (i64.const 0) + (f64.const 0) ) (block $break|1 (loop $continue|1 @@ -894,14 +892,14 @@ (br $break|1) ) (set_local $7 - (i64.add - (i64.mul + (f64.add + (f64.mul (get_local $7) - (i64.extend_s/i32 + (f64.convert_s/i32 (get_local $1) ) ) - (i64.extend_s/i32 + (f64.convert_s/i32 (get_local $4) ) ) @@ -919,113 +917,17 @@ ) ) (return - (i64.mul + (f64.mul (get_local $5) (get_local $7) ) ) ) (func $std:string/parseInt (; 8 ;) (type $iiF) (param $0 i32) (param $1 i32) (result f64) - (local $2 i32) - (local $3 i32) - (local $4 i32) - (set_local $2 - (i32.load - (get_local $0) - ) - ) - (if - (i32.eqz - (get_local $2) - ) - (return - (f64.const nan:0x8000000000000) - ) - ) - (set_local $3 - (get_local $0) - ) - (set_local $4 - (i32.load16_u offset=4 - (get_local $3) - ) - ) - (if - (i32.eq - (get_local $4) - (i32.const 45) - ) - (if - (i32.eqz - (tee_local $2 - (i32.sub - (get_local $2) - (i32.const 1) - ) - ) - ) - (return - (f64.const nan:0x8000000000000) - ) - ) - (if - (i32.eq - (get_local $4) - (i32.const 43) - ) - (if - (i32.eqz - (tee_local $2 - (i32.sub - (get_local $2) - (i32.const 1) - ) - ) - ) - (return - (f64.const nan:0x8000000000000) - ) - ) - ) - ) - (if - (if (result i32) - (i32.ne - (get_local $1) - (i32.const 0) - ) - (i32.and - (if (result i32) - (i32.ne - (i32.lt_s - (get_local $1) - (i32.const 2) - ) - (i32.const 0) - ) - (i32.lt_s - (get_local $1) - (i32.const 2) - ) - (i32.gt_s - (get_local $1) - (i32.const 36) - ) - ) - (i32.const 1) - ) - (get_local $1) - ) - (return - (f64.const nan:0x8000000000000) - ) - ) (return - (f64.convert_s/i64 - (call $std:string/parseI64 - (get_local $0) - (get_local $1) - ) + (call $std:string/parse + (get_local $0) + (get_local $1) ) ) ) @@ -1634,8 +1536,11 @@ ENUM: std:string/CharCode FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: parseInt + FUNCTION_PROTOTYPE: std:string/parseI32 + FUNCTION_PROTOTYPE: parseI32 FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseI64 + FUNCTION_PROTOTYPE: std:string/parse FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: parseFloat GLOBAL: std/string/str @@ -1665,6 +1570,8 @@ CLASS_PROTOTYPE: String FUNCTION_PROTOTYPE: parseInt FUNCTION_PROTOTYPE: std:string/parseInt + FUNCTION_PROTOTYPE: parseI32 + FUNCTION_PROTOTYPE: std:string/parseI32 FUNCTION_PROTOTYPE: parseI64 FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseFloat