Skip to content

Commit 4680b53

Browse files
committed
Refactor number and string utils out of builtins, fixes AssemblyScript#608
1 parent 0484a6b commit 4680b53

23 files changed

+988
-979
lines changed

cli/asc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
},
8484
"runtime": {
8585
"description": [
86-
"Specifies the runtime implementation to include in the program.",
86+
"Specifies the runtime variant to include in the program.",
8787
"",
8888
" full Default runtime based on TLSF and reference counting.",
8989
" half Same as 'full', but not exported to the host.",

lib/i64/README.md

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
@assemblyscript/i64
2-
===================
1+
# ![AS](https://avatars1.githubusercontent.com/u/28916798?s=48) i64
32

43
Exposes WebAssembly's i64 operations to JavaScript using 32-bit integers (low and high bits).
54

std/assembly/builtins.ts

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,3 @@
1-
// @ts-ignore: decorator
2-
@builtin @inline
3-
export const NaN: f64 = 0 / 0;
4-
5-
// @ts-ignore: decorator
6-
@builtin @inline
7-
export const Infinity: f64 = 1 / 0;
8-
91
// @ts-ignore: decorator
102
@builtin
113
export declare function isInteger<T>(value?: T): bool;
@@ -58,20 +50,6 @@ export declare function isConstant(expression: void): bool;
5850
@builtin
5951
export declare function isManaged<T>(value?: T): bool;
6052

61-
export function isNaN<T extends number>(value: T): bool {
62-
if (!isFloat<T>()) {
63-
if (!isInteger<T>()) ERROR("numeric type expected");
64-
}
65-
return value != value;
66-
}
67-
68-
export function isFinite<T extends number>(value: T): bool {
69-
if (!isFloat<T>()) {
70-
if (!isInteger<T>()) ERROR("numeric type expected");
71-
}
72-
return value - value == 0;
73-
}
74-
7553
// @ts-ignore: decorator
7654
@builtin
7755
export declare function clz<T>(value: T): T;

std/assembly/number.ts

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,26 @@
11
import { itoa, dtoa } from "./util/number";
2-
import { isNaN as builtin_isNaN, isFinite as builtin_isFinite } from "./builtins";
2+
3+
// @ts-ignore: decorator
4+
@builtin @inline
5+
export const NaN: f64 = 0 / 0;
6+
7+
// @ts-ignore: decorator
8+
@builtin @inline
9+
export const Infinity: f64 = 1 / 0;
10+
11+
export function isNaN<T extends number>(value: T): bool {
12+
if (!isFloat<T>()) {
13+
if (!isInteger<T>()) ERROR("numeric type expected");
14+
}
15+
return value != value;
16+
}
17+
18+
export function isFinite<T extends number>(value: T): bool {
19+
if (!isFloat<T>()) {
20+
if (!isInteger<T>()) ERROR("numeric type expected");
21+
}
22+
return value - value == 0;
23+
}
324

425
@sealed @unmanaged
526
export abstract class I8 {
@@ -331,19 +352,19 @@ export abstract class F64 {
331352
static readonly NaN: f64 = NaN;
332353

333354
static isNaN(value: f64): bool {
334-
return builtin_isNaN<f64>(value);
355+
return isNaN<f64>(value);
335356
}
336357

337358
static isFinite(value: f64): bool {
338-
return builtin_isFinite<f64>(value);
359+
return isFinite<f64>(value);
339360
}
340361

341362
static isSafeInteger(value: f64): bool {
342363
return abs<f64>(value) <= f64.MAX_SAFE_INTEGER && trunc<f64>(value) == value;
343364
}
344365

345366
static isInteger(value: f64): bool {
346-
return builtin_isFinite<f64>(value) && trunc<f64>(value) == value;
367+
return isFinite<f64>(value) && trunc<f64>(value) == value;
347368
}
348369

349370
static parseInt(value: string, radix: i32 = 0): f64 {
@@ -354,7 +375,7 @@ export abstract class F64 {
354375
return parseFloat(value);
355376
}
356377

357-
toString(this: f64): String {
378+
toString(this: f64, radix: i32 = 0): String {
358379
// TODO: radix
359380
return dtoa(this);
360381
}

std/assembly/string.ts

Lines changed: 5 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/// <reference path="./rt/index.d.ts" />
22

33
import { BLOCK, BLOCK_OVERHEAD, BLOCK_MAXSIZE } from "./rt/common";
4-
import { compareImpl, parse, CharCode, isWhiteSpaceOrLineTerminator } from "./util/string";
4+
import { compareImpl, strtol, strtod, isWhiteSpaceOrLineTerminator } from "./util/string";
55
import { E_INVALIDLENGTH } from "./util/error";
66
import { ArrayBufferView } from "./arraybuffer";
77
import { idof } from "./builtins";
@@ -522,72 +522,10 @@ import { idof } from "./builtins";
522522
// @ts-ignore: nolib
523523
export type string = String;
524524

525-
export function parseInt(str: String, radix: i32 = 0): f64 {
526-
// @ts-ignore: string <-> String
527-
return parse<f64>(str, radix);
525+
export function parseInt(str: string, radix: i32 = 0): f64 {
526+
return strtol<f64>(str, radix);
528527
}
529528

530-
export function parseI32(str: String, radix: i32 = 0): i32 {
531-
// @ts-ignore: string <-> String
532-
return parse<i32>(str, radix);
533-
}
534-
535-
export function parseI64(str: String, radix: i32 = 0): i64 {
536-
// @ts-ignore: string <-> String
537-
return parse<i64>(str, radix);
538-
}
539-
540-
// FIXME: naive implementation
541-
export function parseFloat(str: String): f64 {
542-
var len: i32 = str.length;
543-
if (!len) return NaN;
544-
545-
var ptr = changetype<usize>(str);
546-
var code = <i32>load<u16>(ptr);
547-
548-
// determine sign
549-
var sign: f64;
550-
// trim white spaces
551-
while (isWhiteSpaceOrLineTerminator(code)) {
552-
code = <i32>load<u16>(ptr += 2);
553-
--len;
554-
}
555-
if (code == CharCode.MINUS) {
556-
if (!--len) return NaN;
557-
code = <i32>load<u16>(ptr += 2);
558-
sign = -1;
559-
} else if (code == CharCode.PLUS) {
560-
if (!--len) return NaN;
561-
code = <i32>load<u16>(ptr += 2);
562-
sign = 1;
563-
} else {
564-
sign = 1;
565-
}
566-
567-
// calculate value
568-
var num: f64 = 0;
569-
while (len--) {
570-
code = <i32>load<u16>(ptr);
571-
if (code == CharCode.DOT) {
572-
ptr += 2;
573-
let fac: f64 = 0.1; // precision :(
574-
while (len--) {
575-
code = <i32>load<u16>(ptr);
576-
if (code == CharCode.E || code == CharCode.e) {
577-
assert(false); // TODO
578-
}
579-
code -= CharCode._0;
580-
if (<u32>code > 9) break;
581-
num += <f64>code * fac;
582-
fac *= 0.1;
583-
ptr += 2;
584-
}
585-
break;
586-
}
587-
code -= CharCode._0;
588-
if (<u32>code >= 10) break;
589-
num = (num * 10) + code;
590-
ptr += 2;
591-
}
592-
return sign * num;
529+
export function parseFloat(str: string): f64 {
530+
return strtod(str);
593531
}

std/assembly/util/string.ts

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ export function isWhiteSpaceOrLineTerminator(c: i32): bool {
5757
}
5858

5959
/** Parses a string to an integer (usually), using the specified radix. */
60-
export function parse<T>(str: string, radix: i32 = 0): T {
60+
export function strtol<T>(str: string, radix: i32 = 0): T {
6161
var len: i32 = str.length;
6262
// @ts-ignore: cast
6363
if (!len) return <T>NaN;
@@ -139,3 +139,58 @@ export function parse<T>(str: string, radix: i32 = 0): T {
139139
// @ts-ignore: type
140140
return sign * num;
141141
}
142+
143+
// FIXME: naive implementation
144+
export function strtod(str: string): f64 {
145+
var len: i32 = str.length;
146+
if (!len) return NaN;
147+
148+
var ptr = changetype<usize>(str);
149+
var code = <i32>load<u16>(ptr);
150+
151+
// determine sign
152+
var sign: f64;
153+
// trim white spaces
154+
while (isWhiteSpaceOrLineTerminator(code)) {
155+
code = <i32>load<u16>(ptr += 2);
156+
--len;
157+
}
158+
if (code == CharCode.MINUS) {
159+
if (!--len) return NaN;
160+
code = <i32>load<u16>(ptr += 2);
161+
sign = -1;
162+
} else if (code == CharCode.PLUS) {
163+
if (!--len) return NaN;
164+
code = <i32>load<u16>(ptr += 2);
165+
sign = 1;
166+
} else {
167+
sign = 1;
168+
}
169+
170+
// calculate value
171+
var num: f64 = 0;
172+
while (len--) {
173+
code = <i32>load<u16>(ptr);
174+
if (code == CharCode.DOT) {
175+
ptr += 2;
176+
let fac: f64 = 0.1; // precision :(
177+
while (len--) {
178+
code = <i32>load<u16>(ptr);
179+
if (code == CharCode.E || code == CharCode.e) {
180+
assert(false); // TODO
181+
}
182+
code -= CharCode._0;
183+
if (<u32>code > 9) break;
184+
num += <f64>code * fac;
185+
fac *= 0.1;
186+
ptr += 2;
187+
}
188+
break;
189+
}
190+
code -= CharCode._0;
191+
if (<u32>code >= 10) break;
192+
num = (num * 10) + code;
193+
ptr += 2;
194+
}
195+
return sign * num;
196+
}

tests/compiler/binary.untouched.wat

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,7 +1188,7 @@
11881188
local.get $16
11891189
f64.mul
11901190
)
1191-
(func $~lib/builtins/isNaN<f32> (; 2 ;) (type $FUNCSIG$if) (param $0 f32) (result i32)
1191+
(func $~lib/number/isNaN<f32> (; 2 ;) (type $FUNCSIG$if) (param $0 f32) (result i32)
11921192
local.get $0
11931193
local.get $0
11941194
f32.ne
@@ -1243,7 +1243,7 @@
12431243
i32.const 1
12441244
else
12451245
local.get $1
1246-
call $~lib/builtins/isNaN<f32>
1246+
call $~lib/number/isNaN<f32>
12471247
end
12481248
if
12491249
local.get $0
@@ -2464,7 +2464,7 @@
24642464
local.get $11
24652465
f32.mul
24662466
)
2467-
(func $~lib/builtins/isNaN<f64> (; 6 ;) (type $FUNCSIG$id) (param $0 f64) (result i32)
2467+
(func $~lib/number/isNaN<f64> (; 6 ;) (type $FUNCSIG$id) (param $0 f64) (result i32)
24682468
local.get $0
24692469
local.get $0
24702470
f64.ne
@@ -2519,7 +2519,7 @@
25192519
i32.const 1
25202520
else
25212521
local.get $1
2522-
call $~lib/builtins/isNaN<f64>
2522+
call $~lib/number/isNaN<f64>
25232523
end
25242524
if
25252525
local.get $0

0 commit comments

Comments
 (0)