@weborigami/language 0.1.0 → 0.2.0
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/index.ts +1 -0
- package/package.json +6 -4
- package/src/compiler/compile.js +33 -15
- package/src/compiler/origami.pegjs +222 -193
- package/src/compiler/parse.js +1380 -1040
- package/src/compiler/parserHelpers.js +171 -45
- package/src/runtime/ops.js +137 -55
- package/test/cases/ReadMe.md +1 -0
- package/test/cases/conditionalExpression.yaml +101 -0
- package/test/cases/logicalAndExpression.yaml +146 -0
- package/test/cases/logicalOrExpression.yaml +145 -0
- package/test/cases/nullishCoalescingExpression.yaml +105 -0
- package/test/compiler/compile.test.js +3 -3
- package/test/compiler/parse.test.js +447 -363
- package/test/generated/conditionalExpression.test.js +58 -0
- package/test/generated/logicalAndExpression.test.js +80 -0
- package/test/generated/logicalOrExpression.test.js +78 -0
- package/test/generated/nullishCoalescingExpression.test.js +64 -0
- package/test/generator/generateTests.js +80 -0
- package/test/generator/oriEval.js +15 -0
- package/test/runtime/ops.test.js +127 -23
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Logical AND expression tests
|
|
2
|
+
|
|
3
|
+
- source: "true && true"
|
|
4
|
+
expected: true
|
|
5
|
+
description: "Both operands are true"
|
|
6
|
+
|
|
7
|
+
- source: "true && false"
|
|
8
|
+
expected: false
|
|
9
|
+
description: "First operand is true, second is false"
|
|
10
|
+
|
|
11
|
+
- source: "false && true"
|
|
12
|
+
expected: false
|
|
13
|
+
description: "First operand is false, second is true"
|
|
14
|
+
|
|
15
|
+
- source: "false && false"
|
|
16
|
+
expected: false
|
|
17
|
+
description: "Both operands are false"
|
|
18
|
+
|
|
19
|
+
- source: "false && (1 / 0)"
|
|
20
|
+
expected: false
|
|
21
|
+
description: "Short-circuit evaluation: first operand false, second not evaluated"
|
|
22
|
+
|
|
23
|
+
- source: "true && 42"
|
|
24
|
+
expected: 42
|
|
25
|
+
description: "Short-circuit evaluation: first operand true, evaluates second"
|
|
26
|
+
|
|
27
|
+
- source: "0 && true"
|
|
28
|
+
expected: 0
|
|
29
|
+
description: "Short-circuiting with falsy value (0)"
|
|
30
|
+
|
|
31
|
+
- source: "true && 'string'"
|
|
32
|
+
expected: "string"
|
|
33
|
+
description: "Truthy value with string"
|
|
34
|
+
|
|
35
|
+
- source: "false && 'string'"
|
|
36
|
+
expected: false
|
|
37
|
+
description: "Falsy value with string"
|
|
38
|
+
|
|
39
|
+
- source: "1 && 0"
|
|
40
|
+
expected: 0
|
|
41
|
+
description: "Truthy numeric value with falsy numeric value"
|
|
42
|
+
|
|
43
|
+
- source: "0 && 1"
|
|
44
|
+
expected: 0
|
|
45
|
+
description: "Falsy numeric value with truthy numeric value"
|
|
46
|
+
|
|
47
|
+
- source: "'' && 'non-empty string'"
|
|
48
|
+
expected: ""
|
|
49
|
+
description: "Falsy string value with truthy string"
|
|
50
|
+
|
|
51
|
+
- source: "'non-empty string' && ''"
|
|
52
|
+
expected: ""
|
|
53
|
+
description: "Truthy string with falsy string"
|
|
54
|
+
|
|
55
|
+
- source: "{} && true"
|
|
56
|
+
expected: true
|
|
57
|
+
description: "Empty object as first operand"
|
|
58
|
+
|
|
59
|
+
- source: "true && {}"
|
|
60
|
+
expected: {}
|
|
61
|
+
description: "Empty object as second operand"
|
|
62
|
+
|
|
63
|
+
- source: "[] && true"
|
|
64
|
+
expected: true
|
|
65
|
+
description: "Array as first operand"
|
|
66
|
+
|
|
67
|
+
- source: "true && []"
|
|
68
|
+
expected: []
|
|
69
|
+
description: "Array as second operand"
|
|
70
|
+
|
|
71
|
+
- source: "null && true"
|
|
72
|
+
expected: null
|
|
73
|
+
description: "Null as first operand"
|
|
74
|
+
|
|
75
|
+
- source: "true && null"
|
|
76
|
+
expected: null
|
|
77
|
+
description: "Null as second operand"
|
|
78
|
+
|
|
79
|
+
- source: "undefined && true"
|
|
80
|
+
expected: __undefined__
|
|
81
|
+
description: "Undefined as first operand"
|
|
82
|
+
|
|
83
|
+
- source: "true && undefined"
|
|
84
|
+
expected: __undefined__
|
|
85
|
+
description: "Undefined as second operand"
|
|
86
|
+
|
|
87
|
+
- source: "NaN && true"
|
|
88
|
+
expected: __NaN__
|
|
89
|
+
description: "NaN as first operand"
|
|
90
|
+
|
|
91
|
+
- source: "true && NaN"
|
|
92
|
+
expected: __NaN__
|
|
93
|
+
description: "NaN as second operand"
|
|
94
|
+
|
|
95
|
+
- source: "(true && false) && true"
|
|
96
|
+
expected: false
|
|
97
|
+
description: "Nested logical ANDs with a false in the middle"
|
|
98
|
+
|
|
99
|
+
- source: "(true && true) && true"
|
|
100
|
+
expected: true
|
|
101
|
+
description: "Nested logical ANDs with all true"
|
|
102
|
+
|
|
103
|
+
- source: "true && (true && false)"
|
|
104
|
+
expected: false
|
|
105
|
+
description: "Nested logical ANDs with false in inner"
|
|
106
|
+
|
|
107
|
+
- source: "(true && (false && true))"
|
|
108
|
+
expected: false
|
|
109
|
+
description: "Complex nesting with false at inner-most"
|
|
110
|
+
|
|
111
|
+
# TODO: Uncomment when we can do math
|
|
112
|
+
# - source: "true && (1 + 1 === 2)"
|
|
113
|
+
# expected: true
|
|
114
|
+
# description: "Combines logical AND with equality comparison"
|
|
115
|
+
|
|
116
|
+
# - source: "false && (5 > 2)"
|
|
117
|
+
# expected: false
|
|
118
|
+
# description: "Logical AND with greater-than comparison"
|
|
119
|
+
|
|
120
|
+
- source: "true && (3 || 0)"
|
|
121
|
+
expected: 3
|
|
122
|
+
description: "Logical AND with logical OR"
|
|
123
|
+
|
|
124
|
+
- source: "true && (0 || 3)"
|
|
125
|
+
expected: 3
|
|
126
|
+
description: "Logical AND with logical OR and falsy values"
|
|
127
|
+
|
|
128
|
+
- source: "'' && false"
|
|
129
|
+
expected: ""
|
|
130
|
+
description: "Falsy string and false"
|
|
131
|
+
|
|
132
|
+
- source: "false && ''"
|
|
133
|
+
expected: false
|
|
134
|
+
description: "False and falsy string"
|
|
135
|
+
|
|
136
|
+
- source: "undefined && null"
|
|
137
|
+
expected: __undefined__
|
|
138
|
+
description: "Undefined and null"
|
|
139
|
+
|
|
140
|
+
- source: "null && undefined"
|
|
141
|
+
expected: null
|
|
142
|
+
description: "Null and undefined"
|
|
143
|
+
|
|
144
|
+
- source: "(false && true) && undefined"
|
|
145
|
+
expected: false
|
|
146
|
+
description: "Short-circuiting nested AND with undefined"
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Logical OR expression tests
|
|
2
|
+
|
|
3
|
+
- source: "true || true"
|
|
4
|
+
expected: true
|
|
5
|
+
description: "Both operands are true"
|
|
6
|
+
|
|
7
|
+
- source: "true || false"
|
|
8
|
+
expected: true
|
|
9
|
+
description: "First operand is true, second is false"
|
|
10
|
+
|
|
11
|
+
- source: "false || true"
|
|
12
|
+
expected: true
|
|
13
|
+
description: "First operand is false, second is true"
|
|
14
|
+
|
|
15
|
+
- source: "false || false"
|
|
16
|
+
expected: false
|
|
17
|
+
description: "Both operands are false"
|
|
18
|
+
|
|
19
|
+
# - source: "true || (1 / 0)"
|
|
20
|
+
# expected: true
|
|
21
|
+
# description: "Short-circuit evaluation: first operand true, second not evaluated"
|
|
22
|
+
|
|
23
|
+
- source: "false || 42"
|
|
24
|
+
expected: 42
|
|
25
|
+
description: "Short-circuit evaluation: first operand false, evaluates second"
|
|
26
|
+
|
|
27
|
+
- source: "0 || true"
|
|
28
|
+
expected: true
|
|
29
|
+
description: "Falsy value (0) with truthy second operand"
|
|
30
|
+
|
|
31
|
+
- source: "true || 'string'"
|
|
32
|
+
expected: true
|
|
33
|
+
description: "Truthy first operand, string second operand not evaluated"
|
|
34
|
+
|
|
35
|
+
- source: "false || 'string'"
|
|
36
|
+
expected: "string"
|
|
37
|
+
description: "Falsy first operand, evaluates string second operand"
|
|
38
|
+
|
|
39
|
+
- source: "1 || 0"
|
|
40
|
+
expected: 1
|
|
41
|
+
description: "Truthy numeric value with falsy numeric value"
|
|
42
|
+
|
|
43
|
+
- source: "0 || 1"
|
|
44
|
+
expected: 1
|
|
45
|
+
description: "Falsy numeric value with truthy numeric value"
|
|
46
|
+
|
|
47
|
+
- source: "'' || 'non-empty string'"
|
|
48
|
+
expected: "non-empty string"
|
|
49
|
+
description: "Falsy string value with truthy string"
|
|
50
|
+
|
|
51
|
+
- source: "'non-empty string' || ''"
|
|
52
|
+
expected: "non-empty string"
|
|
53
|
+
description: "Truthy string with falsy string"
|
|
54
|
+
|
|
55
|
+
- source: "{} || true"
|
|
56
|
+
expected: {}
|
|
57
|
+
description: "Empty object as first operand"
|
|
58
|
+
|
|
59
|
+
- source: "true || {}"
|
|
60
|
+
expected: true
|
|
61
|
+
description: "True as first operand, object not evaluated"
|
|
62
|
+
|
|
63
|
+
- source: "[] || true"
|
|
64
|
+
expected: []
|
|
65
|
+
description: "Array as first operand"
|
|
66
|
+
|
|
67
|
+
- source: "true || []"
|
|
68
|
+
expected: true
|
|
69
|
+
description: "True as first operand, array not evaluated"
|
|
70
|
+
|
|
71
|
+
- source: "null || true"
|
|
72
|
+
expected: true
|
|
73
|
+
description: "Null as first operand"
|
|
74
|
+
|
|
75
|
+
- source: "true || null"
|
|
76
|
+
expected: true
|
|
77
|
+
description: "True as first operand, null not evaluated"
|
|
78
|
+
|
|
79
|
+
- source: "undefined || true"
|
|
80
|
+
expected: true
|
|
81
|
+
description: "Undefined as first operand"
|
|
82
|
+
|
|
83
|
+
- source: "true || undefined"
|
|
84
|
+
expected: true
|
|
85
|
+
description: "True as first operand, undefined not evaluated"
|
|
86
|
+
|
|
87
|
+
- source: "NaN || true"
|
|
88
|
+
expected: true
|
|
89
|
+
description: "NaN as first operand"
|
|
90
|
+
|
|
91
|
+
- source: "true || NaN"
|
|
92
|
+
expected: true
|
|
93
|
+
description: "True as first operand, NaN not evaluated"
|
|
94
|
+
|
|
95
|
+
- source: "(false || true) || false"
|
|
96
|
+
expected: true
|
|
97
|
+
description: "Nested logical ORs with a true in the middle"
|
|
98
|
+
|
|
99
|
+
- source: "(false || false) || true"
|
|
100
|
+
expected: true
|
|
101
|
+
description: "Nested logical ORs with a true at the end"
|
|
102
|
+
|
|
103
|
+
- source: "false || (false || true)"
|
|
104
|
+
expected: true
|
|
105
|
+
description: "Nested logical ORs with true in inner"
|
|
106
|
+
|
|
107
|
+
- source: "(false || (true || false))"
|
|
108
|
+
expected: true
|
|
109
|
+
description: "Complex nesting with true at inner-most"
|
|
110
|
+
|
|
111
|
+
# - source: "true || (1 + 1 === 2)"
|
|
112
|
+
# expected: true
|
|
113
|
+
# description: "Combines logical OR with equality comparison"
|
|
114
|
+
|
|
115
|
+
# - source: "false || (5 > 2)"
|
|
116
|
+
# expected: true
|
|
117
|
+
# description: "Logical OR with greater-than comparison"
|
|
118
|
+
|
|
119
|
+
- source: "false || (3 && 0)"
|
|
120
|
+
expected: 0
|
|
121
|
+
description: "Logical OR with logical AND and falsy result"
|
|
122
|
+
|
|
123
|
+
- source: "false || (0 && 3)"
|
|
124
|
+
expected: 0
|
|
125
|
+
description: "Logical OR with logical AND and falsy first operand"
|
|
126
|
+
|
|
127
|
+
- source: "'' || false"
|
|
128
|
+
expected: false
|
|
129
|
+
description: "Falsy string and false"
|
|
130
|
+
|
|
131
|
+
- source: "false || ''"
|
|
132
|
+
expected: ""
|
|
133
|
+
description: "False and falsy string"
|
|
134
|
+
|
|
135
|
+
- source: "undefined || null"
|
|
136
|
+
expected: __null__
|
|
137
|
+
description: "Undefined and null"
|
|
138
|
+
|
|
139
|
+
- source: "null || undefined"
|
|
140
|
+
expected: __undefined__
|
|
141
|
+
description: "Null and undefined"
|
|
142
|
+
|
|
143
|
+
- source: "(true || false) || undefined"
|
|
144
|
+
expected: true
|
|
145
|
+
description: "Short-circuiting nested OR with undefined"
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# Nullish coalescing expression tests
|
|
2
|
+
|
|
3
|
+
- source: "null ?? 42"
|
|
4
|
+
expected: 42
|
|
5
|
+
description: "Left operand is null, returns right operand"
|
|
6
|
+
|
|
7
|
+
- source: "undefined ?? 42"
|
|
8
|
+
expected: 42
|
|
9
|
+
description: "Left operand is undefined, returns right operand"
|
|
10
|
+
|
|
11
|
+
- source: "0 ?? 42"
|
|
12
|
+
expected: 0
|
|
13
|
+
description: "Left operand is 0 (falsy but not nullish), returns left operand"
|
|
14
|
+
|
|
15
|
+
- source: "'' ?? 'default'"
|
|
16
|
+
expected: ""
|
|
17
|
+
description: "Left operand is an empty string (falsy but not nullish), returns left operand"
|
|
18
|
+
|
|
19
|
+
- source: "false ?? true"
|
|
20
|
+
expected: false
|
|
21
|
+
description: "Left operand is false (falsy but not nullish), returns left operand"
|
|
22
|
+
|
|
23
|
+
- source: "42 ?? 0"
|
|
24
|
+
expected: 42
|
|
25
|
+
description: "Left operand is a non-nullish truthy value, returns left operand"
|
|
26
|
+
|
|
27
|
+
- source: "null ?? undefined"
|
|
28
|
+
expected: __undefined__
|
|
29
|
+
description: "Left operand is null, returns right operand which is undefined"
|
|
30
|
+
|
|
31
|
+
- source: "undefined ?? null"
|
|
32
|
+
expected: __null__
|
|
33
|
+
description: "Left operand is undefined, returns right operand which is null"
|
|
34
|
+
|
|
35
|
+
- source: "NaN ?? 42"
|
|
36
|
+
expected: __NaN__
|
|
37
|
+
description: "Left operand is NaN (not nullish), returns left operand"
|
|
38
|
+
|
|
39
|
+
- source: "[] ?? 'default'"
|
|
40
|
+
expected: []
|
|
41
|
+
description: "Left operand is an empty array (not nullish), returns left operand"
|
|
42
|
+
|
|
43
|
+
- source: "{} ?? 'default'"
|
|
44
|
+
expected: {}
|
|
45
|
+
description: "Left operand is an empty object (not nullish), returns left operand"
|
|
46
|
+
|
|
47
|
+
- source: "(null ?? 42) ?? 50"
|
|
48
|
+
expected: 42
|
|
49
|
+
description: "Nested nullish coalescing, first nullish operand replaced, second ignored"
|
|
50
|
+
|
|
51
|
+
- source: "(undefined ?? null) ?? 'fallback'"
|
|
52
|
+
expected: fallback
|
|
53
|
+
description: "Nested nullish coalescing"
|
|
54
|
+
|
|
55
|
+
- source: "(0 ?? null) ?? 'fallback'"
|
|
56
|
+
expected: 0
|
|
57
|
+
description: "Nested nullish coalescing with falsy but non-nullish value"
|
|
58
|
+
|
|
59
|
+
- source: "null ?? (undefined ?? 42)"
|
|
60
|
+
expected: 42
|
|
61
|
+
description: "Nullish coalescing in the right operand"
|
|
62
|
+
|
|
63
|
+
- source: "null ?? null ?? null ?? 'fallback'"
|
|
64
|
+
expected: "fallback"
|
|
65
|
+
description: "Chained nullish coalescing, resolves to the last non-nullish value"
|
|
66
|
+
|
|
67
|
+
- source: "null ?? (false ?? 'default')"
|
|
68
|
+
expected: false
|
|
69
|
+
description: "Right operand evaluates to non-nullish falsy value"
|
|
70
|
+
|
|
71
|
+
- source: "null ?? (true ?? 'default')"
|
|
72
|
+
expected: true
|
|
73
|
+
description: "Right operand evaluates to truthy value"
|
|
74
|
+
|
|
75
|
+
- source: "42 ?? (null ?? 0)"
|
|
76
|
+
expected: 42
|
|
77
|
+
description: "Left operand is not nullish, ignores right operand"
|
|
78
|
+
|
|
79
|
+
- source: "undefined ?? null ?? 'value'"
|
|
80
|
+
expected: "value"
|
|
81
|
+
description: "Chained nullish coalescing with undefined and null"
|
|
82
|
+
|
|
83
|
+
- source: "(NaN ?? null) ?? 42"
|
|
84
|
+
expected: __NaN__
|
|
85
|
+
description: "Left operand is NaN, not nullish, returns NaN"
|
|
86
|
+
|
|
87
|
+
- source: "(undefined ?? NaN) ?? 42"
|
|
88
|
+
expected: __NaN__
|
|
89
|
+
description: "Right operand resolves to NaN"
|
|
90
|
+
|
|
91
|
+
- source: "null ?? 'default' ?? 42"
|
|
92
|
+
expected: "default"
|
|
93
|
+
description: "Chained nullish coalescing, resolves to first non-nullish value"
|
|
94
|
+
|
|
95
|
+
- source: "'' ?? 'default' ?? 42"
|
|
96
|
+
expected: ""
|
|
97
|
+
description: "Falsy but non-nullish value, returns left operand"
|
|
98
|
+
|
|
99
|
+
- source: "null ?? undefined ?? NaN"
|
|
100
|
+
expected: __NaN__
|
|
101
|
+
description: "Chained nullish coalescing, resolves to NaN as the first non-nullish value"
|
|
102
|
+
|
|
103
|
+
- source: "(null ?? null) ?? undefined"
|
|
104
|
+
expected: __undefined__
|
|
105
|
+
description: "Nested nullish coalescing resolves to undefined"
|
|
@@ -10,7 +10,7 @@ const shared = new ObjectTree({
|
|
|
10
10
|
name: "Alice",
|
|
11
11
|
});
|
|
12
12
|
|
|
13
|
-
describe("compile", () => {
|
|
13
|
+
describe.only("compile", () => {
|
|
14
14
|
test("array", async () => {
|
|
15
15
|
await assertCompile("[]", []);
|
|
16
16
|
await assertCompile("[ 1, 2, 3, ]", [1, 2, 3]);
|
|
@@ -85,7 +85,7 @@ describe("compile", () => {
|
|
|
85
85
|
assert.equal(bob, "Hello, Bob!");
|
|
86
86
|
});
|
|
87
87
|
|
|
88
|
-
test("converts non-local ops.scope calls to ops.
|
|
88
|
+
test.only("converts non-local ops.scope calls to ops.external", async () => {
|
|
89
89
|
const expression = `
|
|
90
90
|
(name) => {
|
|
91
91
|
a: 1
|
|
@@ -103,7 +103,7 @@ describe("compile", () => {
|
|
|
103
103
|
ops.object,
|
|
104
104
|
["a", [ops.literal, 1]],
|
|
105
105
|
["b", [ops.scope, "a"]],
|
|
106
|
-
["c", [ops.
|
|
106
|
+
["c", [ops.external, "nonLocal", {}]],
|
|
107
107
|
["d", [ops.scope, "name"]],
|
|
108
108
|
],
|
|
109
109
|
]);
|