@weborigami/language 0.1.0 → 0.2.1

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.
@@ -5,12 +5,42 @@ import { describe, test } from "node:test";
5
5
  import { evaluate, ops } from "../../src/runtime/internal.js";
6
6
 
7
7
  describe("ops", () => {
8
+ test("ops.addition adds two numbers", async () => {
9
+ assert.strictEqual(ops.addition(2, 2), 4);
10
+ assert.strictEqual(ops.addition(2, true), 3);
11
+ });
12
+
13
+ test("ops.addition concatenates two strings", async () => {
14
+ assert.strictEqual(ops.addition("hello ", "everyone"), "hello everyone");
15
+ assert.strictEqual(
16
+ ops.addition("2001", ": A Space Odyssey"),
17
+ "2001: A Space Odyssey"
18
+ );
19
+ });
20
+
8
21
  test("ops.array creates an array", async () => {
9
22
  const code = createCode([ops.array, 1, 2, 3]);
10
23
  const result = await evaluate.call(null, code);
11
24
  assert.deepEqual(result, [1, 2, 3]);
12
25
  });
13
26
 
27
+ test("ops.bitwiseAnd", () => {
28
+ assert.strictEqual(ops.bitwiseAnd(5, 3), 1);
29
+ });
30
+
31
+ test("ops.bitwiseNot", () => {
32
+ assert.strictEqual(ops.bitwiseNot(5), -6);
33
+ assert.strictEqual(ops.bitwiseNot(-3), 2);
34
+ });
35
+
36
+ test("ops.bitwiseOr", () => {
37
+ assert.strictEqual(ops.bitwiseOr(5, 3), 7);
38
+ });
39
+
40
+ test("ops.bitwiseXor", () => {
41
+ assert.strictEqual(ops.bitwiseXor(5, 3), 6);
42
+ });
43
+
14
44
  test("ops.builtin gets a value from the top of the scope chain", async () => {
15
45
  const root = new ObjectTree({
16
46
  a: 1,
@@ -19,32 +49,80 @@ describe("ops", () => {
19
49
  tree.parent = root;
20
50
  const code = createCode([ops.builtin, "a"]);
21
51
  const result = await evaluate.call(tree, code);
22
- assert.equal(result, 1);
52
+ assert.strictEqual(result, 1);
23
53
  });
24
54
 
25
- test("ops.cache looks up a value in scope and memoizes it", async () => {
55
+ test("ops.comma returns the last value", async () => {
56
+ const code = createCode([ops.comma, 1, 2, 3]);
57
+ const result = await evaluate.call(null, code);
58
+ assert.strictEqual(result, 3);
59
+ });
60
+
61
+ test("ops.concat concatenates tree value text", async () => {
62
+ const scope = new ObjectTree({
63
+ name: "world",
64
+ });
65
+
66
+ const code = createCode([ops.concat, "Hello, ", [ops.scope, "name"], "."]);
67
+
68
+ const result = await evaluate.call(scope, code);
69
+ assert.strictEqual(result, "Hello, world.");
70
+ });
71
+
72
+ test("ops.conditional", async () => {
73
+ assert.strictEqual(await ops.conditional(true, trueFn, falseFn), true);
74
+ assert.strictEqual(await ops.conditional(true, falseFn, trueFn), false);
75
+ assert.strictEqual(await ops.conditional(false, trueFn, falseFn), false);
76
+ assert.strictEqual(await ops.conditional(false, falseFn, trueFn), true);
77
+
78
+ // Short-circuiting
79
+ assert.strictEqual(await ops.conditional(false, errorFn, trueFn), true);
80
+ });
81
+
82
+ test("ops.division divides two numbers", async () => {
83
+ assert.strictEqual(ops.division(12, 2), 6);
84
+ assert.strictEqual(ops.division(3, 2), 1.5);
85
+ assert.strictEqual(ops.division(6, "3"), 2);
86
+ assert.strictEqual(ops.division(2, 0), Infinity);
87
+ });
88
+
89
+ test("ops.equal", () => {
90
+ assert(ops.equal(1, 1));
91
+ assert(!ops.equal(1, 2));
92
+ assert(ops.equal("1", 1));
93
+ assert(ops.equal("1", "1"));
94
+ assert(ops.equal(null, undefined));
95
+ });
96
+
97
+ test("ops.exponentiation", () => {
98
+ assert.strictEqual(ops.exponentiation(2, 3), 8);
99
+ assert.strictEqual(ops.exponentiation(2, 0), 1);
100
+ });
101
+
102
+ test("ops.external looks up a value in scope and memoizes it", async () => {
26
103
  let count = 0;
27
104
  const tree = new ObjectTree({
28
105
  get count() {
29
106
  return ++count;
30
107
  },
31
108
  });
32
- const code = createCode([ops.cache, "count", {}]);
109
+ const code = createCode([ops.external, "count", {}]);
33
110
  const result = await evaluate.call(tree, code);
34
- assert.equal(result, 1);
111
+ assert.strictEqual(result, 1);
35
112
  const result2 = await evaluate.call(tree, code);
36
- assert.equal(result2, 1);
113
+ assert.strictEqual(result2, 1);
37
114
  });
38
115
 
39
- test("ops.concat concatenates tree value text", async () => {
40
- const scope = new ObjectTree({
41
- name: "world",
42
- });
43
-
44
- const code = createCode([ops.concat, "Hello, ", [ops.scope, "name"], "."]);
116
+ test("ops.greaterThan", () => {
117
+ assert(ops.greaterThan(5, 3));
118
+ assert(!ops.greaterThan(3, 3));
119
+ assert(ops.greaterThan("ab", "aa"));
120
+ });
45
121
 
46
- const result = await evaluate.call(scope, code);
47
- assert.equal(result, "Hello, world.");
122
+ test("ops.greaterThanOrEqual", () => {
123
+ assert(ops.greaterThanOrEqual(5, 3));
124
+ assert(ops.greaterThanOrEqual(3, 3));
125
+ assert(ops.greaterThanOrEqual("ab", "aa"));
48
126
  });
49
127
 
50
128
  test("ops.inherited searches inherited scope", async () => {
@@ -58,10 +136,17 @@ describe("ops", () => {
58
136
  child.parent = parent;
59
137
  const code = createCode([ops.inherited, "a"]);
60
138
  const result = await evaluate.call(child, code);
61
- assert.equal(result, 1);
139
+ assert.strictEqual(result, 1);
140
+ });
141
+
142
+ test("ops.lambda defines a function with no inputs", async () => {
143
+ const code = createCode([ops.lambda, [], [ops.literal, "result"]]);
144
+ const fn = await evaluate.call(null, code);
145
+ const result = await fn.call();
146
+ assert.strictEqual(result, "result");
62
147
  });
63
148
 
64
- test("ops.lambda defines a function", async () => {
149
+ test("ops.lambda defines a function with underscore input", async () => {
65
150
  const scope = new ObjectTree({
66
151
  message: "Hello",
67
152
  });
@@ -70,7 +155,7 @@ describe("ops", () => {
70
155
 
71
156
  const fn = await evaluate.call(scope, code);
72
157
  const result = await fn.call(scope);
73
- assert.equal(result, "Hello");
158
+ assert.strictEqual(result, "Hello");
74
159
  });
75
160
 
76
161
  test("ops.lambda adds input parameters to scope", async () => {
@@ -81,7 +166,83 @@ describe("ops", () => {
81
166
  ]);
82
167
  const fn = await evaluate.call(null, code);
83
168
  const result = await fn("x", "y");
84
- assert.equal(result, "yx");
169
+ assert.strictEqual(result, "yx");
170
+ });
171
+
172
+ test("ops.lessThan", () => {
173
+ assert(!ops.lessThan(5, 3));
174
+ assert(!ops.lessThan(3, 3));
175
+ assert(ops.lessThan("aa", "ab"));
176
+ });
177
+
178
+ test("ops.lessThanOrEqual", () => {
179
+ assert(!ops.lessThanOrEqual(5, 3));
180
+ assert(ops.lessThanOrEqual(3, 3));
181
+ assert(ops.lessThanOrEqual("aa", "ab"));
182
+ });
183
+
184
+ test("ops.logicalAnd", async () => {
185
+ assert.strictEqual(await ops.logicalAnd(true, trueFn), true);
186
+ assert.strictEqual(await ops.logicalAnd(true, falseFn), false);
187
+ assert.strictEqual(await ops.logicalAnd(false, trueFn), false);
188
+ assert.strictEqual(await ops.logicalAnd(false, falseFn), false);
189
+
190
+ assert.strictEqual(await ops.logicalAnd(true, "hi"), "hi");
191
+
192
+ // Short-circuiting
193
+ assert.strictEqual(await ops.logicalAnd(false, errorFn), false);
194
+ assert.strictEqual(await ops.logicalAnd(0, true), 0);
195
+ });
196
+
197
+ test("ops.logicalNot", async () => {
198
+ assert.strictEqual(await ops.logicalNot(true), false);
199
+ assert.strictEqual(await ops.logicalNot(false), true);
200
+ assert.strictEqual(await ops.logicalNot(0), true);
201
+ assert.strictEqual(await ops.logicalNot(1), false);
202
+ });
203
+
204
+ test("ops.logicalOr", async () => {
205
+ assert.strictEqual(await ops.logicalOr(true, trueFn), true);
206
+ assert.strictEqual(await ops.logicalOr(true, falseFn), true);
207
+ assert.strictEqual(await ops.logicalOr(false, trueFn), true);
208
+ assert.strictEqual(await ops.logicalOr(false, falseFn), false);
209
+
210
+ assert.strictEqual(await ops.logicalOr(false, "hi"), "hi");
211
+
212
+ // Short-circuiting
213
+ assert.strictEqual(await ops.logicalOr(true, errorFn), true);
214
+ });
215
+
216
+ test("ops.multiplication multiplies two numbers", async () => {
217
+ assert.strictEqual(ops.multiplication(3, 4), 12);
218
+ assert.strictEqual(ops.multiplication(-3, 4), -12);
219
+ assert.strictEqual(ops.multiplication("3", 2), 6);
220
+ assert.strictEqual(ops.multiplication("foo", 2), NaN);
221
+ });
222
+
223
+ test("ops.notEqual", () => {
224
+ assert(!ops.notEqual(1, 1));
225
+ assert(ops.notEqual(1, 2));
226
+ assert(!ops.notEqual("1", 1));
227
+ assert(!ops.notEqual("1", "1"));
228
+ assert(!ops.notEqual(null, undefined));
229
+ });
230
+
231
+ test("ops.notStrictEqual", () => {
232
+ assert(!ops.notStrictEqual(1, 1));
233
+ assert(ops.notStrictEqual(1, 2));
234
+ assert(ops.notStrictEqual("1", 1));
235
+ assert(!ops.notStrictEqual("1", "1"));
236
+ assert(ops.notStrictEqual(null, undefined));
237
+ });
238
+
239
+ test("ops.nullishCoalescing", async () => {
240
+ assert.strictEqual(await ops.nullishCoalescing(1, falseFn), 1);
241
+ assert.strictEqual(await ops.nullishCoalescing(null, trueFn), true);
242
+ assert.strictEqual(await ops.nullishCoalescing(undefined, trueFn), true);
243
+
244
+ // Short-circuiting
245
+ assert.strictEqual(await ops.nullishCoalescing(1, errorFn), 1);
85
246
  });
86
247
 
87
248
  test("ops.object instantiates an object", async () => {
@@ -96,8 +257,8 @@ describe("ops", () => {
96
257
  ]);
97
258
 
98
259
  const result = await evaluate.call(scope, code);
99
- assert.equal(result.hello, "HELLO");
100
- assert.equal(result.world, "WORLD");
260
+ assert.strictEqual(result.hello, "HELLO");
261
+ assert.strictEqual(result.world, "WORLD");
101
262
  });
102
263
 
103
264
  test("ops.object instantiates an array", async () => {
@@ -114,11 +275,60 @@ describe("ops", () => {
114
275
  assert.deepEqual(result, ["Hello", 1, "WORLD"]);
115
276
  });
116
277
 
278
+ test("ops.remainder calculates the remainder of two numbers", async () => {
279
+ assert.strictEqual(ops.remainder(13, 5), 3);
280
+ assert.strictEqual(ops.remainder(-13, 5), -3);
281
+ assert.strictEqual(ops.remainder(4, 2), 0);
282
+ assert.strictEqual(ops.remainder(-4, 2), -0);
283
+ });
284
+
285
+ test("ops.shiftLeft", () => {
286
+ assert.strictEqual(ops.shiftLeft(5, 2), 20);
287
+ });
288
+
289
+ test("ops.shiftRightSigned", () => {
290
+ assert.strictEqual(ops.shiftRightSigned(20, 2), 5);
291
+ assert.strictEqual(ops.shiftRightSigned(-20, 2), -5);
292
+ });
293
+
294
+ test("ops.shiftRightUnsigned", () => {
295
+ assert.strictEqual(ops.shiftRightUnsigned(20, 2), 5);
296
+ assert.strictEqual(ops.shiftRightUnsigned(-5, 2), 1073741822);
297
+ });
298
+
299
+ test("ops.strictEqual", () => {
300
+ assert(ops.strictEqual(1, 1));
301
+ assert(!ops.strictEqual(1, 2));
302
+ assert(!ops.strictEqual("1", 1));
303
+ assert(ops.strictEqual("1", "1"));
304
+ assert(!ops.strictEqual(null, undefined));
305
+ assert(ops.strictEqual(null, null));
306
+ assert(ops.strictEqual(undefined, undefined));
307
+ });
308
+
309
+ test("ops.subtraction subtracts two numbers", async () => {
310
+ assert.strictEqual(ops.subtraction(5, 3), 2);
311
+ assert.strictEqual(ops.subtraction(3.5, 5), -1.5);
312
+ assert.strictEqual(ops.subtraction(5, "hello"), NaN);
313
+ assert.strictEqual(ops.subtraction(5, true), 4);
314
+ });
315
+
316
+ test("ops.unaryMinus", () => {
317
+ assert.strictEqual(ops.unaryMinus(4), -4);
318
+ assert.strictEqual(ops.unaryMinus(-4), 4);
319
+ });
320
+
321
+ test("ops.unaryPlus", () => {
322
+ assert.strictEqual(ops.unaryPlus(1), 1);
323
+ assert.strictEqual(ops.unaryPlus(-1), -1);
324
+ assert.strictEqual(ops.unaryPlus(""), 0);
325
+ });
326
+
117
327
  test("ops.unpack unpacks a value", async () => {
118
328
  const fixture = new String("packed");
119
329
  /** @type {any} */ (fixture).unpack = async () => "unpacked";
120
330
  const result = await ops.unpack.call(null, fixture);
121
- assert.equal(result, "unpacked");
331
+ assert.strictEqual(result, "unpacked");
122
332
  });
123
333
  });
124
334
 
@@ -134,3 +344,15 @@ function createCode(array) {
134
344
  };
135
345
  return code;
136
346
  }
347
+
348
+ function errorFn() {
349
+ throw new Error("This should not be called");
350
+ }
351
+
352
+ function falseFn() {
353
+ return false;
354
+ }
355
+
356
+ function trueFn() {
357
+ return true;
358
+ }