yukigo 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.
Files changed (144) hide show
  1. package/.mocharc.json +3 -3
  2. package/CHANGELOG.md +26 -0
  3. package/README.md +193 -199
  4. package/dist/analyzer/GraphBuilder.d.ts +29 -0
  5. package/dist/analyzer/GraphBuilder.js +99 -0
  6. package/dist/analyzer/index.d.ts +11 -23
  7. package/dist/analyzer/index.js +100 -58
  8. package/dist/analyzer/inspections/functional/functional.d.ts +44 -0
  9. package/dist/analyzer/inspections/functional/functional.js +149 -0
  10. package/dist/analyzer/inspections/functional/smells.d.ts +16 -0
  11. package/dist/analyzer/inspections/functional/smells.js +98 -0
  12. package/dist/analyzer/inspections/{generic.d.ts → generic/generic.d.ts} +70 -43
  13. package/dist/analyzer/inspections/generic/generic.js +604 -0
  14. package/dist/analyzer/inspections/generic/smells.d.ts +61 -0
  15. package/dist/analyzer/inspections/generic/smells.js +349 -0
  16. package/dist/analyzer/inspections/imperative/imperative.d.ts +35 -0
  17. package/dist/analyzer/inspections/imperative/imperative.js +109 -0
  18. package/dist/analyzer/inspections/imperative/smells.d.ts +16 -0
  19. package/dist/analyzer/inspections/imperative/smells.js +58 -0
  20. package/dist/analyzer/inspections/logic/logic.d.ts +32 -0
  21. package/dist/analyzer/inspections/logic/logic.js +96 -0
  22. package/dist/analyzer/inspections/logic/smells.d.ts +15 -0
  23. package/dist/analyzer/inspections/logic/smells.js +60 -0
  24. package/dist/analyzer/inspections/object/object.d.ts +88 -0
  25. package/dist/analyzer/inspections/object/object.js +319 -0
  26. package/dist/analyzer/inspections/object/smells.d.ts +30 -0
  27. package/dist/analyzer/inspections/object/smells.js +135 -0
  28. package/dist/analyzer/utils.d.ts +26 -4
  29. package/dist/analyzer/utils.js +71 -13
  30. package/dist/index.d.ts +1 -0
  31. package/dist/index.js +1 -0
  32. package/dist/interpreter/components/EnvBuilder.d.ts +9 -5
  33. package/dist/interpreter/components/EnvBuilder.js +100 -30
  34. package/dist/interpreter/components/Operations.d.ts +4 -4
  35. package/dist/interpreter/components/Operations.js +17 -2
  36. package/dist/interpreter/components/PatternMatcher.d.ts +47 -17
  37. package/dist/interpreter/components/PatternMatcher.js +264 -119
  38. package/dist/interpreter/components/RuntimeContext.d.ts +35 -0
  39. package/dist/interpreter/components/RuntimeContext.js +93 -0
  40. package/dist/interpreter/components/TestRunner.d.ts +18 -0
  41. package/dist/interpreter/components/TestRunner.js +103 -0
  42. package/dist/interpreter/components/Visitor.d.ts +63 -57
  43. package/dist/interpreter/components/Visitor.js +508 -173
  44. package/dist/interpreter/components/logic/LogicEngine.d.ts +29 -0
  45. package/dist/interpreter/components/logic/LogicEngine.js +259 -0
  46. package/dist/interpreter/components/logic/LogicResolver.d.ts +53 -0
  47. package/dist/interpreter/components/logic/LogicResolver.js +471 -0
  48. package/dist/interpreter/components/logic/LogicTranslator.d.ts +14 -0
  49. package/dist/interpreter/components/logic/LogicTranslator.js +99 -0
  50. package/dist/interpreter/components/runtimes/FunctionRuntime.d.ts +12 -0
  51. package/dist/interpreter/components/runtimes/FunctionRuntime.js +147 -0
  52. package/dist/interpreter/components/runtimes/LazyRuntime.d.ts +19 -0
  53. package/dist/interpreter/components/runtimes/LazyRuntime.js +269 -0
  54. package/dist/interpreter/components/runtimes/ObjectRuntime.d.ts +35 -0
  55. package/dist/interpreter/components/runtimes/ObjectRuntime.js +126 -0
  56. package/dist/interpreter/entities.d.ts +105 -0
  57. package/dist/interpreter/entities.js +96 -0
  58. package/dist/interpreter/errors.d.ts +1 -1
  59. package/dist/interpreter/index.d.ts +4 -12
  60. package/dist/interpreter/index.js +10 -13
  61. package/dist/interpreter/trampoline.d.ts +17 -0
  62. package/dist/interpreter/trampoline.js +38 -0
  63. package/dist/interpreter/utils.d.ts +4 -7
  64. package/dist/interpreter/utils.js +25 -17
  65. package/dist/tester/index.d.ts +25 -0
  66. package/dist/tester/index.js +108 -0
  67. package/dist/utils/helpers.d.ts +0 -4
  68. package/dist/utils/helpers.js +20 -24
  69. package/package.json +2 -2
  70. package/src/analyzer/GraphBuilder.ts +142 -0
  71. package/src/analyzer/index.ts +185 -132
  72. package/src/analyzer/inspections/functional/functional.ts +121 -0
  73. package/src/analyzer/inspections/functional/smells.ts +102 -0
  74. package/src/analyzer/inspections/{generic.ts → generic/generic.ts} +581 -499
  75. package/src/analyzer/inspections/generic/smells.ts +365 -0
  76. package/src/analyzer/inspections/imperative/imperative.ts +101 -0
  77. package/src/analyzer/inspections/imperative/smells.ts +54 -0
  78. package/src/analyzer/inspections/logic/logic.ts +90 -0
  79. package/src/analyzer/inspections/logic/smells.ts +54 -0
  80. package/src/analyzer/inspections/{object.ts → object/object.ts} +264 -282
  81. package/src/analyzer/inspections/object/smells.ts +144 -0
  82. package/src/analyzer/utils.ts +109 -26
  83. package/src/index.ts +3 -2
  84. package/src/interpreter/components/EnvBuilder.ts +202 -97
  85. package/src/interpreter/components/Operations.ts +99 -81
  86. package/src/interpreter/components/PatternMatcher.ts +475 -254
  87. package/src/interpreter/components/RuntimeContext.ts +119 -0
  88. package/src/interpreter/components/TestRunner.ts +151 -0
  89. package/src/interpreter/components/Visitor.ts +1065 -493
  90. package/src/interpreter/components/logic/LogicEngine.ts +519 -0
  91. package/src/interpreter/components/logic/LogicResolver.ts +858 -0
  92. package/src/interpreter/components/logic/LogicTranslator.ts +149 -0
  93. package/src/interpreter/components/runtimes/FunctionRuntime.ts +227 -0
  94. package/src/interpreter/components/runtimes/LazyRuntime.ts +334 -0
  95. package/src/interpreter/components/runtimes/ObjectRuntime.ts +224 -0
  96. package/src/interpreter/errors.ts +47 -47
  97. package/src/interpreter/index.ts +52 -59
  98. package/src/interpreter/trampoline.ts +71 -0
  99. package/src/interpreter/utils.ts +84 -79
  100. package/src/tester/index.ts +128 -0
  101. package/src/utils/helpers.ts +67 -73
  102. package/tests/analyzer/functional.spec.ts +207 -221
  103. package/tests/analyzer/generic.spec.ts +178 -100
  104. package/tests/analyzer/helpers.spec.ts +83 -83
  105. package/tests/analyzer/logic.spec.ts +237 -292
  106. package/tests/analyzer/oop.spec.ts +323 -338
  107. package/tests/analyzer/transitive.spec.ts +166 -0
  108. package/tests/interpreter/EnvBuilder.spec.ts +183 -178
  109. package/tests/interpreter/FunctionRuntime.spec.ts +223 -234
  110. package/tests/interpreter/LazyRuntime.spec.ts +225 -190
  111. package/tests/interpreter/LogicEngine.spec.ts +327 -194
  112. package/tests/interpreter/LogicSubstitution.spec.ts +80 -0
  113. package/tests/interpreter/ObjectRuntime.spec.ts +606 -0
  114. package/tests/interpreter/Operations.spec.ts +220 -220
  115. package/tests/interpreter/PatternSystem.spec.ts +213 -189
  116. package/tests/interpreter/Tests.spec.ts +122 -0
  117. package/tests/interpreter/interpreter.spec.ts +991 -937
  118. package/tests/tester/Tester.spec.ts +153 -0
  119. package/tsconfig.build.json +15 -7
  120. package/tsconfig.json +25 -17
  121. package/dist/analyzer/inspections/functional.d.ts +0 -46
  122. package/dist/analyzer/inspections/functional.js +0 -123
  123. package/dist/analyzer/inspections/generic.js +0 -427
  124. package/dist/analyzer/inspections/imperative.d.ts +0 -37
  125. package/dist/analyzer/inspections/imperative.js +0 -105
  126. package/dist/analyzer/inspections/logic.d.ts +0 -49
  127. package/dist/analyzer/inspections/logic.js +0 -140
  128. package/dist/analyzer/inspections/object.d.ts +0 -83
  129. package/dist/analyzer/inspections/object.js +0 -235
  130. package/dist/interpreter/components/FunctionRuntime.d.ts +0 -8
  131. package/dist/interpreter/components/FunctionRuntime.js +0 -52
  132. package/dist/interpreter/components/LazyRuntime.d.ts +0 -7
  133. package/dist/interpreter/components/LazyRuntime.js +0 -75
  134. package/dist/interpreter/components/LogicEngine.d.ts +0 -21
  135. package/dist/interpreter/components/LogicEngine.js +0 -152
  136. package/dist/interpreter/components/LogicResolver.d.ts +0 -11
  137. package/dist/interpreter/components/LogicResolver.js +0 -87
  138. package/src/analyzer/inspections/functional.ts +0 -159
  139. package/src/analyzer/inspections/imperative.ts +0 -129
  140. package/src/analyzer/inspections/logic.ts +0 -166
  141. package/src/interpreter/components/FunctionRuntime.ts +0 -79
  142. package/src/interpreter/components/LazyRuntime.ts +0 -97
  143. package/src/interpreter/components/LogicEngine.ts +0 -227
  144. package/src/interpreter/components/LogicResolver.ts +0 -130
