@weborigami/language 0.5.2 → 0.5.4

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.
@@ -455,8 +455,12 @@ export function makeUnaryOperation(operator, value, location) {
455
455
  "+": ops.unaryPlus,
456
456
  "-": ops.unaryMinus,
457
457
  "~": ops.bitwiseNot,
458
+ await: null, // no-op
459
+ typeof: ops.typeOf,
460
+ void: ops.voidOp,
458
461
  };
459
- return annotate([operators[operator], value], location);
462
+ const op = operators[operator];
463
+ return op ? annotate([op, value], location) : annotate(value, location);
460
464
  }
461
465
 
462
466
  /**
@@ -191,52 +191,56 @@ async function importWrapper(modulePath) {
191
191
  * Origami evaluate() function calls all functions with the evaluation context
192
192
  * -- the tree in which the code is running -- as the call target.
193
193
  *
194
- * This function works around the problem. If the indicated classFn has no
195
- * static methods, it's returned as is. If it does have static methods, this
196
- * returns an extension of the classFn prototype that overrides the static
197
- * methods with ones that are bound to the class.
194
+ * This function works around the problem. If the indicated object has no static
195
+ * methods, it's returned as is. If it does have static methods, this returns an
196
+ * extension of the object that overrides the static methods with ones that are
197
+ * bound to the object.
198
198
  */
199
- function bindStaticMethodsForClass(fn) {
199
+ function bindStaticMethods(obj) {
200
+ if (typeof obj !== "function" && (typeof obj !== "object" || obj === null)) {
201
+ // Something like `NaN` or `null`
202
+ return obj;
203
+ }
204
+
200
205
  const staticMethodDescriptors = Object.entries(
201
- Object.getOwnPropertyDescriptors(fn)
206
+ Object.getOwnPropertyDescriptors(obj)
202
207
  )
203
208
  .filter(([key, descriptor]) => descriptor.value instanceof Function)
204
209
  .map(([key, descriptor]) => [
205
210
  key,
206
211
  {
207
212
  ...descriptor,
208
- value: descriptor.value.bind(fn),
213
+ value: descriptor.value.bind(obj),
209
214
  },
210
215
  ]);
211
216
  if (staticMethodDescriptors.length === 0) {
212
217
  // No static methods
213
- return fn;
218
+ return obj;
214
219
  }
215
220
 
216
221
  let extended;
217
- if (!fn.prototype) {
218
- // A function like Proxy
219
- extended = Object.create(fn);
222
+ // A regular object or an oddball like Proxy with no prototype
223
+ if (typeof obj === "object" || !obj.prototype) {
224
+ extended = Object.create(obj);
220
225
  } else {
221
226
  /** @this {any} */
222
227
  extended = function (...args) {
223
228
  const calledWithNew = this instanceof extended;
224
- return calledWithNew ? new fn(...args) : fn(...args);
229
+ return calledWithNew ? new obj(...args) : obj(...args);
225
230
  };
226
231
  }
227
232
 
228
- return Object.defineProperties(
233
+ Object.defineProperties(
229
234
  extended,
230
235
  Object.fromEntries(staticMethodDescriptors)
231
236
  );
237
+
238
+ return extended;
232
239
  }
233
240
 
234
241
  function bindStaticMethodsForGlobals(objects) {
235
242
  const entries = Object.entries(objects);
236
- const bound = entries.map(([key, value]) => [
237
- key,
238
- value instanceof Function ? bindStaticMethodsForClass(value) : value,
239
- ]);
243
+ const bound = entries.map(([key, value]) => [key, bindStaticMethods(value)]);
240
244
  return Object.fromEntries(bound);
241
245
  }
242
246
 
@@ -547,6 +547,18 @@ export async function templateText(strings, ...values) {
547
547
  }
548
548
  addOpLabel(templateText, "«ops.templateText»");
549
549
 
550
+ /**
551
+ * Emulate the JavaScript `typeof` operator
552
+ *
553
+ * Note the name is `typeOf` (uppercase "O"), as `typeof` is a reserved word
554
+ *
555
+ * @param {any} value
556
+ */
557
+ export function typeOf(value) {
558
+ return typeof value;
559
+ }
560
+ addOpLabel(typeOf, "«ops.typeOf»");
561
+
550
562
  export function unaryMinus(a) {
551
563
  return -a;
552
564
  }
@@ -567,3 +579,13 @@ export async function unpack(value) {
567
579
  return isUnpackable(value) ? value.unpack() : value;
568
580
  }
569
581
  addOpLabel(unpack, "«ops.unpack»");
582
+
583
+ /**
584
+ * Emulate JavaScript's rarely-used `void` operator
585
+ *
586
+ * @param {any} value
587
+ */
588
+ export function voidOp(value) {
589
+ return undefined;
590
+ }
591
+ addOpLabel(voidOp, "«ops.voidOp»");
@@ -155,6 +155,11 @@ describe("Origami parser", () => {
155
155
  ],
156
156
  ],
157
157
  ]);
158
+ assertParse("arrowFunction", "async (x) => x", [
159
+ ops.lambda,
160
+ [[ops.literal, "x"]],
161
+ [markers.traverse, [markers.reference, "x"]],
162
+ ]);
158
163
  });
159
164
 
160
165
  test("bitwiseAndExpression", () => {
@@ -1565,6 +1570,9 @@ Body text`,
1565
1570
  assertParse("unaryExpression", "+1", [ops.unaryPlus, [ops.literal, 1]]);
1566
1571
  assertParse("unaryExpression", "-2", [ops.unaryMinus, [ops.literal, 2]]);
1567
1572
  assertParse("unaryExpression", "~3", [ops.bitwiseNot, [ops.literal, 3]]);
1573
+ assertParse("unaryExpression", "typeof 1", [ops.typeOf, [ops.literal, 1]]);
1574
+ assertParse("unaryExpression", "void 0", [ops.voidOp, [ops.literal, 0]]);
1575
+ assertParse("unaryExpression", "await 2", [ops.literal, 2]);
1568
1576
  });
1569
1577
 
1570
1578
  test("unaryOperator", () => {
@@ -414,6 +414,17 @@ describe("ops", () => {
414
414
  assert.strictEqual(ops.subtraction(5, true), 4);
415
415
  });
416
416
 
417
+ test("ops.typeOf emulates JavaScript typeof", () => {
418
+ assert.strictEqual(ops.typeOf(true), "boolean");
419
+ assert.strictEqual(ops.typeOf(1), "number");
420
+ assert.strictEqual(ops.typeOf("hi"), "string");
421
+ assert.strictEqual(ops.typeOf(undefined), "undefined");
422
+ assert.strictEqual(
423
+ ops.typeOf(() => null),
424
+ "function"
425
+ );
426
+ });
427
+
417
428
  test("ops.unaryMinus", () => {
418
429
  assert.strictEqual(ops.unaryMinus(4), -4);
419
430
  assert.strictEqual(ops.unaryMinus(-4), 4);
@@ -431,6 +442,12 @@ describe("ops", () => {
431
442
  const result = await ops.unpack.call(null, fixture);
432
443
  assert.strictEqual(result, "unpacked");
433
444
  });
445
+
446
+ test("ops.voidOp returns undefined", () => {
447
+ assert.strictEqual(ops.voidOp(123), undefined);
448
+ assert.strictEqual(ops.voidOp("hello"), undefined);
449
+ assert.strictEqual(ops.voidOp(null), undefined);
450
+ });
434
451
  });
435
452
 
436
453
  function errorFn() {