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,499 +1,581 @@
1
- import {
2
- ArithmeticBinaryOperation,
3
- ArithmeticUnaryOperation,
4
- Assignment,
5
- AST,
6
- ASTNode,
7
- Attribute,
8
- Call,
9
- Catch,
10
- ConstructorPattern,
11
- EntryPoint,
12
- Fact,
13
- Function,
14
- If,
15
- ListType,
16
- LogicalBinaryOperation,
17
- LogicalUnaryOperation,
18
- Method,
19
- ParameterizedType,
20
- Print,
21
- Procedure,
22
- Raise,
23
- Record as RecordNode,
24
- Rule,
25
- SimpleType,
26
- StopTraversalException,
27
- SymbolPrimitive,
28
- TraverseVisitor,
29
- Try,
30
- TupleType,
31
- Type,
32
- TypeAlias,
33
- TypeApplication,
34
- TypeSignature,
35
- TypeVar,
36
- Variable,
37
- VariablePattern,
38
- } from "yukigo-ast";
39
- import { InspectionMap, executeVisitor } from "../utils.js";
40
-
41
- export class Assigns extends TraverseVisitor {
42
- private readonly targetIdentifier: string;
43
- constructor(targetIdentifier: string) {
44
- super();
45
- this.targetIdentifier = targetIdentifier;
46
- }
47
- visitVariable(node: Variable): void {
48
- if (node.identifier.value === this.targetIdentifier)
49
- throw new StopTraversalException();
50
- }
51
- visitAttribute(node: Attribute): void {
52
- if (node.identifier.value === this.targetIdentifier)
53
- throw new StopTraversalException();
54
- }
55
- visitAssignment(node: Assignment): void {
56
- if (node.identifier.value === this.targetIdentifier)
57
- throw new StopTraversalException();
58
- }
59
- }
60
- export class Calls extends TraverseVisitor {
61
- private readonly targetCallee: string;
62
- constructor(targetCallee: string) {
63
- super();
64
- this.targetCallee = targetCallee;
65
- }
66
- visitCall(node: Call): void {
67
- if (node.callee.value === this.targetCallee)
68
- throw new StopTraversalException();
69
- }
70
- }
71
- export class Declares extends TraverseVisitor {
72
- private readonly targetIdentifier: string;
73
- constructor(targetIdentifier: string) {
74
- super();
75
- this.targetIdentifier = targetIdentifier;
76
- }
77
- visit(node: ASTNode): void {
78
- if (
79
- "identifier" in node &&
80
- node.identifier instanceof SymbolPrimitive &&
81
- node.identifier.value === this.targetIdentifier
82
- )
83
- throw new StopTraversalException();
84
- }
85
- }
86
- export class DeclaresComputation extends TraverseVisitor {
87
- private readonly callName: string;
88
- constructor(callName: string) {
89
- super();
90
- this.callName = callName;
91
- }
92
- visitFunction(node: Function): void {
93
- if (node.identifier.value === this.callName)
94
- throw new StopTraversalException();
95
- }
96
- visitMethod(node: Method): void {
97
- if (node.identifier.value === this.callName)
98
- throw new StopTraversalException();
99
- }
100
- visitProcedure(node: Procedure): void {
101
- if (node.identifier.value === this.callName)
102
- throw new StopTraversalException();
103
- }
104
- visitFact(node: Fact): void {
105
- if (node.identifier.value === this.callName)
106
- throw new StopTraversalException();
107
- }
108
- visitRule(node: Rule): void {
109
- if (node.identifier.value === this.callName)
110
- throw new StopTraversalException();
111
- }
112
- }
113
- export class DeclaresComputationWithArity extends TraverseVisitor {
114
- private readonly targetBinding: string;
115
- private readonly targetArity: number;
116
- constructor(targetBinding: string, targetArity: number) {
117
- super();
118
- this.targetBinding = targetBinding;
119
- this.targetArity = targetArity;
120
- }
121
- visitFunction(node: Function): void {
122
- if (
123
- node.identifier.value === this.targetBinding &&
124
- node.equations.some((eq) => eq.patterns.length === this.targetArity)
125
- )
126
- throw new StopTraversalException();
127
- }
128
- visitMethod(node: Method): void {
129
- if (
130
- node.identifier.value === this.targetBinding &&
131
- node.equations.some((eq) => eq.patterns.length === this.targetArity)
132
- )
133
- throw new StopTraversalException();
134
- }
135
- visitProcedure(node: Procedure): void {
136
- if (
137
- node.identifier.value === this.targetBinding &&
138
- node.equations.some((eq) => eq.patterns.length === this.targetArity)
139
- )
140
- throw new StopTraversalException();
141
- }
142
- visitFact(node: Fact): void {
143
- if (
144
- node.identifier.value === this.targetBinding &&
145
- node.patterns.length === this.targetArity
146
- )
147
- throw new StopTraversalException();
148
- }
149
- visitRule(node: Rule): void {
150
- if (
151
- node.identifier.value === this.targetBinding &&
152
- node.patterns.length === this.targetArity
153
- )
154
- throw new StopTraversalException();
155
- }
156
- }
157
- export class DeclaresEntryPoint extends TraverseVisitor {
158
- visitEntryPoint(node: EntryPoint): void {
159
- throw new StopTraversalException();
160
- }
161
- }
162
- export class DeclaresFunction extends TraverseVisitor {
163
- private readonly targetBinding: string;
164
- constructor(targetBinding: string) {
165
- super();
166
- this.targetBinding = targetBinding;
167
- }
168
- visitFunction(node: Function): void {
169
- if (node.identifier.value === this.targetBinding)
170
- throw new StopTraversalException();
171
- }
172
- }
173
-
174
- export class DeclaresRecursively extends DeclaresComputation {
175
- private readonly targetBinding: string;
176
- constructor(targetBinding: string) {
177
- super(targetBinding);
178
- this.targetBinding = targetBinding;
179
- }
180
- visitFunction(node: Function): void {
181
- super.visitFunction(node);
182
- this.visitNested(node);
183
- }
184
- visitMethod(node: Method): void {
185
- super.visitMethod(node);
186
- this.visitNested(node);
187
- }
188
- visitProcedure(node: Procedure): void {
189
- super.visitProcedure(node);
190
- this.visitNested(node);
191
- }
192
- visitFact(node: Fact): void {
193
- super.visitFact(node);
194
- this.visitNested(node);
195
- }
196
- visitRule(node: Rule): void {
197
- super.visitRule(node);
198
- this.visitNested(node);
199
- }
200
- visitNested(node: ASTNode): void {
201
- if (
202
- "identifier" in node &&
203
- node.identifier instanceof SymbolPrimitive &&
204
- node.identifier.value === this.targetBinding
205
- )
206
- throw new StopTraversalException();
207
- }
208
- }
209
- export class DeclaresTypeAlias extends TraverseVisitor {
210
- private readonly typeAliasName: string;
211
- constructor(typeAliasName: string) {
212
- super();
213
- this.typeAliasName = typeAliasName;
214
- }
215
- visitTypeAlias(node: TypeAlias): void {
216
- if (node.identifier.value === this.typeAliasName)
217
- throw new StopTraversalException();
218
- }
219
- }
220
- export class DeclaresTypeSignature extends TraverseVisitor {
221
- private readonly targetBinding: string;
222
- constructor(targetBinding: string) {
223
- super();
224
- this.targetBinding = targetBinding;
225
- }
226
- visitTypeSignature(node: TypeSignature): void {
227
- if (node.identifier.value === this.targetBinding)
228
- throw new StopTraversalException();
229
- }
230
- }
231
- export class DeclaresVariable extends TraverseVisitor {
232
- private readonly targetBinding: string;
233
- constructor(targetBinding: string) {
234
- super();
235
- this.targetBinding = targetBinding;
236
- }
237
- visitVariable(node: Variable): void {
238
- if (node.identifier.value === this.targetBinding)
239
- throw new StopTraversalException();
240
- }
241
- }
242
- export class Raises extends TraverseVisitor {
243
- visitRaise(node: Raise): void {
244
- throw new StopTraversalException();
245
- }
246
- }
247
- export class Uses extends TraverseVisitor {
248
- private readonly targetBinding: string;
249
- constructor(targetBinding: string) {
250
- super();
251
- this.targetBinding = targetBinding;
252
- }
253
- visitSymbolPrimitive(node: SymbolPrimitive): void {
254
- if (node.value === this.targetBinding) throw new StopTraversalException();
255
- }
256
- }
257
- export class UsesArithmetic extends TraverseVisitor {
258
- visitArithmeticBinaryOperation(node: ArithmeticBinaryOperation): void {
259
- throw new StopTraversalException();
260
- }
261
- visitArithmeticUnaryOperation(node: ArithmeticUnaryOperation): void {
262
- throw new StopTraversalException();
263
- }
264
- }
265
- export class UsesConditional extends TraverseVisitor {
266
- visitIf(node: If): void {
267
- throw new StopTraversalException();
268
- }
269
- }
270
- export class UsesLogic extends TraverseVisitor {
271
- visitLogicalBinaryOperation(node: LogicalBinaryOperation): void {
272
- throw new StopTraversalException();
273
- }
274
- visitLogicalUnaryOperation(node: LogicalUnaryOperation): void {
275
- throw new StopTraversalException();
276
- }
277
- }
278
- export class UsesPrint extends TraverseVisitor {
279
- visitPrint(node: Print): void {
280
- throw new StopTraversalException();
281
- }
282
- }
283
- export class UsesType extends TraverseVisitor {
284
- private readonly targetBinding: string;
285
- constructor(targetBinding: string) {
286
- super();
287
- this.targetBinding = targetBinding;
288
- }
289
- visitTypeSignature(node: TypeSignature): void {
290
- node.body.accept(this);
291
- }
292
- visitSimpleType(node: SimpleType): void {
293
- if (node.value === this.targetBinding) throw new StopTraversalException();
294
- }
295
- visitTypeVar(node: TypeVar): void {
296
- if (node.value === this.targetBinding) throw new StopTraversalException();
297
- }
298
- }
299
- export class HasBinding extends TraverseVisitor {
300
- private readonly targetBinding: string;
301
- constructor(targetBinding: string) {
302
- super();
303
- this.targetBinding = targetBinding;
304
- }
305
- visitFunction(node: Function): void {
306
- if (node.identifier.value === this.targetBinding)
307
- throw new StopTraversalException();
308
- }
309
- visitTypeAlias(node: TypeAlias): void {
310
- if (node.identifier.value === this.targetBinding)
311
- throw new StopTraversalException();
312
- }
313
- visitTypeSignature(node: TypeSignature): void {
314
- if (node.identifier.value === this.targetBinding)
315
- throw new StopTraversalException();
316
- }
317
- visitRecord(node: RecordNode): void {
318
- if (node.name.value === this.targetBinding)
319
- throw new StopTraversalException();
320
- }
321
- }
322
-
323
- export class SubordinatesDeclarationsTo extends TraverseVisitor {
324
- constructor(private childName: string, private parentName: string) {
325
- super();
326
- }
327
-
328
- visitFunction(node: Function): void {
329
- if (node.identifier.value === this.parentName) {
330
- const childFinder = new Declares(this.childName);
331
- node.equations.forEach((eq) => eq.accept(childFinder)); // we expect that this will throw if find the subordinated decl
332
- } else {
333
- super.visitFunction(node);
334
- }
335
- }
336
- }
337
-
338
- export class SubordinatesDeclarationsToEntryPoint extends TraverseVisitor {
339
- constructor(private childName: string) {
340
- super();
341
- }
342
-
343
- visitEntryPoint(node: EntryPoint): void {
344
- const childFinder = new Declares(this.childName);
345
- node.expression.statements.forEach((stmt) => stmt.accept(childFinder));
346
- }
347
- }
348
-
349
- export class TypesAs extends TraverseVisitor {
350
- constructor(private bindingName: string, private typeName: string) {
351
- super();
352
- }
353
-
354
- visitTypeSignature(node: TypeSignature): void {
355
- if (node.identifier.value === this.bindingName) {
356
- const actualType = node.body.toString();
357
- if (
358
- actualType.replace(/\s+/g, " ").trim() ===
359
- this.typeName.replace(/\s+/g, " ").trim()
360
- ) {
361
- throw new StopTraversalException();
362
- }
363
- }
364
- }
365
- }
366
-
367
- export class TypesParameterAs extends TraverseVisitor {
368
- constructor(
369
- private bindingName: string,
370
- private paramIndex: number,
371
- private typeName: string
372
- ) {
373
- super();
374
- }
375
-
376
- visitTypeSignature(node: TypeSignature): void {
377
- if (node.identifier.value === this.bindingName) {
378
- if (node.body instanceof ParameterizedType) {
379
- const paramType = node.body.inputs[this.paramIndex];
380
- if (paramType) {
381
- const actualType = paramType.toString();
382
- if (
383
- actualType.replace(/\s+/g, " ").trim() ===
384
- this.typeName.replace(/\s+/g, " ").trim()
385
- ) {
386
- throw new StopTraversalException();
387
- }
388
- }
389
- }
390
- }
391
- }
392
- }
393
-
394
- export class TypesReturnAs extends TraverseVisitor {
395
- constructor(private bindingName: string, private typeName: string) {
396
- super();
397
- }
398
-
399
- visitTypeSignature(node: TypeSignature): void {
400
- if (node.identifier.value === this.bindingName) {
401
- if (node.body instanceof ParameterizedType) {
402
- const actualType = node.body.returnType.toString();
403
- if (
404
- actualType.replace(/\s+/g, " ").trim() ===
405
- this.typeName.replace(/\s+/g, " ").trim()
406
- ) {
407
- throw new StopTraversalException();
408
- }
409
- }
410
- }
411
- }
412
- }
413
-
414
- export class Rescues extends TraverseVisitor {
415
- constructor(private exceptionName: string) {
416
- super();
417
- }
418
- visitCatch(node: Catch): void {
419
- for (const pattern of node.patterns) {
420
- if (
421
- pattern instanceof VariablePattern &&
422
- pattern.name.value === this.exceptionName
423
- ) {
424
- throw new StopTraversalException();
425
- }
426
- }
427
- }
428
- }
429
-
430
- export class UsesExceptionHandling extends TraverseVisitor {
431
- visitTry(node: Try): void {
432
- throw new StopTraversalException();
433
- }
434
- }
435
-
436
- export class UsesExceptions extends TraverseVisitor {
437
- visitTry(node: Try): void {
438
- throw new StopTraversalException();
439
- }
440
- visitRaise(node: Raise): void {
441
- throw new StopTraversalException();
442
- }
443
- }
444
-
445
- export const genericInspections: InspectionMap = {
446
- Assigns: (node, args) => executeVisitor(node, new Assigns(args[0])),
447
- Calls: (node, args) => executeVisitor(node, new Calls(args[0])),
448
- Declares: (node, args) => executeVisitor(node, new Declares(args[0])),
449
- DeclaresComputation: (node, args) =>
450
- executeVisitor(node, new DeclaresComputation(args[0])),
451
- DeclaresComputationWithArity: (node, args, binding) =>
452
- executeVisitor(
453
- node,
454
- new DeclaresComputationWithArity(binding, Number(args[0]))
455
- ),
456
- DeclaresEntryPoint: (node, args) =>
457
- executeVisitor(node, new DeclaresEntryPoint()),
458
- DeclaresFunction: (node, args) =>
459
- executeVisitor(node, new DeclaresFunction(args[0])),
460
- DeclaresRecursively: (node, args) =>
461
- executeVisitor(node, new DeclaresRecursively(args[0])),
462
- DeclaresTypeAlias: (node, args) =>
463
- executeVisitor(node, new DeclaresTypeAlias(args[0])),
464
- DeclaresTypeSignature: (node, args) =>
465
- executeVisitor(node, new DeclaresTypeSignature(args[0])),
466
- DeclaresVariable: (node, args) =>
467
- executeVisitor(node, new DeclaresVariable(args[0])),
468
- Delegates: (ast, args) => {
469
- const declares = genericInspections.Declares(ast, args);
470
- const calls = genericInspections.Calls(ast, args);
471
- return declares && calls;
472
- },
473
- Raises: (node, args) => executeVisitor(node, new Raises()),
474
- Uses: (node, args) => executeVisitor(node, new Uses(args[0])),
475
- UsesArithmetic: (node, args) => executeVisitor(node, new UsesArithmetic()),
476
- SubordinatesDeclarationsTo: (node, args) =>
477
- executeVisitor(node, new SubordinatesDeclarationsTo(args[0], args[1])),
478
- SubordinatesDeclarationsToEntryPoint: (node, args) =>
479
- executeVisitor(node, new SubordinatesDeclarationsToEntryPoint(args[0])),
480
- TypesAs: (node, args) => executeVisitor(node, new TypesAs(args[0], args[1])),
481
- TypesParameterAs: (node, args) =>
482
- executeVisitor(
483
- node,
484
- new TypesParameterAs(args[0], Number(args[1]), args[2])
485
- ),
486
- TypesReturnAs: (node, args) =>
487
- executeVisitor(node, new TypesReturnAs(args[0], args[1])),
488
- UsesConditional: (node, args) => executeVisitor(node, new UsesConditional()),
489
- Rescues: (node, args) => executeVisitor(node, new Rescues(args[0])),
490
- UsesExceptionHandling: (node, args) =>
491
- executeVisitor(node, new UsesExceptionHandling()),
492
- UsesExceptions: (node, args) => executeVisitor(node, new UsesExceptions()),
493
- UsesIf: (node, args) => executeVisitor(node, new UsesConditional()),
494
- UsesLogic: (node, args) => executeVisitor(node, new UsesLogic()),
495
- UsesMath: (node, args) => executeVisitor(node, new UsesArithmetic()),
496
- UsesPrint: (node, args) => executeVisitor(node, new UsesPrint()),
497
- UsesType: (node, args) => executeVisitor(node, new UsesType(args[0])),
498
- HasBinding: (node, args) => executeVisitor(node, new HasBinding(args[0])),
499
- };
1
+ import {
2
+ Application,
3
+ ArithmeticBinaryOperation,
4
+ ArithmeticUnaryOperation,
5
+ Assignment,
6
+ ASTNode,
7
+ Attribute,
8
+ Call,
9
+ Catch,
10
+ Class,
11
+ EntryPoint,
12
+ Equation,
13
+ Fact,
14
+ Function,
15
+ If,
16
+ isUnguardedBody,
17
+ LogicalBinaryOperation,
18
+ LogicalUnaryOperation,
19
+ Method,
20
+ Object,
21
+ ParameterizedType,
22
+ Print,
23
+ Procedure,
24
+ Raise,
25
+ Record as RecordNode,
26
+ Rule,
27
+ SimpleType,
28
+ StopTraversalException,
29
+ SymbolPrimitive,
30
+ TraverseVisitor,
31
+ Try,
32
+ TypeAlias,
33
+ TypeSignature,
34
+ TypeVar,
35
+ Variable,
36
+ VariablePattern,
37
+ } from "yukigo-ast";
38
+ import { VisitorConstructor, ScopedVisitor, AutoScoped } from "../../utils.js";
39
+
40
+ @AutoScoped
41
+ export class Assigns extends ScopedVisitor {
42
+ private readonly targetIdentifier: string;
43
+ constructor(targetIdentifier: string, scope?: string) {
44
+ super(scope);
45
+ this.targetIdentifier = targetIdentifier;
46
+ }
47
+ visitVariable(node: Variable): void {
48
+ if (node.identifier.value === this.targetIdentifier)
49
+ throw new StopTraversalException();
50
+ }
51
+ visitAttribute(node: Attribute): void {
52
+ if (node.identifier.value === this.targetIdentifier)
53
+ throw new StopTraversalException();
54
+ }
55
+ visitAssignment(node: Assignment): void {
56
+ if (node.identifier.value === this.targetIdentifier)
57
+ throw new StopTraversalException();
58
+ }
59
+ }
60
+ @AutoScoped
61
+ export class Calls extends ScopedVisitor {
62
+ private readonly targetCallee: string;
63
+ constructor(targetCallee: string, scope?: string) {
64
+ super(scope);
65
+ this.targetCallee = targetCallee;
66
+ }
67
+ visitCall(node: Call): void {
68
+ if (node.callee.value === this.targetCallee)
69
+ throw new StopTraversalException();
70
+ }
71
+ }
72
+ @AutoScoped
73
+ export class Declares extends ScopedVisitor {
74
+ private readonly targetIdentifier: string;
75
+
76
+ constructor(targetIdentifier: string, scopeName?: string) {
77
+ super(scopeName);
78
+ this.targetIdentifier = targetIdentifier;
79
+ }
80
+
81
+ private check(node: { identifier: SymbolPrimitive }): void {
82
+ if (node.identifier.value === this.targetIdentifier)
83
+ throw new StopTraversalException();
84
+ }
85
+
86
+ visitFunction(node: Function): void {
87
+ if (this.inScope) this.check(node);
88
+ super.visitFunction(node);
89
+ }
90
+
91
+ visitMethod(node: Method): void {
92
+ if (this.inScope) this.check(node);
93
+ super.visitMethod(node);
94
+ }
95
+
96
+ visitProcedure(node: Procedure): void {
97
+ if (this.inScope) this.check(node);
98
+ super.visitProcedure(node);
99
+ }
100
+
101
+ visitRule(node: Rule): void {
102
+ if (this.inScope) this.check(node);
103
+ super.visitRule(node);
104
+ }
105
+
106
+ visitFact(node: Fact): void {
107
+ if (this.inScope) this.check(node);
108
+ super.visitFact(node);
109
+ }
110
+
111
+ visitVariable(node: Variable): void {
112
+ this.check(node);
113
+ }
114
+
115
+ visitAttribute(node: Attribute): void {
116
+ this.check(node);
117
+ }
118
+
119
+ visitTypeAlias(node: TypeAlias): void {
120
+ this.check(node);
121
+ }
122
+
123
+ visitTypeSignature(node: TypeSignature): void {
124
+ this.check(node);
125
+ }
126
+ }
127
+ @AutoScoped
128
+ export class DeclaresComputation extends ScopedVisitor {
129
+ private readonly callName: string;
130
+ constructor(callName: string, scope?: string) {
131
+ super(scope);
132
+ this.callName = callName;
133
+ }
134
+ visitFunction(node: Function): void {
135
+ if (node.identifier.value === this.callName)
136
+ throw new StopTraversalException();
137
+ }
138
+ visitMethod(node: Method): void {
139
+ if (node.identifier.value === this.callName)
140
+ throw new StopTraversalException();
141
+ }
142
+ visitProcedure(node: Procedure): void {
143
+ if (node.identifier.value === this.callName)
144
+ throw new StopTraversalException();
145
+ }
146
+ visitFact(node: Fact): void {
147
+ if (node.identifier.value === this.callName)
148
+ throw new StopTraversalException();
149
+ }
150
+ visitRule(node: Rule): void {
151
+ if (node.identifier.value === this.callName)
152
+ throw new StopTraversalException();
153
+ }
154
+ }
155
+ @AutoScoped
156
+ export class DeclaresComputationWithArity extends ScopedVisitor {
157
+ private readonly targetArity: number;
158
+ constructor(targetArity: string, scope?: string) {
159
+ super(scope);
160
+ this.targetArity = Number(targetArity);
161
+ }
162
+ visitFunction(node: Function): void {
163
+ if (node.equations.some((eq) => eq.patterns.length === this.targetArity))
164
+ throw new StopTraversalException();
165
+ }
166
+ visitMethod(node: Method): void {
167
+ if (node.equations.some((eq) => eq.patterns.length === this.targetArity))
168
+ throw new StopTraversalException();
169
+ }
170
+ visitProcedure(node: Procedure): void {
171
+ if (node.equations.some((eq) => eq.patterns.length === this.targetArity))
172
+ throw new StopTraversalException();
173
+ }
174
+ visitFact(node: Fact): void {
175
+ if (node.patterns.length === this.targetArity)
176
+ throw new StopTraversalException();
177
+ }
178
+ visitRule(node: Rule): void {
179
+ if (node.equations.some((eq) => eq.patterns.length === this.targetArity))
180
+ throw new StopTraversalException();
181
+ }
182
+ }
183
+ export class DeclaresEntryPoint extends TraverseVisitor {
184
+ visitEntryPoint(node: EntryPoint): void {
185
+ throw new StopTraversalException();
186
+ }
187
+ }
188
+ @AutoScoped
189
+ export class DeclaresFunction extends ScopedVisitor {
190
+ private readonly targetBinding: string;
191
+ constructor(targetBinding: string, scope?: string) {
192
+ super(scope);
193
+ this.targetBinding = targetBinding;
194
+ }
195
+ visitFunction(node: Function): void {
196
+ if (node.identifier.value === this.targetBinding)
197
+ throw new StopTraversalException();
198
+ }
199
+ }
200
+
201
+ @AutoScoped
202
+ export class DeclaresRecursively extends ScopedVisitor {
203
+ private readonly targetBinding: string;
204
+ constructor(targetBinding: string, scope?: string) {
205
+ super(scope);
206
+ this.targetBinding = targetBinding;
207
+ }
208
+ visitFunction(node: Function): void {
209
+ super.visitFunction(node);
210
+ this.visitNested(node);
211
+ }
212
+ visitMethod(node: Method): void {
213
+ super.visitMethod(node);
214
+ this.visitNested(node);
215
+ }
216
+ visitProcedure(node: Procedure): void {
217
+ super.visitProcedure(node);
218
+ this.visitNested(node);
219
+ }
220
+ visitFact(node: Fact): void {
221
+ super.visitFact(node);
222
+ this.visitNested(node);
223
+ }
224
+ visitRule(node: Rule): void {
225
+ super.visitRule(node);
226
+ this.visitNested(node);
227
+ }
228
+ visitNested(node: ASTNode): void {
229
+ if (
230
+ "identifier" in node &&
231
+ node.identifier instanceof SymbolPrimitive &&
232
+ node.identifier.value === this.targetBinding
233
+ )
234
+ throw new StopTraversalException();
235
+ }
236
+ }
237
+ export class HasDirectRecursion extends TraverseVisitor {
238
+ private isInsideBody: boolean = false;
239
+ constructor(private readonly binding: string) {
240
+ super();
241
+ }
242
+
243
+ override visitFunction(node: Function): void {
244
+ if (node.identifier.value !== this.binding) return;
245
+ this.traverseCollection(node.equations);
246
+ }
247
+ override visitRule(node: Rule): void {
248
+ if (node.identifier.value !== this.binding) return;
249
+ this.traverseCollection(node.equations);
250
+ }
251
+ override visitProcedure(node: Procedure): void {
252
+ if (node.identifier.value !== this.binding) return;
253
+ this.traverseCollection(node.equations);
254
+ }
255
+ override visitMethod(node: Method): void {
256
+ if (node.identifier.value !== this.binding) return;
257
+ this.traverseCollection(node.equations);
258
+ }
259
+ override visitEquation(node: Equation): void {
260
+ this.isInsideBody = true;
261
+ try {
262
+ if (isUnguardedBody(node.body)) {
263
+ node.body.accept(this);
264
+ } else {
265
+ this.traverseCollection(node.body);
266
+ }
267
+ } finally {
268
+ this.isInsideBody = false;
269
+ }
270
+ }
271
+
272
+ visitSymbolPrimitive(node: SymbolPrimitive): void {
273
+ if (this.isInsideBody && node.value === this.binding)
274
+ throw new StopTraversalException();
275
+ }
276
+ }
277
+
278
+ export class DeclaresTypeAlias extends TraverseVisitor {
279
+ private readonly typeAliasName: string;
280
+ constructor(typeAliasName: string) {
281
+ super();
282
+ this.typeAliasName = typeAliasName;
283
+ }
284
+ visitTypeAlias(node: TypeAlias): void {
285
+ if (node.identifier.value === this.typeAliasName)
286
+ throw new StopTraversalException();
287
+ }
288
+ }
289
+ export class DeclaresTypeSignature extends TraverseVisitor {
290
+ private readonly targetBinding: string;
291
+ constructor(targetBinding: string) {
292
+ super();
293
+ this.targetBinding = targetBinding;
294
+ }
295
+ visitTypeSignature(node: TypeSignature): void {
296
+ if (node.identifier.value === this.targetBinding)
297
+ throw new StopTraversalException();
298
+ }
299
+ }
300
+ @AutoScoped
301
+ export class DeclaresVariable extends ScopedVisitor {
302
+ private readonly targetBinding: string;
303
+ constructor(targetBinding: string, scope?: string) {
304
+ super(scope);
305
+ this.targetBinding = targetBinding;
306
+ }
307
+ visitVariable(node: Variable): void {
308
+ if (node.identifier.value === this.targetBinding)
309
+ throw new StopTraversalException();
310
+ }
311
+ }
312
+ @AutoScoped
313
+ export class Raises extends ScopedVisitor {
314
+ constructor(scope: string) {
315
+ super(scope);
316
+ }
317
+ visitRaise(node: Raise): void {
318
+ throw new StopTraversalException();
319
+ }
320
+ }
321
+ @AutoScoped
322
+ export class Uses extends ScopedVisitor {
323
+ private readonly targetBinding: string;
324
+ constructor(targetBinding: string, scope?: string) {
325
+ super(scope);
326
+ this.targetBinding = targetBinding;
327
+ }
328
+ visitSymbolPrimitive(node: SymbolPrimitive): void {
329
+ if (node.value === this.targetBinding) throw new StopTraversalException();
330
+ }
331
+ }
332
+ @AutoScoped
333
+ export class UsesArithmetic extends ScopedVisitor {
334
+ constructor(scope?: string) {
335
+ super(scope);
336
+ }
337
+ visitArithmeticBinaryOperation(node: ArithmeticBinaryOperation): void {
338
+ throw new StopTraversalException();
339
+ }
340
+ visitArithmeticUnaryOperation(node: ArithmeticUnaryOperation): void {
341
+ throw new StopTraversalException();
342
+ }
343
+ }
344
+ @AutoScoped
345
+ export class UsesConditional extends ScopedVisitor {
346
+ visitIf(node: If): void {
347
+ throw new StopTraversalException();
348
+ }
349
+ }
350
+ @AutoScoped
351
+ export class UsesLogic extends ScopedVisitor {
352
+ constructor(scope?: string) {
353
+ super(scope);
354
+ }
355
+ visitLogicalBinaryOperation(node: LogicalBinaryOperation): void {
356
+ throw new StopTraversalException();
357
+ }
358
+ visitLogicalUnaryOperation(node: LogicalUnaryOperation): void {
359
+ throw new StopTraversalException();
360
+ }
361
+ }
362
+ @AutoScoped
363
+ export class UsesPrint extends ScopedVisitor {
364
+ constructor(scope?: string) {
365
+ super(scope);
366
+ }
367
+ visitPrint(node: Print): void {
368
+ throw new StopTraversalException();
369
+ }
370
+ }
371
+ @AutoScoped
372
+ export class UsesType extends ScopedVisitor {
373
+ private readonly targetBinding: string;
374
+ constructor(targetBinding: string, scope?: string) {
375
+ super(scope);
376
+ this.targetBinding = targetBinding;
377
+ }
378
+ visitTypeSignature(node: TypeSignature): void {
379
+ node.body.accept(this);
380
+ }
381
+ visitSimpleType(node: SimpleType): void {
382
+ if (node.value === this.targetBinding) throw new StopTraversalException();
383
+ }
384
+ visitTypeVar(node: TypeVar): void {
385
+ if (node.value === this.targetBinding) throw new StopTraversalException();
386
+ }
387
+ }
388
+ @AutoScoped
389
+ export class HasBinding extends ScopedVisitor {
390
+ visitFunction(node: Function): void {
391
+ throw new StopTraversalException();
392
+ }
393
+ visitObject(node: Object): void {
394
+ throw new StopTraversalException();
395
+ }
396
+ visitClass(node: Class): void {
397
+ throw new StopTraversalException();
398
+ }
399
+ visitRule(node: Rule): void {
400
+ throw new StopTraversalException();
401
+ }
402
+ visitFact(node: Fact): void {
403
+ throw new StopTraversalException();
404
+ }
405
+ visitTypeAlias(node: TypeAlias): void {
406
+ throw new StopTraversalException();
407
+ }
408
+ visitTypeSignature(node: TypeSignature): void {
409
+ throw new StopTraversalException();
410
+ }
411
+ visitRecord(node: RecordNode): void {
412
+ throw new StopTraversalException();
413
+ }
414
+ }
415
+
416
+ export class SubordinatesDeclarationsTo extends TraverseVisitor {
417
+ constructor(private childName: string, private parentName: string) {
418
+ super();
419
+ }
420
+
421
+ visitFunction(node: Function): void {
422
+ if (node.identifier.value === this.parentName) {
423
+ const childFinder = new Declares(this.childName);
424
+ node.equations.forEach((eq) => eq.accept(childFinder)); // we expect that this will throw if find the subordinated decl
425
+ } else {
426
+ super.visitFunction(node);
427
+ }
428
+ }
429
+ }
430
+
431
+ export class SubordinatesDeclarationsToEntryPoint extends TraverseVisitor {
432
+ constructor(private childName: string) {
433
+ super();
434
+ }
435
+
436
+ visitEntryPoint(node: EntryPoint): void {
437
+ const childFinder = new Declares(this.childName);
438
+ node.expression.statements.forEach((stmt) => stmt.accept(childFinder));
439
+ }
440
+ }
441
+
442
+ export class TypesAs extends TraverseVisitor {
443
+ constructor(private typeName: string, private bindingName: string) {
444
+ super();
445
+ }
446
+
447
+ visitTypeSignature(node: TypeSignature): void {
448
+ if (node.identifier.value === this.bindingName) {
449
+ const actualType = node.body.toString();
450
+ if (
451
+ actualType.replace(/\s+/g, " ").trim() ===
452
+ this.typeName.replace(/\s+/g, " ").trim()
453
+ ) {
454
+ throw new StopTraversalException();
455
+ }
456
+ }
457
+ }
458
+ }
459
+
460
+ export class TypesParameterAs extends TraverseVisitor {
461
+ constructor(
462
+ private paramIndex: number,
463
+ private typeName: string,
464
+ private bindingName: string
465
+ ) {
466
+ super();
467
+ }
468
+
469
+ visitTypeSignature(node: TypeSignature): void {
470
+ if (node.identifier.value === this.bindingName) {
471
+ if (node.body instanceof ParameterizedType) {
472
+ const paramType = node.body.inputs[this.paramIndex];
473
+ if (paramType) {
474
+ const actualType = paramType.toString();
475
+ if (
476
+ actualType.replace(/\s+/g, " ").trim() ===
477
+ this.typeName.replace(/\s+/g, " ").trim()
478
+ ) {
479
+ throw new StopTraversalException();
480
+ }
481
+ }
482
+ }
483
+ }
484
+ }
485
+ }
486
+
487
+ export class TypesReturnAs extends TraverseVisitor {
488
+ constructor(private typeName: string, private bindingName: string) {
489
+ super();
490
+ }
491
+
492
+ visitTypeSignature(node: TypeSignature): void {
493
+ if (node.identifier.value === this.bindingName) {
494
+ if (node.body instanceof ParameterizedType) {
495
+ const actualType = node.body.returnType.toString();
496
+ if (
497
+ actualType.replace(/\s+/g, " ").trim() ===
498
+ this.typeName.replace(/\s+/g, " ").trim()
499
+ ) {
500
+ throw new StopTraversalException();
501
+ }
502
+ }
503
+ }
504
+ }
505
+ }
506
+
507
+ @AutoScoped
508
+ export class Rescues extends ScopedVisitor {
509
+ constructor(private exceptionName: string, scope?: string) {
510
+ super(scope);
511
+ }
512
+ visitCatch(node: Catch): void {
513
+ for (const pattern of node.patterns) {
514
+ if (
515
+ pattern instanceof VariablePattern &&
516
+ pattern.name.value === this.exceptionName
517
+ ) {
518
+ throw new StopTraversalException();
519
+ }
520
+ }
521
+ }
522
+ }
523
+
524
+ @AutoScoped
525
+ export class UsesExceptionHandling extends ScopedVisitor {
526
+ constructor(scope?: string) {
527
+ super(scope);
528
+ }
529
+ visitTry(node: Try): void {
530
+ throw new StopTraversalException();
531
+ }
532
+ }
533
+ @AutoScoped
534
+ export class UsesExceptions extends ScopedVisitor {
535
+ constructor(scope?: string) {
536
+ super(scope);
537
+ }
538
+ visitTry(node: Try): void {
539
+ return new UsesExceptionHandling(this.binding).visitTry(node);
540
+ }
541
+ visitRaise(node: Raise): void {
542
+ throw new StopTraversalException();
543
+ }
544
+ }
545
+
546
+ export const genericInspections: Record<string, VisitorConstructor> = {
547
+ Assigns: Assigns,
548
+ Calls: Calls,
549
+ Declares: Declares,
550
+ DeclaresComputation: DeclaresComputation,
551
+ DeclaresComputationWithArity: DeclaresComputationWithArity,
552
+ HasArity: DeclaresComputationWithArity,
553
+ DeclaresEntryPoint: DeclaresEntryPoint,
554
+ DeclaresFunction: DeclaresFunction,
555
+ DeclaresRecursively: DeclaresRecursively,
556
+ HasDirectRecursion: HasDirectRecursion,
557
+ DeclaresTypeAlias: DeclaresTypeAlias,
558
+ DeclaresTypeSignature: DeclaresTypeSignature,
559
+ HasTypeSignature: DeclaresTypeSignature,
560
+ DeclaresVariable: DeclaresVariable,
561
+ Raises: Raises,
562
+ Uses: Uses,
563
+ HasUsage: Uses,
564
+ UsesArithmetic: UsesArithmetic,
565
+ SubordinatesDeclarationsTo: SubordinatesDeclarationsTo,
566
+ SubordinatesDeclarationsToEntryPoint: SubordinatesDeclarationsToEntryPoint,
567
+ TypesAs: TypesAs,
568
+ TypesParameterAs: TypesParameterAs,
569
+ TypesReturnAs: TypesReturnAs,
570
+ UsesConditional: UsesConditional,
571
+ HasConditional: UsesConditional,
572
+ Rescues: Rescues,
573
+ UsesExceptionHandling: UsesExceptionHandling,
574
+ UsesExceptions: UsesExceptions,
575
+ UsesIf: UsesConditional,
576
+ UsesLogic: UsesLogic,
577
+ UsesMath: UsesArithmetic,
578
+ UsesPrint: UsesPrint,
579
+ UsesType: UsesType,
580
+ HasBinding: HasBinding,
581
+ };