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
@@ -0,0 +1,119 @@
1
+ import { Environment, EnvStack, PrimitiveValue } from "yukigo-ast";
2
+ import { FunctionRuntime } from "./runtimes/FunctionRuntime.js";
3
+ import { LazyRuntime } from "./runtimes/LazyRuntime.js";
4
+ import { ObjectRuntime } from "./runtimes/ObjectRuntime.js";
5
+ import { createGlobalEnv } from "../utils.js";
6
+ import { UnboundVariable } from "../errors.js";
7
+
8
+ export const DefaultConfiguration: Required<InterpreterConfig> = {
9
+ lazyLoading: false,
10
+ debug: false,
11
+ outputMode: "first",
12
+ mutability: true,
13
+ };
14
+
15
+ export type LogicSearchMode = "first" | "all" | "stream";
16
+ export interface InterpreterConfig {
17
+ lazyLoading?: boolean;
18
+ debug?: boolean;
19
+ outputMode?: LogicSearchMode;
20
+ mutability?: boolean;
21
+ }
22
+
23
+ export class UninitializedConfig extends Error {
24
+ constructor() {
25
+ super(
26
+ "GlobalConfig was not initialized. You must call initialize() first.",
27
+ );
28
+ }
29
+ }
30
+ export class ReinitializedConfig extends Error {
31
+ constructor() {
32
+ super(
33
+ "GlobalConfig is already initialized. You cannot change it at execution.",
34
+ );
35
+ }
36
+ }
37
+
38
+ export class RuntimeContext {
39
+ public readonly config: InterpreterConfig | null = null;
40
+ public env: EnvStack;
41
+ public lazyRuntime: LazyRuntime;
42
+ public funcRuntime: FunctionRuntime;
43
+ public objRuntime: ObjectRuntime;
44
+ constructor(config?: InterpreterConfig) {
45
+ this.config = Object.freeze({ ...DefaultConfiguration, ...config });
46
+ this.lazyRuntime = new LazyRuntime(this);
47
+ this.funcRuntime = new FunctionRuntime(this);
48
+ this.objRuntime = new ObjectRuntime(this);
49
+ this.env = createGlobalEnv();
50
+ }
51
+
52
+ public setEnv(env: EnvStack) {
53
+ this.env = env;
54
+ }
55
+ public isDefined(name: string): boolean {
56
+ let current: EnvStack | null = this.env;
57
+
58
+ while (current !== null) {
59
+ if (current.head.has(name)) return true;
60
+ current = current.tail;
61
+ }
62
+
63
+ return false;
64
+ }
65
+ public pushEnv(frame: Environment = new Map()) {
66
+ this.env = {
67
+ head: frame,
68
+ tail: this.env,
69
+ };
70
+ }
71
+ public replace(
72
+ name: string,
73
+ value: PrimitiveValue,
74
+ onReplace?: (env: Environment) => void,
75
+ ): boolean {
76
+ let current: EnvStack | null = this.env;
77
+
78
+ while (current !== null) {
79
+ if (current.head.has(name)) {
80
+ current.head.set(name, value);
81
+ if (onReplace) onReplace(current.head);
82
+ return true;
83
+ }
84
+ current = current.tail;
85
+ }
86
+
87
+ return false;
88
+ }
89
+ public popEnv() {
90
+ if (!this.env.tail)
91
+ throw new Error(
92
+ "Runtime Error: Cannot pop the global environment scope.",
93
+ );
94
+ this.env = this.env.tail;
95
+ }
96
+ public lookup(name: string): PrimitiveValue {
97
+ let current: EnvStack | null = this.env;
98
+
99
+ while (current !== null) {
100
+ if (current.head.has(name)) return current.head.get(name);
101
+ current = current.tail;
102
+ }
103
+
104
+ throw new UnboundVariable(name);
105
+ }
106
+ public remove(name: string): void {
107
+ this.env.head.delete(name);
108
+ }
109
+ public define(name: string, value: PrimitiveValue): void {
110
+ this.env.head.set(name, value);
111
+ }
112
+ public clone(env?: EnvStack): EnvStack {
113
+ const target = env ?? this.env;
114
+ return {
115
+ head: new Map(target.head),
116
+ tail: this.env.tail,
117
+ };
118
+ }
119
+ }
@@ -0,0 +1,151 @@
1
+ import {
2
+ Assert,
3
+ Equality,
4
+ Failure,
5
+ isLazyList,
6
+ PrimitiveValue,
7
+ Test,
8
+ TestGroup,
9
+ TraverseVisitor,
10
+ Truth,
11
+ } from "yukigo-ast";
12
+ import { InterpreterVisitor } from "./Visitor.js";
13
+ import {
14
+ CPSThunk,
15
+ idContinuation,
16
+ trampoline,
17
+ Continuation,
18
+ Thunk,
19
+ } from "../trampoline.js";
20
+ import { LazyRuntime } from "./runtimes/LazyRuntime.js";
21
+
22
+ export class FailedAssert extends Error {
23
+ constructor(
24
+ public actual?: PrimitiveValue,
25
+ public expected?: PrimitiveValue,
26
+ message?: string,
27
+ ) {
28
+ super(message || `Assertion failed: expected ${expected}, got ${actual}`);
29
+ this.name = "FailedAssert";
30
+ }
31
+ }
32
+
33
+ class AssertionVisitor extends TraverseVisitor {
34
+ constructor(
35
+ private interpreter: InterpreterVisitor,
36
+ private negated: boolean,
37
+ private lazyRuntime: LazyRuntime,
38
+ ) {
39
+ super();
40
+ }
41
+
42
+ visitFailure(node: Failure): CPSThunk<void> {
43
+ return (k) => () => {
44
+ let threw = false;
45
+ let actualError: string | undefined;
46
+
47
+ try {
48
+ // We use trampoline here to execute the function under test.
49
+ // While this is a nested trampoline, it's necessary to capture the error
50
+ // and isolate the test execution from the test runner's CPS flow.
51
+ trampoline(this.interpreter.evaluate(node.func, idContinuation));
52
+ } catch (error) {
53
+ threw = true;
54
+ actualError = (error as Error).message;
55
+ }
56
+
57
+ return this.interpreter.evaluate(node.message, (expectedError) => {
58
+ const passed =
59
+ threw &&
60
+ (expectedError === undefined ||
61
+ actualError?.includes(expectedError as string));
62
+
63
+ if (this.negated === passed) {
64
+ if (!threw) {
65
+ throw new FailedAssert(
66
+ undefined,
67
+ expectedError,
68
+ "Expected code to fail, but it succeeded",
69
+ );
70
+ } else {
71
+ throw new FailedAssert(
72
+ actualError,
73
+ expectedError,
74
+ `Expected error message to contain "${expectedError}", but got "${actualError}"`,
75
+ );
76
+ }
77
+ }
78
+ return k(undefined);
79
+ });
80
+ };
81
+ }
82
+
83
+ visitEquality(node: Equality): CPSThunk<void> {
84
+ return (k) =>
85
+ this.interpreter.evaluate(node.value, (value) => {
86
+ return () =>
87
+ this.interpreter.evaluate(node.expected, (expected) => {
88
+ this.lazyRuntime.deepEqual(value, expected, (passed) => {
89
+ if (this.negated === passed) {
90
+ throw new FailedAssert(
91
+ value, expected,
92
+ this.negated
93
+ ? `Expected ${JSON.stringify(value)} NOT to be equal to ${JSON.stringify(expected)}`
94
+ : `Expected ${JSON.stringify(expected)}, but got ${JSON.stringify(value)}`,
95
+ );
96
+ }
97
+ return k(undefined);
98
+ })
99
+ });
100
+ });
101
+ }
102
+
103
+ visitTruth(node: Truth): CPSThunk<void> {
104
+ return (k) =>
105
+ this.interpreter.evaluate(node.body, (value) => {
106
+ const isTruthy = Boolean(value);
107
+ if (this.negated === isTruthy) {
108
+ throw new FailedAssert(
109
+ value,
110
+ !this.negated,
111
+ this.negated
112
+ ? `Expected value to be falsy, but got ${JSON.stringify(value)}`
113
+ : `Expected value to be truthy, but got ${JSON.stringify(value)}`,
114
+ );
115
+ }
116
+ return k(undefined);
117
+ });
118
+ }
119
+ }
120
+
121
+ export class TestRunner extends TraverseVisitor {
122
+ constructor(
123
+ public interpreter: InterpreterVisitor,
124
+ private lazyRuntime: LazyRuntime,
125
+ ) {
126
+ super();
127
+ }
128
+
129
+ public run(node: TestGroup | Test | Assert): CPSThunk<void> {
130
+ return node.accept(this) as any;
131
+ }
132
+
133
+ visitTestGroup(node: TestGroup): CPSThunk<void> {
134
+ return (k) => this.interpreter.evaluate(node.group, () => k(undefined));
135
+ }
136
+ visitTest(node: Test): CPSThunk<void> {
137
+ return (k) => this.interpreter.evaluate(node.body, () => k(undefined));
138
+ }
139
+ visitAssert(node: Assert): CPSThunk<void> {
140
+ return (k) =>
141
+ this.interpreter.evaluate(node.negated, (negatedVal) => {
142
+ const isNegated = Boolean(negatedVal);
143
+ const visitor = new AssertionVisitor(
144
+ this.interpreter,
145
+ isNegated,
146
+ this.lazyRuntime,
147
+ );
148
+ return (node.body.accept(visitor) as any)(k);
149
+ });
150
+ }
151
+ }