@@ -1,190 +1,225 @@
1
- import { expect } from "chai";
2
- import { LazyRuntime } from "../../src/interpreter/components/LazyRuntime.js";
3
- import {
4
- RangeExpression,
5
- ConsExpression,
6
- LazyList,
7
- NumberPrimitive,
8
- } from "yukigo-ast";
9
- import { createStream } from "../../src/interpreter/utils.js";
10
-
11
- class MockEvaluator {
12
- evaluate(node: any): any {
13
- if (node && typeof node === "object" && "value" in node) {
14
- return node.value;
15
- }
16
- return node;
17
- }
18
- }
19
-
20
- const num = (value: number) => new NumberPrimitive(value);
21
-
22
- const range = (start: number, end?: number, step?: number): RangeExpression =>
23
- new RangeExpression(
24
- num(start),
25
- end ? num(end) : undefined,
26
- step ? num(step) : undefined
27
- );
28
-
29
- // Helper para crear nodos Cons
30
- const cons = (headVal: any, tailVal: any): ConsExpression =>
31
- new ConsExpression(headVal, tailVal);
32
-
33
- describe("LazyRuntime", () => {
34
- let evaluator: any;
35
-
36
- beforeEach(() => {
37
- evaluator = new MockEvaluator();
38
- });
39
-
40
- describe("realizeList", () => {
41
- it("should return the array as-is if input is already an array", () => {
42
- const input = [1, 2, 3];
43
- const result = LazyRuntime.realizeList(input);
44
- expect(result).to.equal(input);
45
- expect(result).to.deep.equal([1, 2, 3]);
46
- });
47
-
48
- it("should consume a LazyList into an array", () => {
49
- const lazyList: LazyList = createStream(function* () {
50
- yield 10;
51
- yield 20;
52
- });
53
-
54
- const result = LazyRuntime.realizeList(lazyList);
55
- expect(result).to.deep.equal([10, 20]);
56
- });
57
-
58
- it("should throw if value is not a list or lazy list", () => {
59
- expect(() => LazyRuntime.realizeList(123 as any)).to.throw(
60
- /Expected List or LazyList/
61
- );
62
- });
63
- });
64
-
65
- describe("evaluateRange", () => {
66
- describe("Finite Ranges", () => {
67
- it("should create a simple range [1..5]", () => {
68
- const node = range(1, 5);
69
- const result = LazyRuntime.evaluateRange(node, evaluator, {
70
- lazyLoading: false,
71
- });
72
- expect(result).to.deep.equal([1, 2, 3, 4, 5]);
73
- });
74
-
75
- it("should handle custom steps [0, 2 .. 10]", () => {
76
- const node = range(0, 10, 2);
77
- const result = LazyRuntime.evaluateRange(node, evaluator, {
78
- lazyLoading: false,
79
- });
80
- expect(result).to.deep.equal([0, 2, 4, 6, 8, 10]);
81
- });
82
-
83
- it("should handle negative steps [5, 4 .. 1]", () => {
84
- const node = range(5, 1, 4);
85
- const result = LazyRuntime.evaluateRange(node, evaluator, {
86
- lazyLoading: false,
87
- });
88
- expect(result).to.deep.equal([5, 4, 3, 2, 1]);
89
- });
90
-
91
- it("should throw if step is zero", () => {
92
- const node = range(5, 10, 5);
93
- expect(() => LazyRuntime.evaluateRange(node, evaluator, {})).to.throw(
94
- /Range step cannot be zero/
95
- );
96
- });
97
- });
98
-
99
- describe("Infinite Ranges", () => {
100
- it("should return a LazyList object", () => {
101
- const node = range(1);
102
- const result = LazyRuntime.evaluateRange(node, evaluator, {
103
- lazyLoading: true,
104
- });
105
-
106
- expect(result).to.have.property("type", "LazyList");
107
- expect(result).to.have.property("generator");
108
- });
109
-
110
- it("should generate values on demand [1..]", () => {
111
- const node = range(1);
112
- const result = LazyRuntime.evaluateRange(node, evaluator, {
113
- lazyLoading: true,
114
- }) as LazyList;
115
- const gen = result.generator();
116
- expect(gen.next().value).to.equal(1);
117
- expect(gen.next().value).to.equal(2);
118
- expect(gen.next().value).to.equal(3);
119
- });
120
-
121
- it("should generate values with step on demand [0, 5 ..]", () => {
122
- const node = range(0, undefined, 5);
123
- const result = LazyRuntime.evaluateRange(node, evaluator, {
124
- lazyLoading: true,
125
- }) as LazyList;
126
-
127
- const gen = result.generator();
128
- expect(gen.next().value).to.equal(0);
129
- expect(gen.next().value).to.equal(5);
130
- expect(gen.next().value).to.equal(10);
131
- });
132
- });
133
- });
134
-
135
- describe("evaluateCons", () => {
136
- describe("Eager Mode (lazy: false)", () => {
137
- it("should construct an array if tail is an array", () => {
138
- const node = cons(1, [2, 3]);
139
- const result = LazyRuntime.evaluateCons(node, evaluator, false);
140
- expect(result).to.deep.equal([1, 2, 3]);
141
- });
142
-
143
- it("should throw if tail is not an array", () => {
144
- const lazyListMock = { type: "LazyList" };
145
- const node = cons(1, lazyListMock);
146
-
147
- expect(() => LazyRuntime.evaluateCons(node, evaluator, false)).to.throw(
148
- /Expected Array in eager Cons/
149
- );
150
- });
151
- });
152
-
153
- describe("Lazy Mode (lazy: true)", () => {
154
- it("should return an array if tail is an array (hybrid)", () => {
155
- const node = cons(1, [2, 3]);
156
- const result = LazyRuntime.evaluateCons(node, evaluator, true);
157
- expect(result).to.deep.equal([1, 2, 3]);
158
- });
159
-
160
- it("should return a new LazyList if tail is a LazyList", () => {
161
- const tailLazy: LazyList = createStream(function* () {
162
- yield 2;
163
- yield 3;
164
- });
165
-
166
- const node = cons(1, tailLazy);
167
- const result = LazyRuntime.evaluateCons(
168
- node,
169
- evaluator,
170
- true
171
- ) as LazyList;
172
-
173
- expect(result.type).to.equal("LazyList");
174
-
175
- const gen = result.generator();
176
- expect(gen.next().value).to.equal(1);
177
- expect(gen.next().value).to.equal(2);
178
- expect(gen.next().value).to.equal(3);
179
- expect(gen.next().done).to.be.true;
180
- });
181
-
182
- it("should throw if tail is invalid", () => {
183
- const node = cons(1, "invalid string");
184
- expect(() => LazyRuntime.evaluateCons(node, evaluator, true)).to.throw(
185
- /Invalid tail type/
186
- );
187
- });
188
- });
189
- });
190
- });
1
+ import { expect } from "chai";
2
+ import { LazyRuntime } from "../../src/interpreter/components/runtimes/LazyRuntime.js";
3
+ import {
4
+ RangeExpression,
5
+ ConsExpression,
6
+ LazyList,
7
+ NumberPrimitive,
8
+ ListPrimitive,
9
+ Expression,
10
+ isLazyList,
11
+ } from "yukigo-ast";
12
+ import {
13
+ createGlobalEnv,
14
+ createStream,
15
+ ExpressionEvaluator,
16
+ } from "../../src/interpreter/utils.js";
17
+ import {
18
+ isMemoizedList,
19
+ MemoizedLazyList,
20
+ } from "../../src/interpreter/components/PatternMatcher.js";
21
+ import { InterpreterVisitor } from "../../src/interpreter/components/Visitor.js";
22
+ import { fail } from "assert";
23
+ import {
24
+ idContinuation,
25
+ trampoline,
26
+ } from "../../src/interpreter/trampoline.js";
27
+ import { RuntimeContext } from "../../src/interpreter/components/RuntimeContext.js";
28
+
29
+ const num = (value: number) => new NumberPrimitive(value);
30
+
31
+ const range = (start: number, end?: number, step?: number): RangeExpression =>
32
+ new RangeExpression(
33
+ num(start),
34
+ end ? num(end) : undefined,
35
+ step ? num(step) : undefined,
36
+ );
37
+
38
+ const list = (elements: Expression[]) => new ListPrimitive(elements);
39
+
40
+ const cons = (headVal: Expression, tailVal: Expression): ConsExpression =>
41
+ new ConsExpression(headVal, tailVal);
42
+
43
+ const lazyContext = new RuntimeContext({ lazyLoading: true });
44
+ const eagerContext = new RuntimeContext({ lazyLoading: false });
45
+ describe("LazyRuntime", () => {
46
+ let evaluator: ExpressionEvaluator;
47
+ let lazyRuntime: LazyRuntime;
48
+ describe("realizeList", () => {
49
+ beforeEach(() => {
50
+ evaluator = new InterpreterVisitor(lazyContext);
51
+ lazyRuntime = new LazyRuntime(eagerContext);
52
+ });
53
+ it("should return the array as-is if input is already an array", () => {
54
+ const input = [1, 2, 3];
55
+ const result = trampoline(lazyRuntime.realizeList(input, idContinuation));
56
+ expect(result).to.equal(input);
57
+ expect(result).to.deep.equal([1, 2, 3]);
58
+ });
59
+
60
+ it("should consume a LazyList into an array", () => {
61
+ const lazyList: LazyList = createStream(function* () {
62
+ yield 10;
63
+ yield 20;
64
+ });
65
+
66
+ const result = trampoline(
67
+ lazyRuntime.realizeList(lazyList, idContinuation),
68
+ );
69
+ expect(result).to.deep.equal([10, 20]);
70
+ });
71
+
72
+ it("should throw if value is not a list or lazy list", () => {
73
+ expect(() =>
74
+ trampoline(lazyRuntime.realizeList(123 as any, idContinuation)),
75
+ ).to.throw(/Expected List or LazyList/);
76
+ });
77
+ });
78
+
79
+ describe("evaluateRange", () => {
80
+ describe("Finite Ranges", () => {
81
+ beforeEach(() => {
82
+ evaluator = new InterpreterVisitor(eagerContext);
83
+ lazyRuntime = new LazyRuntime(eagerContext);
84
+ });
85
+ it("should create a simple range [1..5]", () => {
86
+ const node = range(1, 5);
87
+ const result = trampoline(
88
+ lazyRuntime.evaluateRange(node, evaluator, idContinuation),
89
+ );
90
+ expect(result).to.deep.equal([1, 2, 3, 4, 5]);
91
+ });
92
+
93
+ it("should handle custom steps [0, 2 .. 10]", () => {
94
+ const node = range(0, 10, 2);
95
+ const result = trampoline(
96
+ lazyRuntime.evaluateRange(node, evaluator, idContinuation),
97
+ );
98
+ expect(result).to.deep.equal([0, 2, 4, 6, 8, 10]);
99
+ });
100
+
101
+ it("should handle negative steps [5, 4 .. 1]", () => {
102
+ const node = range(5, 1, 4);
103
+ const result = trampoline(
104
+ lazyRuntime.evaluateRange(node, evaluator, idContinuation),
105
+ );
106
+ expect(result).to.deep.equal([5, 4, 3, 2, 1]);
107
+ });
108
+
109
+ it("should throw if step is zero", () => {
110
+ const node = range(5, 10, 5);
111
+ expect(() =>
112
+ trampoline(
113
+ lazyRuntime.evaluateRange(node, evaluator, idContinuation),
114
+ ),
115
+ ).to.throw(/Range step cannot be zero/);
116
+ });
117
+ });
118
+
119
+ describe("Infinite Ranges", () => {
120
+ beforeEach(() => {
121
+ evaluator = new InterpreterVisitor(lazyContext);
122
+ lazyRuntime = new LazyRuntime(lazyContext);
123
+ });
124
+ it("should return a LazyList object", () => {
125
+ const node = range(1);
126
+ const result = trampoline(
127
+ lazyRuntime.evaluateRange(node, evaluator, idContinuation),
128
+ );
129
+
130
+ expect(result).to.have.property("type", "LazyList");
131
+ expect(result).to.have.property("generator");
132
+ });
133
+
134
+ it("should generate values on demand [1..]", () => {
135
+ const node = range(1);
136
+ const result = trampoline(
137
+ lazyRuntime.evaluateRange(node, evaluator, idContinuation),
138
+ ) as LazyList;
139
+ const gen = result.generator();
140
+ expect(gen.next().value).to.equal(1);
141
+ expect(gen.next().value).to.equal(2);
142
+ expect(gen.next().value).to.equal(3);
143
+ });
144
+
145
+ it("should generate values with step on demand [0, 5 ..]", () => {
146
+ const node = range(0, undefined, 5);
147
+ const result = trampoline(
148
+ lazyRuntime.evaluateRange(node, evaluator, idContinuation),
149
+ ) as LazyList;
150
+
151
+ const gen = result.generator();
152
+ expect(gen.next().value).to.equal(0);
153
+ expect(gen.next().value).to.equal(5);
154
+ expect(gen.next().value).to.equal(10);
155
+ });
156
+ });
157
+ });
158
+
159
+ describe("evaluateCons", () => {
160
+ describe("Eager Mode (lazy: false)", () => {
161
+ const eagerContext = new RuntimeContext({ lazyLoading: false });
162
+ const eagerEvaluator = new InterpreterVisitor(eagerContext);
163
+ const lazyRuntimeEager = new LazyRuntime(eagerContext);
164
+ it("should construct an array if tail is an array", () => {
165
+ const node = cons(num(1), list([num(2), num(3)]));
166
+ const result = trampoline(
167
+ lazyRuntimeEager.evaluateCons(node, eagerEvaluator, idContinuation),
168
+ );
169
+ expect(result).to.deep.equal([1, 2, 3]);
170
+ });
171
+
172
+ it("should throw if tail is not an array", () => {
173
+ const lazyListMock = range(1);
174
+ const node = cons(num(1), lazyListMock);
175
+
176
+ expect(() =>
177
+ trampoline(
178
+ lazyRuntimeEager.evaluateCons(node, eagerEvaluator, idContinuation),
179
+ ),
180
+ ).to.throw(/Expected Array in eager Cons/);
181
+ });
182
+ });
183
+
184
+ describe("Lazy Mode (lazy: true)", () => {
185
+ it("should return an array if tail is an array (hybrid)", () => {
186
+ const node = cons(num(1), list([num(2), num(3)]));
187
+ const result = trampoline(
188
+ lazyRuntime.evaluateCons(node, evaluator, idContinuation),
189
+ );
190
+ expect(isMemoizedList(result)).to.be.true;
191
+ const memoList = result as MemoizedLazyList;
192
+ const generator = memoList.generator();
193
+ expect(generator.next().value).to.deep.equal(1);
194
+ expect(generator.next().value).to.deep.equal(2);
195
+ expect(generator.next().value).to.deep.equal(3);
196
+ });
197
+
198
+ it("should return a new LazyList if tail is a LazyList", () => {
199
+ const tailLazy = range(2, 3);
200
+
201
+ const node = cons(num(1), tailLazy);
202
+ const result = trampoline(
203
+ lazyRuntime.evaluateCons(node, evaluator, idContinuation),
204
+ );
205
+ if (!isLazyList(result)) fail("result is not a lazy list");
206
+ const gen = result.generator();
207
+ expect(gen.next().value).to.equal(1);
208
+ expect(gen.next().value).to.equal(2);
209
+ expect(gen.next().value).to.equal(3);
210
+ expect(gen.next().done).to.be.true;
211
+ });
212
+
213
+ it("should throw if tail is invalid", () => {
214
+ const node = cons(num(1), num(123));
215
+ const result = trampoline(
216
+ lazyRuntime.evaluateCons(node, evaluator, idContinuation),
217
+ );
218
+ expect(isMemoizedList(result)).to.be.true;
219
+ const gen = (result as MemoizedLazyList).generator();
220
+ gen.next();
221
+ expect(() => gen.next()).to.throw(/Invalid tail type for Cons/);
222
+ });
223
+ });
224
+ });
225
+ });