porffor 0.20.8 → 0.20.10

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.
@@ -128,4 +128,96 @@ export const __Porffor_object_set = (_this: object, key: any, value: any): any =
128
128
  0, 12);
129
129
 
130
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
+ const out: boolean = Porffor.wasm.i32.load8_u(ptr, 0, 12) & 0b0100;
200
+ return out;
201
+ };
202
+
203
+ export const __Porffor_object_isObject = (arg: any): boolean => {
204
+ const t: i32 = Porffor.wasm`local.get ${arg+1}`;
205
+ return Porffor.fastAnd(
206
+ arg != 0, // null
207
+ t > 0x05,
208
+ t != Porffor.TYPES.undefined,
209
+ t != Porffor.TYPES.string,
210
+ t != Porffor.TYPES.bytestring,
211
+ );
212
+ };
213
+
214
+ export const __Porffor_object_isObjectOrSymbol = (arg: any): boolean => {
215
+ const t: i32 = Porffor.wasm`local.get ${arg+1}`;
216
+ return Porffor.fastAnd(
217
+ arg != 0, // null
218
+ t > 0x04,
219
+ t != Porffor.TYPES.undefined,
220
+ t != Porffor.TYPES.string,
221
+ t != Porffor.TYPES.bytestring,
222
+ );
131
223
  };
