@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.
- package/package.json +3 -3
- package/src/compiler/origami.pegjs +19 -12
- package/src/compiler/parse.js +575 -445
- package/src/compiler/parserHelpers.js +5 -1
- package/src/runtime/jsGlobals.js +21 -17
- package/src/runtime/ops.js +22 -0
- package/test/compiler/parse.test.js +8 -0
- package/test/runtime/ops.test.js +17 -0
|
@@ -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
|
-
|
|
462
|
+
const op = operators[operator];
|
|
463
|
+
return op ? annotate([op, value], location) : annotate(value, location);
|
|
460
464
|
}
|
|
461
465
|
|
|
462
466
|
/**
|
package/src/runtime/jsGlobals.js
CHANGED
|
@@ -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
|
|
195
|
-
*
|
|
196
|
-
*
|
|
197
|
-
*
|
|
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
|
|
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(
|
|
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(
|
|
213
|
+
value: descriptor.value.bind(obj),
|
|
209
214
|
},
|
|
210
215
|
]);
|
|
211
216
|
if (staticMethodDescriptors.length === 0) {
|
|
212
217
|
// No static methods
|
|
213
|
-
return
|
|
218
|
+
return obj;
|
|
214
219
|
}
|
|
215
220
|
|
|
216
221
|
let extended;
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
extended = Object.create(
|
|
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
|
|
229
|
+
return calledWithNew ? new obj(...args) : obj(...args);
|
|
225
230
|
};
|
|
226
231
|
}
|
|
227
232
|
|
|
228
|
-
|
|
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
|
|
package/src/runtime/ops.js
CHANGED
|
@@ -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", () => {
|
package/test/runtime/ops.test.js
CHANGED
|
@@ -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() {
|