porffor 0.16.0-f9dde1759 → 0.16.0-f9e625159

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -29,7 +29,7 @@ Expect nothing to work! Only very limited JS is currently supported. See files i
29
29
  > [!WARNING]
30
30
  > Compiling to native binaries uses [2c](#2c), Porffor's own Wasm -> C compiler, which is experimental.
31
31
 
32
- **`porf native path/to/script.js out(.exe)`**. You can specify the compiler with `--compiler=clang/zig/gcc`, and which opt level to use with `--cO=O3` (`Ofast` by default). Output binaries are also stripped by default.
32
+ **`porf native path/to/script.js out(.exe)`**. You can specify the compiler with `--compiler=clang|gcc|zig` (`clang` by default), and which optimization level to use with `--cO=Ofast|O3|O2|O1|O0` (`Ofast` by default). Output binaries are also stripped by default.
33
33
 
34
34
  ### Compiling to C
35
35
  > [!WARNING]
@@ -49,7 +49,7 @@ Expect nothing to work! Only very limited JS is currently supported. See files i
49
49
 
50
50
  **`porf debug path/to/script.js`**
51
51
 
52
- ### Profiling the generated Wasm of a JS file
52
+ ### Debugging the compiled Wasm of a JS file
53
53
  > [!WARNING]
54
54
  > Very experimental WIP feature!
55
55
 
@@ -63,26 +63,14 @@ Expect nothing to work! Only very limited JS is currently supported. See files i
63
63
  - `--valtype=i32|i64|f64` (default: `f64`) to set valtype
64
64
  - `-O0` to disable opt
65
65
  - `-O1` (default) to enable basic opt (simplify insts, treeshake wasm imports)
66
- - `-O2` to enable advanced opt (inlining). unstable
67
- - `-O3` to enable advanceder opt (precompute const math). unstable
68
- - `--no-run` to not run wasm output, just compile
69
- - `--opt-log` to log some opts
70
- - `--code-log` to log some codegen (you probably want `-funcs`)
71
- - `--regex-log` to log some regex
72
- - `--funcs` to log funcs
73
- - `--ast-log` to log AST
74
- - `--opt-funcs` to log funcs after opt
75
- - `--sections` to log sections as hex
76
- - `--opt-no-inline` to not inline any funcs
77
- - `--tail-call` to enable tail calls (experimental + not widely implemented)
78
- - `--compile-hints` to enable V8 compilation hints (experimental + doesn't seem to do much?)
66
+ - `-O2` to enable advanced opt (inlining). unstable!
67
+ - `-O3` to enable advanceder opt (precompute const math). unstable!
79
68
 
80
69
  ## Limitations
81
70
  - No full object support yet
82
71
  - Little built-ins/prototype
83
72
  - No async/promise/await
84
73
  - No variables between scopes (except args and globals)
85
- - Literal callees only in calls (eg `print()` works, `a = print; a()` does not)
86
74
  - No `eval()` etc (since it is AOT)
87
75
 
88
76
  ## Sub-engines
@@ -112,7 +100,7 @@ These include some early (stage 1/0) and/or dead (last commit years ago) proposa
112
100
 
113
101
  - Number literals
114
102
  - Declaring functions
115
- - Calling functions *literal callees only*
103
+ - Calling functions
116
104
  - `return`
117
105
  - `let`/`const`/`var` basic declarations
118
106
  - Some basic integer operators (`+-/*%`)
package/compiler/2c.js CHANGED
@@ -2,10 +2,11 @@ import { read_ieee754_binary64, read_signedLEB128, read_unsignedLEB128 } from '.
2
2
  import { Blocktype, Opcodes, Valtype } from './wasmSpec.js';
3
3
  import { operatorOpcode } from './expression.js';
4
4
  import { log } from './log.js';
5
+ import Prefs from './prefs.js';
5
6
 
6
7
  const CValtype = {
7
- i8: 'i8',
8
- i16: 'i16',
8
+ i8: 'u8',
9
+ i16: 'u16',
9
10
  i32: 'i32',
10
11
  u32: 'u32',
11
12
  i64: 'i64',
@@ -17,8 +18,8 @@ const CValtype = {
17
18
  undefined: 'void'
18
19
  };
19
20
 
20
- const alwaysPreface = `typedef uint8_t i8;
21
- typedef uint16_t i16;
21
+ const alwaysPreface = `typedef uint8_t u8;
22
+ typedef uint16_t u16;
22
23
  typedef int32_t i32;
23
24
  typedef uint32_t u32;
24
25
  typedef int64_t i64;
@@ -33,11 +34,11 @@ struct ReturnValue {
33
34
  i32 type;
34
35
  };\n\n`;
35
36
 
36
- // todo: is memcpy/etc safe with host endianness?
37
+ // todo: review whether 2cMemcpy should be default or not
37
38
 
38
39
  // all:
39
40
  // immediates: ['align', 'offset']
40
- const CMemFuncs = {
41
+ const CMemFuncs = Prefs['2cMemcpy'] ? {
41
42
  [Opcodes.i32_store]: {
42
43
  c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
43
44
  args: ['pointer', 'value'],
@@ -47,13 +48,13 @@ const CMemFuncs = {
47
48
  [Opcodes.i32_store16]: {
48
49
  c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
49
50
  args: ['pointer', 'value'],
50
- argTypes: ['i32', 'i16'],
51
+ argTypes: ['i32', 'u16'],
51
52
  returns: false
52
53
  },
53
54
  [Opcodes.i32_store8]: {
54
55
  c: `memcpy(_memory + offset + pointer, &value, sizeof(value));`,
55
56
  args: ['pointer', 'value'],
56
- argTypes: ['i32', 'i8'],
57
+ argTypes: ['i32', 'u8'],
57
58
  returns: false
58
59
  },
59
60
 
@@ -66,7 +67,7 @@ return out;`,
66
67
  returns: 'i32'
67
68
  },
68
69
  [Opcodes.i32_load16_u]: {
69
- c: `i16 out;
70
+ c: `u16 out;
70
71
  memcpy(&out, _memory + offset + pointer, sizeof(out));
71
72
  return out;`,
72
73
  args: ['pointer'],
@@ -74,7 +75,7 @@ return out;`,
74
75
  returns: 'i32'
75
76
  },
76
77
  [Opcodes.i32_load8_u]: {
77
- c: `i8 out;
78
+ c: `u8 out;
78
79
  memcpy(&out, _memory + offset + pointer, sizeof(out));
79
80
  return out;`,
80
81
  args: ['pointer'],
@@ -96,6 +97,57 @@ return out;`,
96
97
  argTypes: ['i32'],
97
98
  returns: 'f64'
98
99
  },
100
+ } : {
101
+ [Opcodes.i32_store]: {
102
+ c: `*((i32*)(_memory + offset + pointer)) = value;`,
103
+ args: ['pointer', 'value'],
104
+ argTypes: ['i32', 'i32'],
105
+ returns: false
106
+ },
107
+ [Opcodes.i32_store16]: {
108
+ c: `*((u16*)(_memory + offset + pointer)) = value;`,
109
+ args: ['pointer', 'value'],
110
+ argTypes: ['i32', 'u16'],
111
+ returns: false
112
+ },
113
+ [Opcodes.i32_store8]: {
114
+ c: `*((u8*)(_memory + offset + pointer)) = value;`,
115
+ args: ['pointer', 'value'],
116
+ argTypes: ['i32', 'u8'],
117
+ returns: false
118
+ },
119
+
120
+ [Opcodes.i32_load]: {
121
+ c: `return *((i32*)(_memory + offset + pointer));`,
122
+ args: ['pointer'],
123
+ argTypes: ['i32'],
124
+ returns: 'i32'
125
+ },
126
+ [Opcodes.i32_load16_u]: {
127
+ c: `return *((u16*)(_memory + offset + pointer));`,
128
+ args: ['pointer'],
129
+ argTypes: ['i32'],
130
+ returns: 'i32'
131
+ },
132
+ [Opcodes.i32_load8_u]: {
133
+ c: `return *((u8*)(_memory + offset + pointer));`,
134
+ args: ['pointer'],
135
+ argTypes: ['i32'],
136
+ returns: 'i32'
137
+ },
138
+
139
+ [Opcodes.f64_store]: {
140
+ c: `*((f64*)(_memory + offset + pointer)) = value;`,
141
+ args: ['pointer', 'value'],
142
+ argTypes: ['i32', 'f64'],
143
+ returns: false
144
+ },
145
+ [Opcodes.f64_load]: {
146
+ c: `return *((f64*)(_memory + offset + pointer));`,
147
+ args: ['pointer'],
148
+ argTypes: ['i32'],
149
+ returns: 'f64'
150
+ },
99
151
  };
100
152
 
101
153
  const inv = (obj, keyMap = x => x) => Object.keys(obj).reduce((acc, x) => { acc[keyMap(obj[x])] = x; return acc; }, {});
@@ -152,11 +204,16 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
152
204
 
153
205
  if (pages.size > 0) {
154
206
  prepend.set('_memory', `char _memory[${pages.size * pageSize}];\n`);
155
- includes.set('string.h', true);
207
+ if (Prefs['2cMemcpy']) includes.set('string.h', true);
156
208
  }
157
209
 
158
210
  if (data.length > 0) {
159
- prependMain.set('_data', data.map(x => `memcpy(_memory + ${x.offset}, (unsigned char[]){${x.bytes.join(',')}}, ${x.bytes.length});`).join('\n '));
211
+ if (Prefs['2cMemcpy']) {
212
+ prependMain.set('_data', data.map(x => `memcpy(_memory + ${x.offset}, (unsigned char[]){${x.bytes.join(',')}}, ${x.bytes.length});`).join('\n '));
213
+ includes.set('string.h', true);
214
+ } else {
215
+ prependMain.set('_data', data.map(x => x.bytes.reduce((acc, y, i) => acc + `_memory[${x.offset + i}]=(u8)${y};`, '')).join('\n '));
216
+ }
160
217
  }
161
218
 
162
219
  if (importFuncs.find(x => x.name === '__Porffor_readArgv')) {
@@ -362,7 +419,10 @@ export default ({ funcs, globals, tags, data, exceptions, pages }) => {
362
419
 
363
420
  case Opcodes.return:
364
421
  // line(`return${returns ? ` ${removeBrackets(vals.pop())}` : ''}`);
365
- line(`return${returns ? ` (struct ReturnValue){ ${removeBrackets(vals.pop())}, ${removeBrackets(vals.pop())} }` : ''}`);
422
+ const b = vals.pop();
423
+ const a = vals.pop();
424
+ line(`return${returns ? ` (struct ReturnValue){ ${removeBrackets(a)}, ${removeBrackets(b)} }` : ''}`);
425
+ // line(`return${returns ? ` (struct ReturnValue){ ${removeBrackets(vals.pop())}, ${removeBrackets(vals.pop())} }` : ''}`);
366
426
  break;
367
427
 
368
428
  case Opcodes.if: {
@@ -474,7 +534,7 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
474
534
  out[read++] = ch;
475
535
  }
476
536
 
477
- memcpy(_memory + outPtr, &read, sizeof(read));
537
+ *((i32*)(_memory + outPtr)) = (i32)read;
478
538
  return read;
479
539
  }`);
480
540
 
@@ -504,7 +564,7 @@ _time_out = _time.tv_nsec / 1000000. + _time.tv_sec * 1000.;`);
504
564
 
505
565
  fclose(fp);
506
566
 
507
- memcpy(_memory + outPtr, &read, sizeof(read));
567
+ *((i32*)(_memory + outPtr)) = (i32)read;
508
568
  return read;
509
569
  }`);
510
570
  const outPtr = vals.pop();
@@ -0,0 +1,128 @@
1
+ import { Opcodes, PageSize, Valtype } from './wasmSpec.js';
2
+ import { number } from './embedding.js';
3
+ import Prefs from './prefs.js';
4
+
5
+ // we currently have 3 allocators:
6
+ // - static (default): a static/compile-time allocator. fast (no grow/run-time alloc needed) but can break some code
7
+ // - grow: perform a memory.grow every allocation. simple but maybe slow?
8
+ // - chunk: perform large memory.grow's in chunks when needed. needs investigation
9
+
10
+ export default name => {
11
+ switch (name) {
12
+ case 'static': return new StaticAllocator();
13
+ case 'grow': return new GrowAllocator();
14
+ case 'chunk': return new ChunkAllocator();
15
+ default: throw new Error(`unknown allocator: ${name}`);
16
+ }
17
+ };
18
+
19
+ export class StaticAllocator {
20
+ constructor() {
21
+ }
22
+
23
+ allocType(itemType) {
24
+ switch (itemType) {
25
+ case 'i8': return 'bytestring';
26
+ case 'i16': return 'string';
27
+
28
+ default: return 'array';
29
+ }
30
+ }
31
+
32
+ ptr(ind) {
33
+ if (ind === 0) return 4;
34
+ return ind * PageSize;
35
+ }
36
+
37
+ alloc({ scope, pages }, name, { itemType }) {
38
+ const reason = `${this.allocType(itemType)}: ${Prefs.scopedPageNames ? (scope.name + '/') : ''}${name}`;
39
+
40
+ if (pages.has(reason)) return number(this.ptr(pages.get(reason).ind), Valtype.i32);
41
+
42
+ if (reason.startsWith('array:')) pages.hasArray = true;
43
+ if (reason.startsWith('string:')) pages.hasString = true;
44
+ if (reason.startsWith('bytestring:')) pages.hasByteString = true;
45
+ if (reason.includes('string:')) pages.hasAnyString = true;
46
+
47
+ let ind = pages.size;
48
+ pages.set(reason, { ind, type: itemType });
49
+
50
+ scope.pages ??= new Map();
51
+ scope.pages.set(reason, { ind, type: itemType });
52
+
53
+ return number(this.ptr(ind), Valtype.i32);
54
+ }
55
+ }
56
+
57
+ export class GrowAllocator {
58
+ constructor() {
59
+ Prefs.rmUnusedTypes = false;
60
+ }
61
+
62
+ alloc() {
63
+ return [
64
+ // grow by 1 page
65
+ [ Opcodes.i32_const, 1 ],
66
+ [ Opcodes.memory_grow, 0 ], // returns old page count
67
+
68
+ // get ptr (page count * page size)
69
+ number(65536, Valtype.i32)[0],
70
+ [ Opcodes.i32_mul ]
71
+ ];
72
+ }
73
+ }
74
+
75
+ export class ChunkAllocator {
76
+ constructor(chunkSize) {
77
+ Prefs.rmUnusedTypes = false;
78
+
79
+ // 64KiB * chunk size each growth
80
+ // 16: 1MiB chunks
81
+ this.chunkSize = chunkSize ?? Prefs.chunkAllocatorSize ?? 16;
82
+ }
83
+
84
+ alloc({ asmFunc, funcIndex }) {
85
+ const func = funcIndex['#chunkallocator_alloc'] ?? asmFunc('#chunkallocator_alloc', {
86
+ wasm: [
87
+ [ Opcodes.global_get, 0 ],
88
+ [ Opcodes.global_get, 1 ],
89
+ [ Opcodes.i32_ge_s ],
90
+ [ Opcodes.if, Valtype.i32 ], // ptr >= next
91
+ // grow by chunk size pages
92
+ [ Opcodes.i32_const, this.chunkSize ],
93
+ [ Opcodes.memory_grow, 0 ],
94
+
95
+ // ptr = prev memory size * PageSize
96
+ number(65536, Valtype.i32)[0],
97
+ [ Opcodes.i32_mul ],
98
+ [ Opcodes.global_set, 0 ],
99
+
100
+ // next = ptr + ((chunkSize - 1) * PageSize)
101
+ [ Opcodes.global_get, 0 ],
102
+ number(65536 * (this.chunkSize - 1), Valtype.i32)[0],
103
+ [ Opcodes.i32_add ],
104
+ [ Opcodes.global_set, 1 ],
105
+
106
+ // return ptr
107
+ [ Opcodes.global_get, 0 ],
108
+ [ Opcodes.else ],
109
+ // return ptr = ptr + PageSize
110
+ [ Opcodes.global_get, 0 ],
111
+ number(65536, Valtype.i32)[0],
112
+ [ Opcodes.i32_add ],
113
+ [ Opcodes.global_set, 0 ],
114
+ [ Opcodes.global_get, 0 ],
115
+ [ Opcodes.end ],
116
+ ],
117
+ params: [],
118
+ locals: [],
119
+ globals: [ Valtype.i32, Valtype.i32 ],
120
+ globalNames: ['#chunkallocator_ptr', '#chunkallocator_next'],
121
+ returns: [ Valtype.i32 ],
122
+ }).index;
123
+
124
+ return [
125
+ [ Opcodes.call, func ]
126
+ ];
127
+ }
128
+ }
@@ -240,7 +240,13 @@ export default (funcs, globals, tags, pages, data, flags, noTreeshake = false) =
240
240
 
241
241
  const dataSection = data.length === 0 ? [] : createSection(
242
242
  Section.data,
243
- encodeVector(data.map(x => [ 0x00, Opcodes.i32_const, ...signedLEB128(x.offset), Opcodes.end, ...encodeVector(x.bytes) ]))
243
+ encodeVector(data.map(x => {
244
+ // type: active
245
+ if (x.offset != null) return [ 0x00, Opcodes.i32_const, ...signedLEB128(x.offset), Opcodes.end, ...encodeVector(x.bytes) ];
246
+
247
+ // type: passive
248
+ return [ 0x01, ...encodeVector(x.bytes) ];
249
+ }))
244
250
  );
245
251
 
246
252
  const dataCountSection = data.length === 0 ? [] : createSection(
@@ -54,7 +54,7 @@ export const __Array_prototype_indexOf = (_this: any[], searchElement: any, posi
54
54
  } else position = 0;
55
55
 
56
56
  for (let i: i32 = position; i < len; i++) {
57
- if (_this[i] == searchElement) return i;
57
+ if (_this[i] === searchElement) return i;
58
58
  }
59
59
 
60
60
  return -1;
@@ -68,7 +68,7 @@ export const __Array_prototype_lastIndexOf = (_this: any[], searchElement: any,
68
68
  } else position = 0;
69
69
 
70
70
  for (let i: i32 = len - 1; i >= position; i--) {
71
- if (_this[i] == searchElement) return i;
71
+ if (_this[i] === searchElement) return i;
72
72
  }
73
73
 
74
74
  return -1;
@@ -82,7 +82,7 @@ export const __Array_prototype_includes = (_this: any[], searchElement: any, pos
82
82
  } else position = 0;
83
83
 
84
84
  for (let i: i32 = position; i < len; i++) {
85
- if (_this[i] == searchElement) return true;
85
+ if (_this[i] === searchElement) return true;
86
86
  }
87
87
 
88
88
  return false;
@@ -171,12 +171,13 @@ export const __Array_prototype_filter = (_this: any[], callbackFn: any) => {
171
171
  };
172
172
 
173
173
  export const __Array_prototype_map = (_this: any[], callbackFn: any) => {
174
+ const len: i32 = _this.length;
174
175
  const out: any[] = [];
176
+ out.length = len;
175
177
 
176
- const len: i32 = _this.length;
177
178
  let i: i32 = 0;
178
179
  while (i < len) {
179
- out.push(callbackFn(_this[i], i++, _this));
180
+ out[i] = callbackFn(_this[i], i++, _this);
180
181
  }
181
182
 
182
183
  return out;
@@ -222,4 +223,70 @@ export const __Array_prototype_every = (_this: any[], callbackFn: any) => {
222
223
  }
223
224
 
224
225
  return true;
226
+ };
227
+
228
+ export const __Array_prototype_reduce = (_this: any[], callbackFn: any, initialValue: any) => {
229
+ let acc: any = initialValue ?? _this[0];
230
+
231
+ const len: i32 = _this.length;
232
+ let i: i32 = 0;
233
+ while (i < len) {
234
+ acc = callbackFn(acc, _this[i], i++, _this);
235
+ }
236
+
237
+ return acc;
238
+ };
239
+
240
+ export const __Array_prototype_toString = (_this: any[]) => {
241
+ // todo: this is bytestring only!
242
+
243
+ let out: bytestring = '';
244
+ out.length = 0;
245
+
246
+ const len: i32 = _this.length;
247
+ let i: i32 = 0;
248
+ while (i < len) {
249
+ if (i > 0) Porffor.bytestring.appendChar(out, 44);
250
+
251
+ const element: any = _this[i++];
252
+ const type: i32 = Porffor.rawType(element);
253
+ if (element != 0 || Porffor.fastAnd(
254
+ type != Porffor.TYPES.undefined, // undefined
255
+ type != Porffor.TYPES.object // null
256
+ )) {
257
+ Porffor.bytestring.appendStr(out, ecma262.ToString(element));
258
+ }
259
+ }
260
+
261
+ return out;
262
+ };
263
+
264
+ export const __Array_prototype_join = (_this: any[], _separator: any) => {
265
+ // todo: this is bytestring only!
266
+ // todo/perf: optimize single char separators
267
+ // todo/perf: optimize default separator (?)
268
+
269
+ let separator: bytestring = ',';
270
+ if (Porffor.rawType(_separator) != Porffor.TYPES.undefined)
271
+ separator = ecma262.ToString(_separator);
272
+
273
+ let out: bytestring = '';
274
+ out.length = 0;
275
+
276
+ const len: i32 = _this.length;
277
+ let i: i32 = 0;
278
+ while (i < len) {
279
+ if (i > 0) Porffor.bytestring.appendStr(out, separator);
280
+
281
+ const element: any = _this[i++];
282
+ const type: i32 = Porffor.rawType(element);
283
+ if (element != 0 || Porffor.fastAnd(
284
+ type != Porffor.TYPES.undefined, // undefined
285
+ type != Porffor.TYPES.object // null
286
+ )) {
287
+ Porffor.bytestring.appendStr(out, ecma262.ToString(element));
288
+ }
289
+ }
290
+
291
+ return out;
225
292
  };
@@ -253,29 +253,6 @@ export const __ecma262_UTC = (t: number): number => {
253
253
  return t;
254
254
  };
255
255
 
256
-
257
- // todo: move this somewhere generic?
258
- // 7.1.5 ToIntegerOrInfinity (argument)
259
- // https://tc39.es/ecma262/multipage/abstract-operations.html#sec-tointegerorinfinity
260
- export const __ecma262_ToIntegerOrInfinity = (argument: unknown): number => {
261
- // 1. Let number be ? ToNumber(argument).
262
- let number: number = Number(argument);
263
-
264
- // 2. If number is one of NaN, +0𝔽, or -0𝔽, return 0.
265
- if (Number.isNaN(number)) return 0;
266
-
267
- // 3. If number is +∞𝔽, return +∞.
268
- // 4. If number is -∞𝔽, return -∞.
269
- if (!Number.isFinite(number)) return number;
270
-
271
- // 5. Return truncate(ℝ(number)).
272
- number = Math.trunc(number);
273
-
274
- // return 0 for -0
275
- if (number == 0) return 0;
276
- return number;
277
- };
278
-
279
256
  // 21.4.1.27 MakeTime (hour, min, sec, ms)
280
257
  // https://tc39.es/ecma262/multipage/numbers-and-dates.html#sec-maketime
281
258
  export const __ecma262_MakeTime = (hour: number, min: number, sec: number, ms: number): number => {
@@ -722,12 +699,9 @@ export const __Porffor_date_allocate = (): Date => {
722
699
  const hack: bytestring = '';
723
700
 
724
701
  if (hack.length == 0) {
725
- hack.length = Porffor.wasm`i32.const 1
726
- memory.grow 0
727
- drop
728
- memory.size 0
702
+ hack.length = Porffor.wasm`
729
703
  i32.const 1
730
- i32.sub
704
+ memory.grow 0
731
705
  i32.const 65536
732
706
  i32.mul
733
707
  i32.from_u`;