@@ -21,15 +21,12 @@ export const __Object_keys = (obj: any): any[] => {
21
21
 
22
22
  const t: i32 = Porffor.rawType(obj);
23
23
  if (t == Porffor.TYPES.object) {
24
- const size: i32 = Porffor.wasm.i32.load(obj, 0, 0);
25
- let len: i32 = size;
26
-
27
24
  let ptr: i32 = Porffor.wasm`local.get ${obj}` + 4;
28
- const endPtr: i32 = ptr + size * 14;
25
+ const endPtr: i32 = ptr + Porffor.wasm.i32.load(obj, 0, 0) * 14;
29
26
 
30
27
  let i: i32 = 0;
31
28
  for (; ptr < endPtr; ptr += 14) {
32
- // todo: check enumerable flag
29
+ if (!Porffor.object.isEnumerable(ptr)) continue;
33
30
 
34
31
  let key: any;
35
32
  Porffor.wasm`local raw i32
@@ -60,7 +57,7 @@ local.set ${key}`;
60
57
  out[i++] = key;
61
58
  }
62
59
 
63
- out.length = len;
60
+ out.length = i;
64
61
  } else if (Porffor.fastOr(
65
62
  t == Porffor.TYPES.array,
66
63
  t == Porffor.TYPES.bytestring,
@@ -84,15 +81,12 @@ export const __Object_values = (obj: any): any[] => {
84
81
 
85
82
  const t: i32 = Porffor.rawType(obj);
86
83
  if (t == Porffor.TYPES.object) {
87
- const size: i32 = Porffor.wasm.i32.load(obj, 0, 0);
88
- let len: i32 = size;
89
-
90
84
  let ptr: i32 = Porffor.wasm`local.get ${obj}` + 4;
91
- const endPtr: i32 = ptr + size * 14;
85
+ const endPtr: i32 = ptr + Porffor.wasm.i32.load(obj, 0, 0) * 14;
92
86
 
93
87
  let i: i32 = 0;
94
88
  for (; ptr < endPtr; ptr += 14) {
95
- // todo: check enumerable flag
89
+ if (!Porffor.object.isEnumerable(ptr)) continue;
96
90
 
97
91
  let val: any;
98
92
  Porffor.wasm`local ptr32 i32
@@ -110,7 +104,7 @@ local.set ${val+1}`;
110
104
  out[i++] = val;
111
105
  }
112
106
 
113
- out.length = len;
107
+ out.length = i;
114
108
  } else if (Porffor.fastOr(
115
109
  t == Porffor.TYPES.array,
116
110
  t == Porffor.TYPES.bytestring,
@@ -154,7 +148,7 @@ export const __Object_fromEntries = (iterable: any): object => {
154
148
  const out: object = {};
155
149
 
156
150
  for (const x of iterable) {
157
- 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');
158
152
  out[ecma262.ToPropertyKey(x[0])] = x[1];
159
153
  }
160
154
 
@@ -167,7 +161,7 @@ export const __Object_prototype_hasOwnProperty = (_this: any, prop: any) => {
167
161
 
168
162
  const t: i32 = Porffor.rawType(_this);
169
163
  if (t == Porffor.TYPES.object) {
170
- return __Porffor_object_lookup(_this, prop) != -1;
164
+ return Porffor.object.lookup(_this, p) != -1;
171
165
  }
172
166
 
173
167
  const keys: any[] = __Object_keys(_this);
@@ -196,6 +190,65 @@ export const __Object_assign = (target: any, ...sources: any[]) => {
196
190
  return target;
197
191
  };
198
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
+
236
+
237
+ export const __Object_prototype_propertyIsEnumerable = (_this: any, prop: any) => {
238
+ const p: any = ecma262.ToPropertyKey(prop);
239
+
240
+ const t: i32 = Porffor.rawType(_this);
241
+ if (t == Porffor.TYPES.object) {
242
+ const entryPtr: i32 = Porffor.object.lookup(_this, p);
243
+ if (entryPtr == -1) return false;
244
+
245
+ return Porffor.object.isEnumerable(entryPtr);
246
+ }
247
+
248
+ const keys: any[] = __Object_keys(_this);
249
+ return __Array_prototype_includes(keys, p);
250
+ };
251
+
199
252
 
200
253
  export const __Object_prototype_toString = (_this: object) => {
201
254
  let out: bytestring = '[object Object]';
@@ -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,10 +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 => {
27
+ export const __ecma262_ToString = (argument: unknown): any => {
29
28
  const type: i32 = Porffor.rawType(argument);
30
29
 
31
30
  // 1. If argument is a String, return argument.
@@ -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;
@@ -2918,7 +2918,7 @@ const generateAssign = (scope, decl, _global, _name, valueUnused = false) => {
2918
2918
  ...(op === '=' ? [] : [ [ Opcodes.local_tee, localTmp(scope, '#objset_object', Valtype.i32) ] ]),
2919
2919
  ...getNodeType(scope, object),
2920
2920
 
2921
- ...generate(scope, property),
2921
+ ...generate(scope, property, false, '#member_prop'),
2922
2922
  ...getNodeType(scope, property),
2923
2923
  ...toPropertyKey(scope, op === '='),
2924
2924
  ...(op === '=' ? [] : [ [ Opcodes.local_set, localTmp(scope, '#objset_property_type', Valtype.i32) ] ]),
@@ -4212,6 +4212,7 @@ const makeArray = (scope, decl, global = false, name = '$undeclared', initEmpty
4212
4212
  const local = global ? globals[name] : scope.locals[name];
4213
4213
  if (
4214
4214
  Prefs.data && firstAssign && useRawElements &&
4215
+ name !== '#member_prop' &&
4215
4216
  (!globalThis.precompile || !global)
4216
4217
  ) {
4217
4218
  makeData(scope, elements, rawPtr, itemType, initEmpty);
@@ -4727,7 +4728,7 @@ const generateMember = (scope, decl, _global, _name) => {
4727
4728
  [ Opcodes.br, 1 ],
4728
4729
  [ Opcodes.end ],
4729
4730
 
4730
- ...generate(scope, property),
4731
+ ...generate(scope, property, false, '#member_prop'),
4731
4732
  [ Opcodes.local_set, localTmp(scope, '#member_prop') ]
4732
4733
  );
4733
4734
 
@@ -4739,7 +4740,7 @@ const generateMember = (scope, decl, _global, _name) => {
4739
4740
  ...generate(scope, object),
4740
4741
  [ Opcodes.local_set, localTmp(scope, '#member_obj') ],
4741
4742
 
4742
- ...generate(scope, property),
4743
+ ...generate(scope, property, false, '#member_prop'),
4743
4744
  [ Opcodes.local_set, localTmp(scope, '#member_prop') ]
4744
4745
  );
4745
4746
  }