porffor 0.36.1 → 0.36.3
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/compiler/builtins/_internal_object.ts +151 -2
- package/compiler/builtins/object.ts +17 -7
- package/compiler/builtins/z_ecma262.ts +41 -10
- package/compiler/builtins_objects.js +9 -12
- package/compiler/builtins_precompiled.js +78 -55
- package/compiler/codegen.js +43 -33
- package/compiler/index.js +3 -2
- package/compiler/precompile.js +2 -0
- package/package.json +1 -1
- package/runner/index.js +1 -1
@@ -326,7 +326,6 @@ export const __Porffor_object_set = (obj: any, key: any, value: any): any => {
|
|
326
326
|
|
327
327
|
// no setter, return early
|
328
328
|
if (Porffor.wasm`local.get ${set}` == 0) {
|
329
|
-
// todo: throw in strict mode?
|
330
329
|
return value;
|
331
330
|
}
|
332
331
|
|
@@ -375,6 +374,92 @@ export const __Porffor_object_set = (obj: any, key: any, value: any): any => {
|
|
375
374
|
return value;
|
376
375
|
};
|
377
376
|
|
377
|
+
export const __Porffor_object_setStrict = (obj: any, key: any, value: any): any => {
|
378
|
+
if (Porffor.wasm`local.get ${obj}` == 0) throw new TypeError('Cannot set property of null');
|
379
|
+
|
380
|
+
if (Porffor.wasm`local.get ${obj+1}` != Porffor.TYPES.object) {
|
381
|
+
obj = __Porffor_object_getObject(obj);
|
382
|
+
if (Porffor.wasm`local.get ${obj+1}` != Porffor.TYPES.object) return value;
|
383
|
+
}
|
384
|
+
|
385
|
+
let entryPtr: i32 = __Porffor_object_lookup(obj, key);
|
386
|
+
let flags: i32;
|
387
|
+
if (entryPtr == -1) {
|
388
|
+
// add new entry
|
389
|
+
// check if object is inextensible
|
390
|
+
if (__Porffor_object_isInextensible(obj)) {
|
391
|
+
throw new TypeError('Cannot add property to inextensible object');
|
392
|
+
}
|
393
|
+
|
394
|
+
// bump size +1
|
395
|
+
const size: i32 = Porffor.wasm.i32.load(obj, 0, 0);
|
396
|
+
Porffor.wasm.i32.store(obj, size + 1, 0, 0);
|
397
|
+
|
398
|
+
// entryPtr = current end of object
|
399
|
+
entryPtr = Porffor.wasm`local.get ${obj}` + 5 + size * 14;
|
400
|
+
|
401
|
+
__Porffor_object_writeKey(entryPtr, key);
|
402
|
+
|
403
|
+
// flags = writable, enumerable, configurable, not accessor
|
404
|
+
flags = 0b1110;
|
405
|
+
} else {
|
406
|
+
// existing entry, modify it
|
407
|
+
const tail: i32 = Porffor.wasm.i32.load16_u(entryPtr, 0, 12);
|
408
|
+
|
409
|
+
if (tail & 0b0001) {
|
410
|
+
// accessor descriptor
|
411
|
+
const set: Function = __Porffor_object_accessorSet(entryPtr);
|
412
|
+
|
413
|
+
// no setter, return early
|
414
|
+
if (Porffor.wasm`local.get ${set}` == 0) {
|
415
|
+
throw new TypeError('Cannot set property with no setter of object');
|
416
|
+
}
|
417
|
+
|
418
|
+
const funcFlags: i32 = __Porffor_funcLut_flags(set);
|
419
|
+
if (funcFlags & 0b10) {
|
420
|
+
// constructor func, add new.target, this args
|
421
|
+
Porffor.wasm`
|
422
|
+
f64.const 0
|
423
|
+
i32.const 0
|
424
|
+
local.get ${obj}
|
425
|
+
f64.convert_i32_u
|
426
|
+
i32.const 7
|
427
|
+
local.get ${value}
|
428
|
+
local.get ${value+1}
|
429
|
+
local.get ${set}
|
430
|
+
call_indirect 3 0`;
|
431
|
+
} else {
|
432
|
+
Porffor.wasm`
|
433
|
+
local.get ${value}
|
434
|
+
local.get ${value+1}
|
435
|
+
local.get ${set}
|
436
|
+
call_indirect 1 0`;
|
437
|
+
}
|
438
|
+
|
439
|
+
return value;
|
440
|
+
}
|
441
|
+
|
442
|
+
// data descriptor
|
443
|
+
if (!(tail & 0b1000)) {
|
444
|
+
// not writable, return now
|
445
|
+
throw new TypeError('Cannot modify read-only property of object');
|
446
|
+
}
|
447
|
+
|
448
|
+
// flags = same flags as before
|
449
|
+
flags = tail & 0xff;
|
450
|
+
}
|
451
|
+
|
452
|
+
// write new value value (lol)
|
453
|
+
Porffor.wasm.f64.store(entryPtr, value, 0, 4);
|
454
|
+
|
455
|
+
// write new tail (value type + flags)
|
456
|
+
Porffor.wasm.i32.store16(entryPtr,
|
457
|
+
flags + (Porffor.wasm`local.get ${value+1}` << 8),
|
458
|
+
0, 12);
|
459
|
+
|
460
|
+
return value;
|
461
|
+
};
|
462
|
+
|
378
463
|
export const __Porffor_object_define = (obj: any, key: any, value: any, flags: i32): void => {
|
379
464
|
if (Porffor.wasm`local.get ${obj+1}` != Porffor.TYPES.object) {
|
380
465
|
obj = __Porffor_object_getObject(obj);
|
@@ -477,7 +562,6 @@ export const __Porffor_object_delete = (obj: any, key: any): boolean => {
|
|
477
562
|
const tail: i32 = Porffor.wasm.i32.load16_u(entryPtr, 0, 12);
|
478
563
|
if (!(tail & 0b0010)) {
|
479
564
|
// not configurable
|
480
|
-
// todo: throw in strict mode
|
481
565
|
return false;
|
482
566
|
}
|
483
567
|
|
@@ -511,6 +595,71 @@ memory.copy 0 0`;
|
|
511
595
|
return true;
|
512
596
|
};
|
513
597
|
|
598
|
+
export const __Porffor_object_deleteStrict = (obj: any, key: any): boolean => {
|
599
|
+
if (Porffor.wasm`local.get ${obj}` == 0) throw new TypeError('Cannot delete property of null');
|
600
|
+
|
601
|
+
if (Porffor.wasm`local.get ${obj+1}` == Porffor.TYPES.function) {
|
602
|
+
const tmp1: bytestring = 'name';
|
603
|
+
if (key == tmp1) {
|
604
|
+
__Porffor_funcLut_deleteName(obj);
|
605
|
+
return true;
|
606
|
+
}
|
607
|
+
|
608
|
+
const tmp2: bytestring = 'length';
|
609
|
+
if (key == tmp2) {
|
610
|
+
__Porffor_funcLut_deleteLength(obj);
|
611
|
+
return true;
|
612
|
+
}
|
613
|
+
}
|
614
|
+
|
615
|
+
if (Porffor.wasm`local.get ${obj+1}` != Porffor.TYPES.object) obj = __Porffor_object_getObject(obj);
|
616
|
+
if (Porffor.rawType(obj) != Porffor.TYPES.object) {
|
617
|
+
// todo: support non-pure objects
|
618
|
+
return true;
|
619
|
+
}
|
620
|
+
|
621
|
+
const entryPtr: i32 = __Porffor_object_lookup(obj, key);
|
622
|
+
if (entryPtr == -1) {
|
623
|
+
// not found, stop
|
624
|
+
return true;
|
625
|
+
}
|
626
|
+
|
627
|
+
const tail: i32 = Porffor.wasm.i32.load16_u(entryPtr, 0, 12);
|
628
|
+
if (!(tail & 0b0010)) {
|
629
|
+
// not configurable
|
630
|
+
throw new TypeError('Cannot delete non-configurable property of object');
|
631
|
+
}
|
632
|
+
|
633
|
+
const ind: i32 = (entryPtr - Porffor.wasm`local.get ${obj}`) / 14;
|
634
|
+
|
635
|
+
// decrement size
|
636
|
+
let size: i32 = Porffor.wasm.i32.load(obj, 0, 0);
|
637
|
+
Porffor.wasm.i32.store(obj, --size, 0, 0);
|
638
|
+
|
639
|
+
if (size > ind) {
|
640
|
+
// offset all elements after by -1 ind
|
641
|
+
Porffor.wasm`
|
642
|
+
;; dst = entryPtr
|
643
|
+
local.get ${entryPtr}
|
644
|
+
|
645
|
+
;; src = entryPtr + 14 (+ 1 entry)
|
646
|
+
local.get ${entryPtr}
|
647
|
+
i32.const 14
|
648
|
+
i32.add
|
649
|
+
|
650
|
+
;; size = (size - ind) * 14
|
651
|
+
local.get ${size}
|
652
|
+
local.get ${ind}
|
653
|
+
i32.sub
|
654
|
+
i32.const 14
|
655
|
+
i32.mul
|
656
|
+
|
657
|
+
memory.copy 0 0`;
|
658
|
+
}
|
659
|
+
|
660
|
+
return true;
|
661
|
+
};
|
662
|
+
|
514
663
|
|
515
664
|
export const __Porffor_object_isEnumerable = (entryPtr: i32): boolean => {
|
516
665
|
const out: boolean = Porffor.wasm.i32.load8_u(entryPtr, 0, 12) & 0b0100;
|
@@ -595,13 +595,11 @@ export const __Object_defineProperty = (target: any, prop: any, descriptor: any)
|
|
595
595
|
|
596
596
|
let flags: i32 = 0b0000;
|
597
597
|
if (accessor) flags |= 0b0001;
|
598
|
-
if (configurable) flags |= 0b0010;
|
599
|
-
if (enumerable) flags |= 0b0100;
|
600
|
-
if (writable) flags |= 0b1000;
|
598
|
+
if (!!configurable) flags |= 0b0010;
|
599
|
+
if (!!enumerable) flags |= 0b0100;
|
600
|
+
if (!!writable) flags |= 0b1000;
|
601
601
|
|
602
|
-
if (accessor)
|
603
|
-
value = Porffor.object.packAccessor(get, set);
|
604
|
-
}
|
602
|
+
if (accessor) value = Porffor.object.packAccessor(get, set);
|
605
603
|
|
606
604
|
Porffor.object.define(target, p, value, flags);
|
607
605
|
return target;
|
@@ -680,6 +678,12 @@ export const __Object_prototype_isPrototypeOf = (_this: any, obj: any) => {
|
|
680
678
|
|
681
679
|
|
682
680
|
export const __Object_prototype_toString = (_this: any) => {
|
681
|
+
if (Porffor.rawType(_this) == Porffor.TYPES.object) {
|
682
|
+
const obj: object = _this;
|
683
|
+
const ovr: any = obj.toString;
|
684
|
+
if (ovr != null && ovr !== __Object_prototype_toString) return ovr.call(_this);
|
685
|
+
}
|
686
|
+
|
683
687
|
let out: bytestring = Porffor.allocate();
|
684
688
|
|
685
689
|
// 1. If the this value is undefined, return "[object Undefined]".
|
@@ -704,10 +708,16 @@ export const __Object_prototype_toString = (_this: any) => {
|
|
704
708
|
return out = '[object Object]';
|
705
709
|
};
|
706
710
|
|
707
|
-
export const __Object_prototype_toLocaleString = (_this: any) =>
|
711
|
+
export const __Object_prototype_toLocaleString = (_this: any) => __Object_prototype_toString(_this);
|
708
712
|
|
709
713
|
export const __Object_prototype_valueOf = (_this: any) => {
|
710
714
|
// todo: ToObject
|
715
|
+
if (Porffor.rawType(_this) == Porffor.TYPES.object) {
|
716
|
+
const obj: object = _this;
|
717
|
+
const ovr: any = obj.valueOf;
|
718
|
+
if (ovr != null && ovr !== __Object_prototype_valueOf) return ovr.call(_this);
|
719
|
+
}
|
720
|
+
|
711
721
|
return _this;
|
712
722
|
};
|
713
723
|
|
@@ -1,6 +1,30 @@
|
|
1
1
|
// general widely used ecma262/spec functions
|
2
2
|
import type {} from './porffor.d.ts';
|
3
3
|
|
4
|
+
export const __ecma262_ToPrimitive_Number = (input: any): any => {
|
5
|
+
// todo: %Symbol.toPrimitive%
|
6
|
+
|
7
|
+
let value: any = input.valueOf?.();
|
8
|
+
if (value != null && !Porffor.object.isObjectOrNull(value)) return value;
|
9
|
+
|
10
|
+
value = input.toString?.();
|
11
|
+
if (value != null && !Porffor.object.isObjectOrNull(value)) return value;
|
12
|
+
|
13
|
+
throw new TypeError('Cannot convert an object to primitive');
|
14
|
+
};
|
15
|
+
|
16
|
+
export const __ecma262_ToPrimitive_String = (input: any): any => {
|
17
|
+
// todo: %Symbol.toPrimitive%
|
18
|
+
|
19
|
+
let value: any = input.toString?.();
|
20
|
+
if (value != null && !Porffor.object.isObjectOrNull(value)) return value;
|
21
|
+
|
22
|
+
value = input.valueOf?.();
|
23
|
+
if (value != null && !Porffor.object.isObjectOrNull(value)) return value;
|
24
|
+
|
25
|
+
throw new TypeError('Cannot convert an object to primitive');
|
26
|
+
};
|
27
|
+
|
4
28
|
// 7.1.4 ToNumber (argument)
|
5
29
|
// https://tc39.es/ecma262/#sec-tonumber
|
6
30
|
export const __ecma262_ToNumber = (argument: unknown): number => {
|
@@ -35,13 +59,11 @@ export const __ecma262_ToNumber = (argument: unknown): number => {
|
|
35
59
|
|
36
60
|
// 7. Assert: argument is an Object.
|
37
61
|
// 8. Let primValue be ? ToPrimitive(argument, number).
|
62
|
+
const primValue: any = __ecma262_ToPrimitive_Number(argument);
|
63
|
+
|
38
64
|
// 9. Assert: primValue is not an Object.
|
39
65
|
// 10. Return ? ToNumber(primValue).
|
40
|
-
|
41
|
-
// // todo: I doubt this is spec-compliant
|
42
|
-
// return __ecma262_ToNumber(argument.valueOf());
|
43
|
-
|
44
|
-
return NaN;
|
66
|
+
return __ecma262_ToNumber(primValue);
|
45
67
|
};
|
46
68
|
|
47
69
|
|
@@ -128,26 +150,35 @@ export const __ecma262_ToString = (argument: unknown): any => {
|
|
128
150
|
}
|
129
151
|
|
130
152
|
// 7. If argument is a Number, return Number::toString(argument, 10).
|
153
|
+
if (type == Porffor.TYPES.number) return __Number_prototype_toString(argument, 10);
|
154
|
+
|
131
155
|
// 8. If argument is a BigInt, return BigInt::toString(argument, 10).
|
156
|
+
|
132
157
|
// 9. Assert: argument is an Object.
|
133
158
|
// 10. Let primValue be ? ToPrimitive(argument, string).
|
159
|
+
const primValue: any = __ecma262_ToPrimitive_String(argument);
|
160
|
+
|
134
161
|
// 11. Assert: primValue is not an Object.
|
135
162
|
// 12. Return ? ToString(primValue).
|
136
|
-
return
|
163
|
+
return __ecma262_ToString(primValue);
|
137
164
|
};
|
138
165
|
|
139
166
|
// 7.1.19 ToPropertyKey (argument)
|
140
167
|
// https://tc39.es/ecma262/#sec-topropertykey
|
141
168
|
export const __ecma262_ToPropertyKey = (argument: any): any => {
|
142
169
|
// 1. Let key be ? ToPrimitive(argument, string).
|
143
|
-
|
170
|
+
let key: any = argument;
|
171
|
+
|
172
|
+
// only run ToPrimitive if pure object for perf
|
173
|
+
if (Porffor.rawType(argument) == Porffor.TYPES.object && Porffor.wasm`local.get ${argument}` != 0)
|
174
|
+
key = __ecma262_ToPrimitive_String(argument);
|
144
175
|
|
145
176
|
// 2. If key is a Symbol, then
|
146
|
-
if (Porffor.rawType(
|
177
|
+
if (Porffor.rawType(key) == Porffor.TYPES.symbol) {
|
147
178
|
// a. Return key.
|
148
|
-
return
|
179
|
+
return key;
|
149
180
|
}
|
150
181
|
|
151
182
|
// 3. Return ! ToString(key).
|
152
|
-
return __ecma262_ToString(
|
183
|
+
return __ecma262_ToString(key);
|
153
184
|
};
|
@@ -16,11 +16,9 @@ export default function({ builtinFuncs }, Prefs) {
|
|
16
16
|
builtinFuncs['#get_' + name] = {
|
17
17
|
params: [],
|
18
18
|
locals: [],
|
19
|
-
globals: [ Valtype.i32 ],
|
20
|
-
globalNames: [ '#getptr_' + name ],
|
21
19
|
returns: [ Valtype.i32 ],
|
22
20
|
returnType: TYPES.object,
|
23
|
-
wasm: (scope, { allocPage, makeString, generate, getNodeType, builtin }) => {
|
21
|
+
wasm: (scope, { allocPage, makeString, generate, getNodeType, builtin, glbl }) => {
|
24
22
|
if (globalThis.precompile) return [ [ 'get object', name ] ];
|
25
23
|
|
26
24
|
// todo/perf: precompute bytes here instead of calling real funcs if we really care about perf later
|
@@ -32,17 +30,18 @@ export default function({ builtinFuncs }, Prefs) {
|
|
32
30
|
ptr = allocPage(scope, `builtin object: ${name}`);
|
33
31
|
}
|
34
32
|
|
33
|
+
const getPtr = glbl(Opcodes.global_get, `getptr_${name}`, Valtype.i32)[0];
|
35
34
|
const out = [
|
36
35
|
// check if already made/cached
|
37
|
-
|
36
|
+
getPtr,
|
38
37
|
[ Opcodes.if, Blocktype.void ],
|
39
|
-
|
38
|
+
getPtr,
|
40
39
|
[ Opcodes.return ],
|
41
40
|
[ Opcodes.end ],
|
42
41
|
|
43
42
|
// set cache & ptr for use
|
44
43
|
...number(ptr, Valtype.i32),
|
45
|
-
|
44
|
+
glbl(Opcodes.global_set, `getptr_${name}`, Valtype.i32)[0]
|
46
45
|
];
|
47
46
|
|
48
47
|
for (const x in props) {
|
@@ -62,7 +61,7 @@ export default function({ builtinFuncs }, Prefs) {
|
|
62
61
|
if (this[prefix + x]?.type === TYPES.object && this[prefix + x] !== this.null) value = { type: 'ObjectExpression', properties: [] };
|
63
62
|
|
64
63
|
out.push(
|
65
|
-
|
64
|
+
getPtr,
|
66
65
|
...number(existingFunc ? TYPES.function : TYPES.object, Valtype.i32),
|
67
66
|
|
68
67
|
...makeString(scope, x, false, `#builtin_object_${name}_${x}`),
|
@@ -75,16 +74,14 @@ export default function({ builtinFuncs }, Prefs) {
|
|
75
74
|
...number(flags, Valtype.i32),
|
76
75
|
...number(TYPES.number, Valtype.i32),
|
77
76
|
|
78
|
-
[ Opcodes.call, builtin('
|
77
|
+
[ Opcodes.call, builtin('__Porffor_object_expr_initWithFlags') ],
|
79
78
|
[ Opcodes.drop ],
|
80
79
|
[ Opcodes.drop ]
|
81
80
|
);
|
82
81
|
}
|
83
82
|
|
84
|
-
|
85
|
-
|
86
|
-
[ Opcodes.global_get, 0 ]
|
87
|
-
);
|
83
|
+
// return ptr
|
84
|
+
out.push(getPtr);
|
88
85
|
return out;
|
89
86
|
}
|
90
87
|
};
|