@@ -1894,8 +1868,7 @@ export const __ecma262_ToDateString = (tv: number) => {
1894
1868
 
1895
1869
  // 1. If tv is NaN, return "Invalid Date".
1896
1870
  if (Number.isNaN(tv)) {
1897
- out = 'Invalid Date';
1898
- return out;
1871
+ return out = 'Invalid Date';
1899
1872
  }
1900
1873
 
1901
1874
  // 2. Let t be LocalTime(tv).
@@ -6,11 +6,9 @@ export const __Number_prototype_toString = (_this: number, radix: number|any) =>
6
6
  let outPtr: i32 = Porffor.wasm`local.get ${out}`;
7
7
 
8
8
  if (!Number.isFinite(_this)) {
9
- if (Number.isNaN(_this)) out = 'NaN';
10
- else if (_this == Infinity) out = 'Infinity';
11
- else out = '-Infinity';
12
-
13
- return out;
9
+ if (Number.isNaN(_this)) return out = 'NaN';
10
+ if (_this == Infinity) return out = 'Infinity';
11
+ return out = '-Infinity';
14
12
  }
15
13
 
16
14
  if (Porffor.rawType(radix) != Porffor.TYPES.number) {
@@ -24,8 +22,7 @@ export const __Number_prototype_toString = (_this: number, radix: number|any) =>
24
22
  }
25
23
 
26
24
  if (_this == 0) {
27
- out = '0';
28
- return out;
25
+ return out = '0';
29
26
  }
30
27
 
31
28
  // if negative value
@@ -99,7 +96,6 @@ export const __Number_prototype_toString = (_this: number, radix: number|any) =>
99
96
  }
