porffor 0.20.7 → 0.20.9

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.
@@ -0,0 +1,222 @@
1
+ // @porf --valtype=i32
2
+ import type {} from './porffor.d.ts';
3
+
4
+ // memory layout:
5
+ // size (i32, 4)
6
+ // per entry (14):
7
+ // key - value, type MSB encoded (u32, 4)
8
+ // value - value (f64, 8)
9
+ // value - type + obj flag (u16, 2)
10
+ // flags:
11
+ // accessor - 0b0001
12
+ // configurable - 0b0010
13
+ // enumerable - 0b0100
14
+ // writable - 0b1000
15
+
16
+ export const __Porffor_object_lookup = (_this: object, target: any): i32 => {
17
+ const targetType: i32 = Porffor.wasm`local.get ${target+1}`;
18
+
19
+ let ptr: i32 = Porffor.wasm`local.get ${_this}` + 4;
20
+
21
+ const size: i32 = Porffor.wasm.i32.load(_this, 0, 0);
22
+ const endPtr: i32 = ptr + size * 14;
23
+
24
+ if (targetType == Porffor.TYPES.bytestring) {
25
+ const targetStr: bytestring = target;
26
+ for (; ptr < endPtr; ptr += 14) {
27
+ const keyRaw: i32 = Porffor.wasm.i32.load(ptr, 0, 0);
28
+ if (keyRaw == 0) break; // ran out of keys
29
+ if (keyRaw >>> 31) continue; // MSB set, regular string type
30
+
31
+ const keyStr: bytestring = keyRaw;
32
+ if (keyStr == targetStr) return ptr;
33
+ }
34
+ } else {
35
+ const targetStr: string = target;
36
+ for (; ptr < endPtr; ptr += 14) {
37
+ const keyRaw: i32 = Porffor.wasm.i32.load(ptr, 0, 0);
38
+ if (keyRaw == 0) break; // ran out of keys
39
+ if (keyRaw >>> 31) { // MSB set, regular string type
40
+ const keyStr: string = keyRaw & 0x7FFFFFFF; // unset MSB
41
+ if (keyStr == targetStr) return ptr;
42
+ }
43
+ }
44
+ }
45
+
46
+ return -1;
47
+ };
48
+
49
+ export const __Porffor_object_get = (_this: object, key: any): any => {
50
+ const entryPtr: i32 = __Porffor_object_lookup(_this, key);
51
+ if (entryPtr == -1) {
52
+ Porffor.wasm`
53
+ f64.const 0
54
+ i32.const 128
55
+ return`;
56
+ }
57
+
58
+ const tail: i32 = Porffor.wasm.i32.load16_u(entryPtr, 0, 12);
59
+
60
+ if (tail & 0b0001) {
61
+ // accessor descriptor
62
+ // todo
63
+
64
+ Porffor.wasm`
65
+ f64.const 0
66
+ i32.const 128
67
+ return`;
68
+ }
69
+
70
+ // data descriptor
71
+ Porffor.wasm`
72
+ local.get ${entryPtr}
73
+ f64.load 0 4
74
+ local.get ${tail}
75
+ i32.const 8
76
+ i32.shr_u
77
+ return`;
78
+ };
79
+
80
+ export const __Porffor_object_set = (_this: object, key: any, value: any): any => {
81
+ let entryPtr: i32 = __Porffor_object_lookup(_this, key);
82
+ let flags: i32;
83
+ if (entryPtr == -1) {
84
+ // add new entry
85
+ // bump size +1
86
+ const size: i32 = Porffor.wasm.i32.load(_this, 0, 0);
87
+ Porffor.wasm.i32.store(_this, size + 1, 0, 0);
88
+
89
+ // entryPtr = current end of object
90
+ entryPtr = Porffor.wasm`local.get ${_this}` + 4 + size * 14;
91
+
92
+ // encode key type, set MSB if regular string
93
+ let keyEnc: i32 = Porffor.wasm`local.get ${key}`;
94
+ if (Porffor.wasm`local.get ${key+1}` == Porffor.TYPES.string) keyEnc |= 0x80000000;
95
+
96
+ // write key value and type (MSB)
97
+ Porffor.wasm.i32.store(entryPtr, keyEnc, 0, 0);
98
+
99
+ // flags = writable, enumerable, configurable, not accessor
100
+ flags = 0b1110;
101
+ } else {
102
+ // existing entry, modify it
103
+ const tail: i32 = Porffor.wasm.i32.load16_u(entryPtr, 0, 12);
104
+
105
+ if (tail & 0b0001) {
106
+ // accessor descriptor
107
+ // todo
108
+
109
+ return value;
110
+ }
111
+
112
+ // data descriptor
113
+ if (!(tail & 0b1000)) {
114
+ // not writable, return now
115
+ return value;
116
+ }
117
+
118
+ // flags = same flags as before
119
+ flags = tail & 0xff;
120
+ }
121
+
122
+ // write new value value (lol)
123
+ Porffor.wasm.f64.store(entryPtr, value, 0, 4);
124
+
125
+ // write new tail (value type + flags)
126
+ Porffor.wasm.i32.store16(entryPtr,
127
+ flags + (Porffor.wasm`local.get ${value+1}` << 8),
128
+ 0, 12);
129
+
130
+ return value;
131
+ };
132
+
133
+ export const __Porffor_object_define = (_this: object, key: any, value: any, flags: any): any => {
134
+ let entryPtr: i32 = __Porffor_object_lookup(_this, key);
135
+ if (entryPtr == -1) {
136
+ // add new entry
137
+ // bump size +1
138
+ const size: i32 = Porffor.wasm.i32.load(_this, 0, 0);
139
+ Porffor.wasm.i32.store(_this, size + 1, 0, 0);
140
+
141
+ // entryPtr = current end of object
142
+ entryPtr = Porffor.wasm`local.get ${_this}` + 4 + size * 14;
143
+
144
+ // encode key type, set MSB if regular string
145
+ let keyEnc: i32 = Porffor.wasm`local.get ${key}`;
146
+ if (Porffor.wasm`local.get ${key+1}` == Porffor.TYPES.string) keyEnc |= 0x80000000;
147
+
148
+ // write key value and type (MSB)
149
+ Porffor.wasm.i32.store(entryPtr, keyEnc, 0, 0);
150
+ } else {
151
+ // existing entry, check and maybe modify it
152
+ const tail: i32 = Porffor.wasm.i32.load16_u(entryPtr, 0, 12);
153
+
154
+ if ((tail & 0b0010) == 0) {
155
+ // not already configurable, check to see if we can redefine
156
+ if ((tail & 0b1111) != flags) {
157
+ // flags have changed, perform checks
158
+ let err: boolean = false;
159
+
160
+ // descriptor type (accessor/data) and/or flags (other than writable) have changed
161
+ if ((tail & 0b0111) != flags) err = true;
162
+ else if (!(tail & 0b0001) && !(tail & 0b1000)) {
163
+ // data descriptor and already non-writable only checks
164
+ // trying to change writable false -> true
165
+ if (flags & 0b1000) {
166
+ err = true;
167
+ } else {
168
+ // if already non-writable, check value isn't being changed
169
+ Porffor.wasm`
170
+ local.get ${entryPtr}
171
+ f64.load 0 4
172
+ local.get ${value}
173
+ f64.ne
174
+
175
+ local.get ${entryPtr}
176
+ i32.load8_u 0 13
177
+ local.get ${value+1}
178
+ i32.ne
179
+ i32.or
180
+ local.set ${err}`;
181
+ }
182
+ }
183
+
184
+ if (err) throw new TypeError('Cannot redefine property');
185
+ }
186
+ }
187
+ }
188
+
189
+ // write new value value (lol)
190
+ Porffor.wasm.f64.store(entryPtr, value, 0, 4);
191
+
192
+ // write new tail (value type + flags)
193
+ Porffor.wasm.i32.store16(entryPtr,
194
+ flags + (Porffor.wasm`local.get ${value+1}` << 8),
195
+ 0, 12);
196
+ };
197
+
198
+ export const __Porffor_object_isEnumerable = (ptr: i32): boolean => {
199
+ return Porffor.wasm.i32.load8_u(ptr, 0, 12) & 0b0100;
200
+ };
201
+
202
+ export const __Porffor_object_isObject = (arg: any): boolean => {
203
+ const t: i32 = Porffor.wasm`local.get ${arg+1}`;
204
+ return Porffor.fastAnd(
205
+ arg != 0, // null
206
+ t > 0x05,
207
+ t != Porffor.TYPES.undefined,
208
+ t != Porffor.TYPES.string,
209
+ t != Porffor.TYPES.bytestring,
210
+ );
211
+ };
212
+
213
+ export const __Porffor_object_isObjectOrSymbol = (arg: any): boolean => {
214
+ const t: i32 = Porffor.wasm`local.get ${arg+1}`;
215
+ return Porffor.fastAnd(
216
+ arg != 0, // null
217
+ t > 0x04,
218
+ t != Porffor.TYPES.undefined,
219
+ t != Porffor.TYPES.string,
220
+ t != Porffor.TYPES.bytestring,
221
+ );
222
+ };
@@ -62,7 +62,7 @@ export const __Porffor_miniLog = (arg: any) => {
62
62
  } else {
63
63
  printStatic('[ ');
64
64
  for (let i: i32 = 0; i <= arrLen; i++) {
65
- __Porffor_miniPrint(arg[i]);
65
+ __Porffor_miniLog(arg[i]);
66
66
  if (i != arrLen) printStatic(', ');
67
67
  }
68
68
  printStatic(' ]');
@@ -2,8 +2,8 @@ export default () => {
2
2
  let out = '';
3
3
 
4
4
  const error = name => out += `export const ${name} = function (message: bytestring) {
5
- new.target;
6
- return Object();
5
+ new.target; // trick compiler into allowing as constructor
6
+ return {};
7
7
  };`;
8
8
 
9
9
  error('Error');
@@ -1,5 +1,19 @@
1
1
  import type {} from './porffor.d.ts';
2
2
 
3
+ export const Object = function (value: any): object {
4
+ new.target; // trick compiler into allowing as constructor
5
+
6
+ if (value == null) {
7
+ // if nullish, return new empty object
8
+ const obj: object = Porffor.allocate();
9
+ return obj;
10
+ }
11
+
12
+ // todo: turn primitive args into objects
13
+ // return input
14
+ return value;
15
+ };
16
+
3
17
  export const __Object_keys = (obj: any): any[] => {
4
18
  if (obj == null) throw new TypeError('Argument is nullish, expected object');
5
19
 
@@ -7,13 +21,43 @@ export const __Object_keys = (obj: any): any[] => {
7
21
 
8
22
  const t: i32 = Porffor.rawType(obj);
9
23
  if (t == Porffor.TYPES.object) {
10
- const keys: Set = Porffor.wasm.i32.load(obj, 0, 0);
11
- const size: i32 = Porffor.wasm.i32.load(keys, 0, 0);
12
- out.length = size;
13
-
14
- for (let i: i32 = 0; i < size; i++) {
15
- out[i] = Porffor.set.read(keys, i);
24
+ let ptr: i32 = Porffor.wasm`local.get ${obj}` + 4;
25
+ const endPtr: i32 = ptr + Porffor.wasm.i32.load(obj, 0, 0) * 14;
26
+
27
+ let i: i32 = 0;
28
+ for (; ptr < endPtr; ptr += 14) {
29
+ if (!Porffor.object.isEnumerable(ptr)) continue;
30
+
31
+ let key: any;
32
+ Porffor.wasm`local raw i32
33
+ local.get ${ptr}
34
+ i32.to_u
35
+ i32.load 0 0
36
+ local.set raw
37
+
38
+ local.get raw
39
+ i32.const 31
40
+ i32.shr_u
41
+ if 127
42
+ i32.const 67
43
+ local.set ${key+1}
44
+
45
+ local.get raw
46
+ i32.const 2147483647
47
+ i32.and
48
+ else
49
+ i32.const 195
50
+ local.set ${key+1}
51
+
52
+ local.get raw
53
+ end
54
+ i32.from_u
55
+ local.set ${key}`;
56
+
57
+ out[i++] = key;
16
58
  }
59
+
60
+ out.length = i;
17
61
  } else if (Porffor.fastOr(
18
62
  t == Porffor.TYPES.array,
19
63
  t == Porffor.TYPES.bytestring,
@@ -37,13 +81,30 @@ export const __Object_values = (obj: any): any[] => {
37
81
 
38
82
  const t: i32 = Porffor.rawType(obj);
39
83
  if (t == Porffor.TYPES.object) {
40
- const size: i32 = Porffor.wasm.i32.load(Porffor.wasm.i32.load(obj, 0, 0), 0, 0);
41
- const vals: any[] = Porffor.wasm.i32.load(obj, 0, 4);
84
+ let ptr: i32 = Porffor.wasm`local.get ${obj}` + 4;
85
+ const endPtr: i32 = ptr + Porffor.wasm.i32.load(obj, 0, 0) * 14;
86
+
87
+ let i: i32 = 0;
88
+ for (; ptr < endPtr; ptr += 14) {
89
+ if (!Porffor.object.isEnumerable(ptr)) continue;
42
90
 
43
- out.length = size;
44
- for (let i: i32 = 0; i < size; i++) {
45
- out[i] = vals[i];
91
+ let val: any;
92
+ Porffor.wasm`local ptr32 i32
93
+ local.get ${ptr}
94
+ i32.to_u
95
+ local.tee ptr32
96
+
97
+ f64.load 0 4
98
+ local.set ${val}
99
+
100
+ local.get ptr32
101
+ i32.load8_u 0 13
102
+ local.set ${val+1}`;
103
+
104
+ out[i++] = val;
46
105
  }
106
+
107
+ out.length = i;
47
108
  } else if (Porffor.fastOr(
48
109
  t == Porffor.TYPES.array,
49
110
  t == Porffor.TYPES.bytestring,
@@ -87,7 +148,7 @@ export const __Object_fromEntries = (iterable: any): object => {
87
148
  const out: object = {};
88
149
 
89
150
  for (const x of iterable) {
90
- if (Porffor.rawType(x) < 0x06) throw new TypeError('Iterator contains non-object');
151
+ if (!Porffor.object.isObject(x)) throw new TypeError('Iterator contains non-object');
91
152
  out[ecma262.ToPropertyKey(x[0])] = x[1];
92
153
  }
93
154
 
@@ -100,8 +161,7 @@ export const __Object_prototype_hasOwnProperty = (_this: any, prop: any) => {
100
161
 
101
162
  const t: i32 = Porffor.rawType(_this);
102
163
  if (t == Porffor.TYPES.object) {
103
- const keys: Set = Porffor.wasm.i32.load(_this, 0, 0);
104
- return __Set_prototype_has(keys, p);
164
+ return Porffor.object.lookup(_this, p) != -1;
105
165
  }
106
166
 
107
167
  const keys: any[] = __Object_keys(_this);
@@ -130,6 +190,49 @@ export const __Object_assign = (target: any, ...sources: any[]) => {
130
190
  return target;
131
191
  };
132
192
 
193
+ export const __Object_defineProperty = (target: any, prop: any, descriptor: any) => {
194
+ if (!Porffor.object.isObject(target)) throw new TypeError('Target is a non-object');
195
+
196
+ // if (Porffor.rawType(descriptor) < 0x06) {
197
+ if (Porffor.rawType(descriptor) != Porffor.TYPES.object) {
198
+ throw new TypeError('Descriptor is a non-object');
199
+ }
200
+
201
+ const p: any = ecma262.ToPropertyKey(prop);
202
+
203
+ const desc: object = descriptor;
204
+
205
+ // base keys
206
+ const configurable: any = desc.configurable; // defaults to false/undefined
207
+ const enumerable: any = desc.enumerable; // defaults to false/undefined
208
+
209
+ // data descriptor keys
210
+ const value: any = desc.value;
211
+ const writable: any = desc.writable;
212
+
213
+ const get: any = desc.get;
214
+ const set: any = desc.set;
215
+
216
+ let accessor: boolean = false;
217
+
218
+ if (get || set) {
219
+ if (value || writable) {
220
+ throw new TypeError('Descriptor cannot define both accessor and data descriptor attributes');
221
+ }
222
+
223
+ accessor = true;
224
+ }
225
+
226
+ let flags: i32 = 0b0000;
227
+ if (accessor) flags |= 0b0001;
228
+ if (configurable) flags |= 0b0010;
229
+ if (enumerable) flags |= 0b0100;
230
+ if (writable) flags |= 0b1000;
231
+
232
+ Porffor.object.define(target, p, value, flags);
233
+ return target;
234
+ };
235
+
133
236
 
134
237
  export const __Object_prototype_toString = (_this: object) => {
135
238
  let out: bytestring = '[object Object]';
@@ -1,17 +1,6 @@
1
1
  import type {} from './porffor.d.ts';
2
2
 
3
3
  // dark wasm magic for dealing with memory, sorry.
4
- export const __Porffor_allocate = (): number => {
5
- Porffor.wasm`
6
- i32.const 1
7
- memory.grow 0
8
- i32.const 65536
9
- i32.mul
10
- i32.from_u
11
- i32.const 1
12
- return`;
13
- };
14
-
15
4
  export const __Porffor_set_read = (_this: Set, index: number): any => {
16
5
  Porffor.wasm`
17
6
  local offset i32
@@ -3,7 +3,7 @@ import type {} from './porffor.d.ts';
3
3
  export const WeakRef = function (target: any): WeakRef {
4
4
  if (!new.target) throw new TypeError("Constructor WeakRef requires 'new'");
5
5
 
6
- if (Porffor.rawType(target) < 0x05) throw new TypeError('Target for WeakRef needs to be an object or symbol');
6
+ if (!Porffor.object.isObjectOrSymbol(target)) throw new TypeError('Target for WeakRef needs to be an object or symbol');
7
7
 
8
8
  const out: WeakRef = Porffor.allocateBytes(9);
9
9
 
@@ -22,11 +22,9 @@ export const __ecma262_ToIntegerOrInfinity = (argument: unknown): number => {
22
22
  return number;
23
23
  };
24
24
 
25
- // todo: support non-bytestring properly
26
25
  // 7.1.17 ToString (argument)
27
26
  // https://tc39.es/ecma262/#sec-tostring
28
- export const __ecma262_ToString = (argument: unknown): bytestring => {
29
- let out: bytestring = Porffor.allocate();
27
+ export const __ecma262_ToString = (argument: unknown): any => {
30
28
  const type: i32 = Porffor.rawType(argument);
31
29
 
32
30
  // 1. If argument is a String, return argument.
@@ -37,6 +35,8 @@ export const __ecma262_ToString = (argument: unknown): bytestring => {
37
35
  // 2. If argument is a Symbol, throw a TypeError exception.
38
36
  if (type == Porffor.TYPES.symbol) throw new TypeError('Cannot convert a Symbol value to a string');
39
37
 
38
+ let out: bytestring = Porffor.allocate();
39
+
40
40
  // 3. If argument is undefined, return "undefined".
41
41
  if (Porffor.fastOr(
42
42
  type == Porffor.TYPES.undefined,
@@ -68,14 +68,14 @@ export const __ecma262_ToString = (argument: unknown): bytestring => {
68
68
  // https://tc39.es/ecma262/#sec-topropertykey
69
69
  export const __ecma262_ToPropertyKey = (argument: any): any => {
70
70
  // 1. Let key be ? ToPrimitive(argument, string).
71
- const key: any = argument;
71
+ // argument = key
72
72
 
73
73
  // 2. If key is a Symbol, then
74
- if (Porffor.rawType(key) == Porffor.TYPES.symbol) {
74
+ if (Porffor.rawType(argument) == Porffor.TYPES.symbol) {
75
75
  // a. Return key.
76
- return key;
76
+ return argument;
77
77
  }
78
78
 
79
79
  // 3. Return ! ToString(key).
80
- return __ecma262_ToString(key);
80
+ return __ecma262_ToString(argument);
81
81
  };
@@ -98,7 +98,7 @@ export const Map = function (iterable: any): Map {
98
98
  Porffor.wasm.i32.store(out, vals, 0, 4);
99
99
 
100
100
  if (iterable != null) for (const x of iterable) {
101
- if (Porffor.rawType(x) < 0x06) throw new TypeError('Iterator contains non-object');
101
+ if (!Porffor.object.isObject(x)) throw new TypeError('Iterator contains non-object');
102
102
  __Map_prototype_set(out, x[0], x[1]);
103
103
  }
104
104
 
@@ -3,7 +3,7 @@ import type {} from './porffor.d.ts';
3
3
  export const __WeakMap_prototype_has = (_this: WeakMap, key: any) => __Map_prototype_has(_this, key);
4
4
 
5
5
  export const __WeakMap_prototype_set = (_this: WeakMap, key: any, value: any) => {
6
- if (Porffor.rawType(key) < 0x05) throw new TypeError('Value in WeakSet needs to be an object or symbol');
6
+ if (!Porffor.object.isObjectOrSymbol(key)) throw new TypeError('Value in WeakSet needs to be an object or symbol');
7
7
 
8
8
  __Map_prototype_set(_this, key, value);
9
9
  return _this;
@@ -23,7 +23,7 @@ export const WeakMap = function (iterable: any): WeakMap {
23
23
  Porffor.wasm.i32.store(out, vals, 0, 4);
24
24
 
25
25
  if (iterable != null) for (const x of iterable) {
26
- if (Porffor.rawType(x) < 0x06) throw new TypeError('Iterator contains non-object');
26
+ if (!Porffor.object.isObject(x)) throw new TypeError('Iterator contains non-object');
27
27
  __WeakMap_prototype_set(out, x[0], x[1]);
28
28
  }
29
29
 
@@ -3,7 +3,7 @@ import type {} from './porffor.d.ts';
3
3
  export const __WeakSet_prototype_has = (_this: WeakSet, value: any) => __Set_prototype_has(_this, value);
4
4
 
5
5
  export const __WeakSet_prototype_add = (_this: WeakSet, value: any) => {
6
- if (Porffor.rawType(value) < 0x05) throw new TypeError('Value in WeakSet needs to be an object or symbol');
6
+ if (!Porffor.object.isObjectOrSymbol(value)) throw new TypeError('Value in WeakSet needs to be an object or symbol');
7
7
 
8
8
  __Set_prototype_add(_this, value);
9
9
  return _this;
@@ -248,19 +248,6 @@ export const BuiltinFuncs = function() {
248
248
  constr: true
249
249
  };
250
250
 
251
- // just return given (default 0) for (new) Object() as we somewhat supports object just not constructor
252
- this.Object = {
253
- params: [ valtypeBinary ],
254
- locals: [],
255
- returns: [ valtypeBinary ],
256
- returnType: TYPES.object,
257
- wasm: [
258
- // [ Opcodes.local_get, 0 ]
259
- ...number(1)
260
- ],
261
- constr: true
262
- };
263
-
264
251
  this.isNaN = {
265
252
  floatOnly: true,
266
253
  params: [ valtypeBinary ],
@@ -427,7 +414,7 @@ export const BuiltinFuncs = function() {
427
414
  returnType: TYPES.number,
428
415
  wasm: [
429
416
  [ Opcodes.local_get, 0 ],
430
- Opcodes.i32_trunc_sat_f64_u,
417
+ Opcodes.i32_to_u,
431
418
  [ Opcodes.i32_clz ],
432
419
  Opcodes.i32_from
433
420
  ]
@@ -455,9 +442,9 @@ export const BuiltinFuncs = function() {
455
442
  returnType: TYPES.number,
456
443
  wasm: [
457
444
  [ Opcodes.local_get, 0 ],
458
- Opcodes.i32_trunc_sat_f64_s,
445
+ Opcodes.i32_to,
459
446
  [ Opcodes.local_get, 1 ],
460
- Opcodes.i32_trunc_sat_f64_s,
447
+ Opcodes.i32_to,
461
448
  [ Opcodes.i32_mul ],
462
449
  Opcodes.i32_from
463
450
  ]
@@ -980,6 +967,19 @@ export const BuiltinFuncs = function() {
980
967
  ]
981
968
  };
982
969
 
970
+ this.__Porffor_allocate = {
971
+ params: [],
972
+ locals: [],
973
+ returns: [ Valtype.i32 ],
974
+ returnType: TYPES.number,
975
+ wasm: [
976
+ ...number(1, Valtype.i32),
977
+ [ Opcodes.memory_grow, 0 ],
978
+ ...number(65536, Valtype.i32),
979
+ [ Opcodes.i32_mul ]
980
+ ]
981
+ };
982
+
983
983
  this.__Porffor_allocateBytes = {
984
984
  params: [ Valtype.i32 ],
985
985
  locals: [],