From ab5a938ea078ea5eb6939de410546d7051cf9e48 Mon Sep 17 00:00:00 2001 From: dcodeIO Date: Tue, 30 Jan 2018 01:26:38 +0100 Subject: [PATCH] parseInt compatibility layer around parseI64, see #19 --- std/assembly.d.ts | 4 +- std/assembly/string.ts | 27 ++++- tests/compiler/std/array.wast | 4 + tests/compiler/std/carray.wast | 4 + tests/compiler/std/heap.wast | 4 + tests/compiler/std/new.wast | 4 + tests/compiler/std/set.wast | 4 + tests/compiler/std/string.optimized.wast | 125 ++++++++++++++++--- tests/compiler/std/string.wast | 147 ++++++++++++++++++++--- 9 files changed, 282 insertions(+), 41 deletions(-) diff --git a/std/assembly.d.ts b/std/assembly.d.ts index 648fa9e3..7946d2f6 100644 --- a/std/assembly.d.ts +++ b/std/assembly.d.ts @@ -189,10 +189,12 @@ declare function changetype(value: any): T; declare function isNaN(value: T): bool; /** Tests if a 32-bit or 64-bit float is finite, that is not `NaN` or +/-`Infinity`. */ declare function isFinite(value: T): bool; -/** Traps if the specified value is not true-ish, otherwise returns the value. */ +/** Traps if the specified value is not true-ish, otherwise returns the (non-nullable) value. */ 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 64-bit integer. */ +declare function parseI64(str: string, radix?: i32): i64; /** Parses a string to a 64-bit float. */ declare function parseFloat(str: string): f64; diff --git a/std/assembly/string.ts b/std/assembly/string.ts index 11869272..861dd182 100644 --- a/std/assembly/string.ts +++ b/std/assembly/string.ts @@ -350,7 +350,30 @@ const enum CharCode { z = 0x7A } -export function parseInt(str: String, radix: i32 = 0): i64 { +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); + + // 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 parseI64(str: String, radix: i32 = 0): i64 { var len: i32 = str.length; if (!len) return 0; // (NaN) @@ -422,7 +445,7 @@ export function parseInt(str: String, radix: i32 = 0): i64 { return sign * num; } -export function parseFloat(str: string): f64 { +export function parseFloat(str: String): f64 { var len: i32 = str.length; if (!len) return NaN; diff --git a/tests/compiler/std/array.wast b/tests/compiler/std/array.wast index 4a5cec37..3e0db620 100644 --- a/tests/compiler/std/array.wast +++ b/tests/compiler/std/array.wast @@ -4077,6 +4077,8 @@ ENUM: std:string/CharCode FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: parseInt + FUNCTION_PROTOTYPE: std:string/parseI64 + FUNCTION_PROTOTYPE: parseI64 FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: parseFloat GLOBAL: std/array/arr @@ -4116,6 +4118,8 @@ CLASS_PROTOTYPE: String FUNCTION_PROTOTYPE: parseInt FUNCTION_PROTOTYPE: std:string/parseInt + FUNCTION_PROTOTYPE: parseI64 + FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseFloat FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: allocate_memory diff --git a/tests/compiler/std/carray.wast b/tests/compiler/std/carray.wast index 64f5559d..ef42ffdf 100644 --- a/tests/compiler/std/carray.wast +++ b/tests/compiler/std/carray.wast @@ -284,6 +284,8 @@ ENUM: std:string/CharCode FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: parseInt + FUNCTION_PROTOTYPE: std:string/parseI64 + FUNCTION_PROTOTYPE: parseI64 FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: parseFloat GLOBAL: std/carray/arr @@ -312,6 +314,8 @@ CLASS_PROTOTYPE: String FUNCTION_PROTOTYPE: parseInt FUNCTION_PROTOTYPE: std:string/parseInt + FUNCTION_PROTOTYPE: parseI64 + FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseFloat FUNCTION_PROTOTYPE: std:string/parseFloat ;) diff --git a/tests/compiler/std/heap.wast b/tests/compiler/std/heap.wast index 36a0a1ab..6e6a99fb 100644 --- a/tests/compiler/std/heap.wast +++ b/tests/compiler/std/heap.wast @@ -2893,6 +2893,8 @@ ENUM: std:string/CharCode FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: parseInt + FUNCTION_PROTOTYPE: std:string/parseI64 + FUNCTION_PROTOTYPE: parseI64 FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: parseFloat GLOBAL: std/heap/size @@ -2934,6 +2936,8 @@ CLASS_PROTOTYPE: String FUNCTION_PROTOTYPE: parseInt FUNCTION_PROTOTYPE: std:string/parseInt + FUNCTION_PROTOTYPE: parseI64 + FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseFloat FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: allocate_memory diff --git a/tests/compiler/std/new.wast b/tests/compiler/std/new.wast index 67c76302..d5213004 100644 --- a/tests/compiler/std/new.wast +++ b/tests/compiler/std/new.wast @@ -234,6 +234,8 @@ ENUM: std:string/CharCode FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: parseInt + FUNCTION_PROTOTYPE: std:string/parseI64 + FUNCTION_PROTOTYPE: parseI64 FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: parseFloat CLASS_PROTOTYPE: std/new/AClass @@ -274,6 +276,8 @@ CLASS_PROTOTYPE: String FUNCTION_PROTOTYPE: parseInt FUNCTION_PROTOTYPE: std:string/parseInt + FUNCTION_PROTOTYPE: parseI64 + FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseFloat FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: allocate_memory diff --git a/tests/compiler/std/set.wast b/tests/compiler/std/set.wast index 6d7a2b6c..bbaf156f 100644 --- a/tests/compiler/std/set.wast +++ b/tests/compiler/std/set.wast @@ -2802,6 +2802,8 @@ ENUM: std:string/CharCode FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: parseInt + FUNCTION_PROTOTYPE: std:string/parseI64 + FUNCTION_PROTOTYPE: parseI64 FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: parseFloat GLOBAL: std/set/set @@ -2840,6 +2842,8 @@ CLASS_PROTOTYPE: String FUNCTION_PROTOTYPE: parseInt FUNCTION_PROTOTYPE: std:string/parseInt + FUNCTION_PROTOTYPE: parseI64 + FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseFloat FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: allocate_memory diff --git a/tests/compiler/std/string.optimized.wast b/tests/compiler/std/string.optimized.wast index d83dbaed..4424003a 100644 --- a/tests/compiler/std/string.optimized.wast +++ b/tests/compiler/std/string.optimized.wast @@ -3,6 +3,7 @@ (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)) (global $std/string/str (mut i32) (i32.const 8)) @@ -374,7 +375,7 @@ (func $std/string/getString (; 5 ;) (type $i) (result i32) (get_global $std/string/str) ) - (func $std:string/parseInt (; 6 ;) (type $iiI) (param $0 i32) (param $1 i32) (result i64) + (func $std:string/parseI64 (; 6 ;) (type $iiI) (param $0 i32) (param $1 i32) (result i64) (local $2 i32) (local $3 i32) (local $4 i64) @@ -741,7 +742,93 @@ (get_local $4) ) ) - (func $std:string/parseFloat (; 7 ;) (type $iF) (param $0 i32) (result f64) + (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) + ) + ) + ) + (func $std:string/parseFloat (; 8 ;) (type $iF) (param $0 i32) (result f64) (local $1 i32) (local $2 i32) (local $3 f64) @@ -985,7 +1072,7 @@ (get_local $3) ) ) - (func $start (; 8 ;) (type $v) + (func $start (; 9 ;) (type $v) (if (i32.ne (get_global $std/string/str) @@ -1068,82 +1155,82 @@ (unreachable) ) (if - (i64.ne + (f64.ne (call $std:string/parseInt (i32.const 120) (i32.const 0) ) - (i64.const 0) + (f64.const 0) ) (unreachable) ) (if - (i64.ne + (f64.ne (call $std:string/parseInt (i32.const 128) (i32.const 0) ) - (i64.const 1) + (f64.const 1) ) (unreachable) ) (if - (i64.ne + (f64.ne (call $std:string/parseInt (i32.const 136) (i32.const 0) ) - (i64.const 5) + (f64.const 5) ) (unreachable) ) (if - (i64.ne + (f64.ne (call $std:string/parseInt (i32.const 152) (i32.const 0) ) - (i64.const 455) + (f64.const 455) ) (unreachable) ) (if - (i64.ne + (f64.ne (call $std:string/parseInt (i32.const 168) (i32.const 0) ) - (i64.const 3855) + (f64.const 3855) ) (unreachable) ) (if - (i64.ne + (f64.ne (call $std:string/parseInt (i32.const 184) (i32.const 0) ) - (i64.const 3855) + (f64.const 3855) ) (unreachable) ) (if - (i64.ne + (f64.ne (call $std:string/parseInt (i32.const 200) (i32.const 0) ) - (i64.const 11) + (f64.const 11) ) (unreachable) ) (if - (i64.ne + (f64.ne (call $std:string/parseInt (i32.const 216) (i32.const 0) ) - (i64.const 1) + (f64.const 1) ) (unreachable) ) diff --git a/tests/compiler/std/string.wast b/tests/compiler/std/string.wast index abfc3add..9a02085b 100644 --- a/tests/compiler/std/string.wast +++ b/tests/compiler/std/string.wast @@ -3,6 +3,7 @@ (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)) (global $std/string/str (mut i32) (i32.const 8)) @@ -499,7 +500,7 @@ (get_global $std/string/str) ) ) - (func $std:string/parseInt (; 7 ;) (type $iiI) (param $0 i32) (param $1 i32) (result i64) + (func $std:string/parseI64 (; 7 ;) (type $iiI) (param $0 i32) (param $1 i32) (result i64) (local $2 i32) (local $3 i32) (local $4 i32) @@ -924,7 +925,111 @@ ) ) ) - (func $std:string/parseFloat (; 8 ;) (type $iF) (param $0 i32) (result f64) + (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) + ) + ) + ) + ) + (func $std:string/parseFloat (; 9 ;) (type $iF) (param $0 i32) (result f64) (local $1 i32) (local $2 i32) (local $3 i32) @@ -1205,7 +1310,7 @@ ) ) ) - (func $start (; 9 ;) (type $v) + (func $start (; 10 ;) (type $v) (if (i32.eqz (i32.eq @@ -1299,96 +1404,96 @@ ) (if (i32.eqz - (i64.eq + (f64.eq (call $std:string/parseInt (i32.const 120) (i32.const 0) ) - (i64.const 0) + (f64.const 0) ) ) (unreachable) ) (if (i32.eqz - (i64.eq + (f64.eq (call $std:string/parseInt (i32.const 128) (i32.const 0) ) - (i64.const 1) + (f64.const 1) ) ) (unreachable) ) (if (i32.eqz - (i64.eq + (f64.eq (call $std:string/parseInt (i32.const 136) (i32.const 0) ) - (i64.const 5) + (f64.const 5) ) ) (unreachable) ) (if (i32.eqz - (i64.eq + (f64.eq (call $std:string/parseInt (i32.const 152) (i32.const 0) ) - (i64.const 455) + (f64.const 455) ) ) (unreachable) ) (if (i32.eqz - (i64.eq + (f64.eq (call $std:string/parseInt (i32.const 168) (i32.const 0) ) - (i64.const 3855) + (f64.const 3855) ) ) (unreachable) ) (if (i32.eqz - (i64.eq + (f64.eq (call $std:string/parseInt (i32.const 184) (i32.const 0) ) - (i64.const 3855) + (f64.const 3855) ) ) (unreachable) ) (if (i32.eqz - (i64.eq + (f64.eq (call $std:string/parseInt (i32.const 200) (i32.const 0) ) - (i64.const 11) + (f64.const 11) ) ) (unreachable) ) (if (i32.eqz - (i64.eq + (f64.eq (call $std:string/parseInt (i32.const 216) (i32.const 0) ) - (i64.const 1) + (f64.const 1) ) ) (unreachable) @@ -1529,6 +1634,8 @@ ENUM: std:string/CharCode FUNCTION_PROTOTYPE: std:string/parseInt FUNCTION_PROTOTYPE: parseInt + FUNCTION_PROTOTYPE: std:string/parseI64 + FUNCTION_PROTOTYPE: parseI64 FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: parseFloat GLOBAL: std/string/str @@ -1558,6 +1665,8 @@ CLASS_PROTOTYPE: String FUNCTION_PROTOTYPE: parseInt FUNCTION_PROTOTYPE: std:string/parseInt + FUNCTION_PROTOTYPE: parseI64 + FUNCTION_PROTOTYPE: std:string/parseI64 FUNCTION_PROTOTYPE: parseFloat FUNCTION_PROTOTYPE: std:string/parseFloat FUNCTION_PROTOTYPE: std/string/getString