100
97
 
101
98
  out.length = outPtr - Porffor.wasm`local.get ${out}`;
102
-
103
99
  return out;
104
100
  }
105
101
 
@@ -235,7 +231,6 @@ export const __Number_prototype_toString = (_this: number, radix: number|any) =>
235
231
  }
236
232
 
237
233
  out.length = outPtr - Porffor.wasm`local.get ${out}`;
238
-
239
234
  return out;
240
235
  };
241
236
 
@@ -244,11 +239,9 @@ export const __Number_prototype_toFixed = (_this: number, fractionDigits: number
244
239
  let outPtr: i32 = Porffor.wasm`local.get ${out}`;
245
240
 
246
241
  if (!Number.isFinite(_this)) {
247
- if (Number.isNaN(_this)) out = 'NaN';
248
- else if (_this == Infinity) out = 'Infinity';
249
- else out = '-Infinity';
250
-
251
- return out;
242
+ if (Number.isNaN(_this)) return out = 'NaN';
243
+ if (_this == Infinity) return out = 'Infinity';
244
+ return out = '-Infinity';
252
245
  }
253
246
 
254
247
  fractionDigits |= 0;
@@ -324,7 +317,6 @@ export const __Number_prototype_toFixed = (_this: number, fractionDigits: number
324
317
  }
325
318
 
326
319
  out.length = outPtr - Porffor.wasm`local.get ${out}`;
327
-
328
320
  return out;
329
321
  };
330
322
 
@@ -334,11 +326,9 @@ export const __Number_prototype_toExponential = (_this: number, fractionDigits:
334
326
  let outPtr: i32 = Porffor.wasm`local.get ${out}`;
335
327
 
336
328
  if (!Number.isFinite(_this)) {
337
- if (Number.isNaN(_this)) out = 'NaN';
338
- else if (_this == Infinity) out = 'Infinity';
339
- else out = '-Infinity';
340
-
341
- return out;
329
+ if (Number.isNaN(_this)) return out = 'NaN';
330
+ if (_this == Infinity) return out = 'Infinity';
331
+ return out = '-Infinity';
342
332
  }
343
333
 
344
334
  if (Porffor.rawType(fractionDigits) != Porffor.TYPES.number) {
@@ -519,7 +509,6 @@ export const __Number_prototype_toExponential = (_this: number, fractionDigits:
519
509
  }
520
510
 
521
511
  out.length = outPtr - Porffor.wasm`local.get ${out}`;
522
-
523
512
  return out;
524
513
  };
525
514
 
@@ -28,6 +28,13 @@ type PorfforGlobal = {
28
28
  write(_this: any, index: number, value: any): boolean;
29
29
  }
30
30
 
31
+ bytestring: {
32
+ // defined in date.ts
33
+ appendStr(str: bytestring, appendage: bytestring): i32;
34
+ appendChar(str: bytestring, char: i32): i32;
35
+ appendPadNum(str: bytestring, num: number, len: number): i32;
36
+ }
37
+
31
38
  print(x: any): i32;
32
39
 
33
40
  randomByte(): i32;
@@ -2,12 +2,9 @@ import type {} from './porffor.d.ts';
2
2
 
3
3
  // dark wasm magic for dealing with memory, sorry.
4
4
  export const __Porffor_allocate = (): number => {
5
- Porffor.wasm`i32.const 1
6
- memory.grow 0
7
- drop
8
- memory.size 0
5
+ Porffor.wasm`
9
6
  i32.const 1
10
- i32.sub
7
+ memory.grow 0
11
8
  i32.const 65536
12
9
  i32.mul
13
10
  i32.from_u