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,282 +1,264 @@
1
- import {
2
- Attribute,
3
- Class,
4
- Include,
5
- Interface,
6
- Method,
7
- New,
8
- Object,
9
- PrimitiveMethod,
10
- Self,
11
- Send,
12
- StopTraversalException,
13
- SymbolPrimitive,
14
- TraverseVisitor,
15
- } from "yukigo-ast";
16
- import { executeVisitor, InspectionMap } from "../utils.js";
17
-
18
- export class DeclaresAttribute extends TraverseVisitor {
19
- constructor(private attributeName: string) {
20
- super();
21
- }
22
- visitAttribute(node: Attribute): void {
23
- if (node.identifier.value === this.attributeName)
24
- throw new StopTraversalException();
25
- }
26
- }
27
-
28
- export class DeclaresClass extends TraverseVisitor {
29
- constructor(private className: string) {
30
- super();
31
- }
32
- visitClass(node: Class): void {
33
- if (node.identifier.value === this.className)
34
- throw new StopTraversalException();
35
- }
36
- }
37
-
38
- export class DeclaresInterface extends TraverseVisitor {
39
- constructor(private interfaceName: string) {
40
- super();
41
- }
42
- visitInterface(node: Interface): void {
43
- if (node.identifier.value === this.interfaceName)
44
- throw new StopTraversalException();
45
- }
46
- }
47
-
48
- export class DeclaresMethod extends TraverseVisitor {
49
- constructor(private methodName: string) {
50
- super();
51
- }
52
- visitMethod(node: Method): void {
53
- if (node.identifier.value === this.methodName)
54
- throw new StopTraversalException();
55
- }
56
- }
57
-
58
- export class DeclaresObject extends TraverseVisitor {
59
- constructor(private objectName: string) {
60
- super();
61
- }
62
- visitObject(node: Object): void {
63
- if (node.identifier.value === this.objectName)
64
- throw new StopTraversalException();
65
- }
66
- }
67
-
68
- export class DeclaresPrimitive extends TraverseVisitor {
69
- constructor(private operatorName: string) {
70
- super();
71
- }
72
- visitPrimitiveMethod(node: PrimitiveMethod): void {
73
- if (node.operator === this.operatorName) throw new StopTraversalException();
74
- }
75
- }
76
-
77
- export class DeclaresSuperclass extends TraverseVisitor {
78
- constructor(private superclassName: string) {
79
- super();
80
- }
81
- visitClass(node: Class): void {
82
- if (node.extendsSymbol && node.extendsSymbol.value === this.superclassName)
83
- throw new StopTraversalException();
84
- }
85
- }
86
-
87
- export class Implements extends TraverseVisitor {
88
- constructor(private interfaceName: string) {
89
- super();
90
- }
91
- visitClass(node: Class): void {
92
- if (
93
- node.implementsNode &&
94
- node.implementsNode.identifier.value === this.interfaceName
95
- )
96
- throw new StopTraversalException();
97
- }
98
- }
99
-
100
- export class IncludeMixin extends TraverseVisitor {
101
- constructor(private mixinsName: string) {
102
- super();
103
- }
104
- visitInclude(node: Include): void {
105
- if (node.identifier.value === this.mixinsName)
106
- throw new StopTraversalException();
107
- }
108
- }
109
-
110
- export class Instantiates extends TraverseVisitor {
111
- constructor(private className: string) {
112
- super();
113
- }
114
- visitNew(node: New): void {
115
- if (node.identifier.value === this.className)
116
- throw new StopTraversalException();
117
- }
118
- }
119
-
120
- export class UsesDynamicPolymorphism extends TraverseVisitor {
121
- private count = 0;
122
-
123
- constructor(private selectorName: string) {
124
- super();
125
- }
126
-
127
- visitMethod(node: Method): void {
128
- if (node.identifier.value === this.selectorName) {
129
- this.count++;
130
- if (this.count >= 2) throw new StopTraversalException();
131
- }
132
- }
133
- }
134
-
135
- export class UsesInheritance extends TraverseVisitor {
136
- visitClass(node: Class): void {
137
- if (node.extendsSymbol) throw new StopTraversalException();
138
- }
139
- visitInterface(node: Interface): void {
140
- if (node.extendsSymbol && node.extendsSymbol.length > 0)
141
- throw new StopTraversalException();
142
- }
143
- }
144
-
145
- export class UsesMixins extends TraverseVisitor {
146
- visitInclude(node: Include): void {
147
- throw new StopTraversalException();
148
- }
149
- }
150
-
151
- export class UsesObjectComposition extends TraverseVisitor {
152
- visitAttribute(node: Attribute): void {
153
- if (node.expression instanceof New) throw new StopTraversalException();
154
- }
155
- }
156
-
157
- export class UsesStaticMethodOverload extends TraverseVisitor {
158
- private scopes: Set<string>[] = [];
159
-
160
- visitClass(node: Class): void {
161
- this.scopes.push(new Set());
162
- node.expression.accept(this);
163
- this.scopes.pop();
164
- }
165
-
166
- visitObject(node: Object): void {
167
- this.scopes.push(new Set());
168
- node.expression.accept(this);
169
- this.scopes.pop();
170
- }
171
-
172
- visitMethod(node: Method): void {
173
- const currentScope = this.scopes[0];
174
- const methodName = node.identifier.value;
175
-
176
- if (currentScope.has(methodName)) throw new StopTraversalException();
177
- currentScope.add(methodName);
178
- }
179
- }
180
-
181
- export class UsesDynamicMethodOverload extends TraverseVisitor {
182
- visitMethod(node: Method): void {
183
- if (node.equations.length > 1) throw new StopTraversalException();
184
- }
185
- }
186
-
187
- class AbstractMethodCollector extends TraverseVisitor {
188
- public abstractMethods: Set<string> = new Set();
189
-
190
- visitMethod(node: Method): void {
191
- if (node.getMetadata<boolean>("isAbstract") === true)
192
- this.abstractMethods.add(node.identifier.value);
193
- }
194
- // stop propagation to not mix scopes
195
- visitClass(node: Class) {
196
- return;
197
- }
198
- visitObject(node: Object) {
199
- return;
200
- }
201
- }
202
-
203
- export class UsesTemplateMethod extends TraverseVisitor {
204
- private abstractMethodsStack: Set<string>[] = [];
205
-
206
- visitClass(node: Class): void {
207
- const collector = new AbstractMethodCollector();
208
- if (node.expression) executeVisitor(node.expression, collector);
209
- this.abstractMethodsStack.push(collector.abstractMethods);
210
- node.expression.accept(this);
211
- this.abstractMethodsStack.pop();
212
- }
213
-
214
- visitSend(node: Send): void {
215
- if (node.receiver instanceof Self) {
216
- if (this.abstractMethodsStack.length === 0) return;
217
- const currentAbstractMethods = this.abstractMethodsStack[0];
218
-
219
- // This doesnt match if message is complex expression
220
- if (!(node.selector instanceof SymbolPrimitive)) return;
221
- const selectorName = node.selector.value;
222
-
223
- const isMessageAbstract = currentAbstractMethods.has(selectorName);
224
-
225
- if (isMessageAbstract) throw new StopTraversalException();
226
- }
227
- }
228
- }
229
-
230
- export const objectInspections: InspectionMap = {
231
- DeclaresAttribute: (node, args) =>
232
- executeVisitor(node, new DeclaresAttribute(args[0])),
233
-
234
- DeclaresClass: (node, args) =>
235
- executeVisitor(node, new DeclaresClass(args[0])),
236
-
237
- DeclaresInterface: (node, args) =>
238
- executeVisitor(node, new DeclaresInterface(args[0])),
239
-
240
- DeclaresMethod: (node, args) =>
241
- executeVisitor(node, new DeclaresMethod(args[0])),
242
-
243
- DeclaresObject: (node, args) =>
244
- executeVisitor(node, new DeclaresObject(args[0])),
245
-
246
- DeclaresPrimitive: (node, args) =>
247
- executeVisitor(node, new DeclaresPrimitive(args[0])),
248
-
249
- DeclaresSuperclass: (node, args) =>
250
- executeVisitor(node, new DeclaresSuperclass(args[0])),
251
-
252
- Implements: (node, args) => executeVisitor(node, new Implements(args[0])),
253
-
254
- Include: (node, args) => executeVisitor(node, new IncludeMixin(args[0])),
255
-
256
- Inherits: (node, args) =>
257
- executeVisitor(node, new DeclaresSuperclass(args[0])),
258
-
259
- Instantiates: (node, args) => executeVisitor(node, new Instantiates(args[0])),
260
-
261
- UsesDynamicPolymorphism: (node, args) =>
262
- executeVisitor(node, new UsesDynamicPolymorphism(args[0])),
263
-
264
- UsesInheritance: (node, args) => executeVisitor(node, new UsesInheritance()),
265
-
266
- UsesMixins: (node, args) => executeVisitor(node, new UsesMixins()),
267
-
268
- UsesObjectComposition: (node, args) =>
269
- executeVisitor(node, new UsesObjectComposition()),
270
-
271
- UsesStaticMethodOverload: (node, args) =>
272
- executeVisitor(node, new UsesStaticMethodOverload()),
273
-
274
- UsesDynamicMethodOverload: (node, args) =>
275
- executeVisitor(node, new UsesDynamicMethodOverload()),
276
-
277
- UsesTemplateMethod: (node, args) =>
278
- executeVisitor(node, new UsesTemplateMethod()),
279
-
280
- UsesStaticPolymorphism: (node, args) =>
281
- executeVisitor(node, new UsesStaticMethodOverload()),
282
- };
1
+ import {
2
+ Attribute,
3
+ Class,
4
+ Interface,
5
+ Method,
6
+ New,
7
+ Object,
8
+ PrimitiveMethod,
9
+ Self,
10
+ Send,
11
+ StopTraversalException,
12
+ SymbolPrimitive,
13
+ TraverseVisitor,
14
+ } from "yukigo-ast";
15
+ import { AutoScoped, ScopedVisitor, VisitorConstructor } from "../../utils.js";
16
+ @AutoScoped
17
+ export class DeclaresAttribute extends ScopedVisitor {
18
+ constructor(private attributeName: string, scope?: string) {
19
+ super(scope);
20
+ }
21
+ visitAttribute(node: Attribute): void {
22
+ if (node.identifier.value === this.attributeName)
23
+ throw new StopTraversalException();
24
+ }
25
+ }
26
+ @AutoScoped
27
+ export class DeclaresClass extends ScopedVisitor {
28
+ constructor(private className: string, scope?: string) {
29
+ super(scope);
30
+ }
31
+ visitClass(node: Class): void {
32
+ if (node.identifier.value === this.className)
33
+ throw new StopTraversalException();
34
+ }
35
+ }
36
+
37
+ export class DeclaresInterface extends TraverseVisitor {
38
+ constructor(private interfaceName: string) {
39
+ super();
40
+ }
41
+ visitInterface(node: Interface): void {
42
+ if (node.identifier.value === this.interfaceName)
43
+ throw new StopTraversalException();
44
+ }
45
+ }
46
+ @AutoScoped
47
+ export class DeclaresMethod extends ScopedVisitor {
48
+ constructor(private methodName: string, scope?: string) {
49
+ super(scope);
50
+ }
51
+ visitMethod(node: Method): void {
52
+ if (node.identifier.value === this.methodName)
53
+ throw new StopTraversalException();
54
+ }
55
+ }
56
+
57
+ export class DeclaresObject extends TraverseVisitor {
58
+ constructor(private objectName: string) {
59
+ super();
60
+ }
61
+ visitObject(node: Object): void {
62
+ if (node.identifier.value === this.objectName)
63
+ throw new StopTraversalException();
64
+ }
65
+ }
66
+ @AutoScoped
67
+ export class DeclaresPrimitive extends ScopedVisitor {
68
+ constructor(private operatorName: string, scope?: string) {
69
+ super(scope);
70
+ }
71
+ visitPrimitiveMethod(node: PrimitiveMethod): void {
72
+ if (node.operator === this.operatorName) throw new StopTraversalException();
73
+ }
74
+ }
75
+ @AutoScoped
76
+ export class DeclaresSuperclass extends ScopedVisitor {
77
+ constructor(private superclassName: string, scope?: string) {
78
+ super(scope);
79
+ }
80
+ visitClass(node: Class): void {
81
+ if (node.extendsSymbol && node.extendsSymbol.value === this.superclassName)
82
+ throw new StopTraversalException();
83
+ }
84
+ }
85
+ @AutoScoped
86
+ export class Implements extends ScopedVisitor {
87
+ constructor(private interfaceName: string, scope?: string) {
88
+ super(scope);
89
+ }
90
+ visitClass(node: Class): void {
91
+ if (
92
+ node.implementsNode &&
93
+ node.implementsNode.identifier.value === this.interfaceName
94
+ )
95
+ throw new StopTraversalException();
96
+ }
97
+ }
98
+ @AutoScoped
99
+ export class IncludeMixin extends ScopedVisitor {
100
+ constructor(private mixinsName: string, scope?: string) {
101
+ super(scope);
102
+ }
103
+ visitClass(node: Class): void {
104
+ if (node.includes.some((sym) => sym.value === this.mixinsName))
105
+ throw new StopTraversalException();
106
+ }
107
+ }
108
+ @AutoScoped
109
+ export class Instantiates extends ScopedVisitor {
110
+ constructor(private className: string, scope?: string) {
111
+ super(scope);
112
+ }
113
+ visitNew(node: New): void {
114
+ if (node.identifier.value === this.className)
115
+ throw new StopTraversalException();
116
+ }
117
+ }
118
+ @AutoScoped
119
+ export class UsesDynamicPolymorphism extends ScopedVisitor {
120
+ private count = 0;
121
+
122
+ constructor(private selectorName: string, scope?: string) {
123
+ super(scope);
124
+ }
125
+
126
+ visitMethod(node: Method): void {
127
+ if (node.identifier.value === this.selectorName) {
128
+ this.count++;
129
+ if (this.count >= 2) throw new StopTraversalException();
130
+ }
131
+ }
132
+ }
133
+ @AutoScoped
134
+ export class UsesInheritance extends ScopedVisitor {
135
+ constructor(scope?: string) {
136
+ super(scope);
137
+ }
138
+ visitClass(node: Class): void {
139
+ if (node.extendsSymbol) throw new StopTraversalException();
140
+ }
141
+ visitInterface(node: Interface): void {
142
+ if (node.extendsSymbol && node.extendsSymbol.length > 0)
143
+ throw new StopTraversalException();
144
+ }
145
+ }
146
+ @AutoScoped
147
+ export class UsesMixins extends ScopedVisitor {
148
+ constructor(scope?: string) {
149
+ super(scope);
150
+ }
151
+ visitClass(node: Class): void {
152
+ if (node.includes.length > 0) throw new StopTraversalException();
153
+ }
154
+ }
155
+ @AutoScoped
156
+ export class UsesObjectComposition extends ScopedVisitor {
157
+ constructor(scope?: string) {
158
+ super(scope);
159
+ }
160
+ visitAttribute(node: Attribute): void {
161
+ if (node.expression instanceof New) throw new StopTraversalException();
162
+ }
163
+ }
164
+
165
+ export class UsesStaticMethodOverload extends TraverseVisitor {
166
+ private scopes: Set<string>[] = [];
167
+ visitClass(node: Class): void {
168
+ this.scopes.push(new Set());
169
+ node.expression.accept(this);
170
+ this.scopes.pop();
171
+ }
172
+ visitObject(node: Object): void {
173
+ this.scopes.push(new Set());
174
+ node.expression.accept(this);
175
+ this.scopes.pop();
176
+ }
177
+
178
+ visitMethod(node: Method): void {
179
+ const currentScope = this.scopes[0];
180
+ const methodName = node.identifier.value;
181
+
182
+ if (currentScope.has(methodName)) throw new StopTraversalException();
183
+ currentScope.add(methodName);
184
+ }
185
+ }
186
+ @AutoScoped
187
+ export class UsesDynamicMethodOverload extends ScopedVisitor {
188
+ constructor(scope?: string) {
189
+ super(scope);
190
+ }
191
+
192
+ visitMethod(node: Method): void {
193
+ if (node.equations.length > 1) throw new StopTraversalException();
194
+ }
195
+ }
196
+ @AutoScoped
197
+ class AbstractMethodCollector extends ScopedVisitor {
198
+ public abstractMethods: Set<string> = new Set();
199
+ constructor(scope?: string) {
200
+ super(scope);
201
+ }
202
+ visitMethod(node: Method): void {
203
+ if (node.getMetadata<boolean>("isAbstract") === true)
204
+ this.abstractMethods.add(node.identifier.value);
205
+ }
206
+ // stop propagation to not mix scopes
207
+ visitClass(node: Class) {
208
+ return;
209
+ }
210
+ visitObject(node: Object) {
211
+ return;
212
+ }
213
+ }
214
+ @AutoScoped
215
+ export class UsesTemplateMethod extends ScopedVisitor {
216
+ private abstractMethodsStack: Set<string>[] = [];
217
+ constructor(scope?: string) {
218
+ super(scope);
219
+ }
220
+ visitClass(node: Class): void {
221
+ const collector = new AbstractMethodCollector(this.binding);
222
+ if (node.expression) node.expression.accept(collector);
223
+ this.abstractMethodsStack.push(collector.abstractMethods);
224
+ node.expression.accept(this);
225
+ this.abstractMethodsStack.pop();
226
+ }
227
+
228
+ visitSend(node: Send): void {
229
+ if (node.receiver instanceof Self) {
230
+ if (this.abstractMethodsStack.length === 0) return;
231
+ const currentAbstractMethods = this.abstractMethodsStack[0];
232
+
233
+ // This doesnt match if message is complex expression
234
+ if (!(node.selector instanceof SymbolPrimitive)) return;
235
+ const selectorName = node.selector.value;
236
+
237
+ const isMessageAbstract = currentAbstractMethods.has(selectorName);
238
+
239
+ if (isMessageAbstract) throw new StopTraversalException();
240
+ }
241
+ }
242
+ }
243
+
244
+ export const objectInspections: Record<string, VisitorConstructor> = {
245
+ DeclaresAttribute: DeclaresAttribute,
246
+ DeclaresClass: DeclaresClass,
247
+ DeclaresInterface: DeclaresInterface,
248
+ DeclaresMethod: DeclaresMethod,
249
+ DeclaresObject: DeclaresObject,
250
+ DeclaresPrimitive: DeclaresPrimitive,
251
+ DeclaresSuperclass: DeclaresSuperclass,
252
+ Implements: Implements,
253
+ IncludeMixin: IncludeMixin,
254
+ Inherits: DeclaresSuperclass, // alias for DeclaresSuperclass
255
+ Instantiates: Instantiates,
256
+ UsesDynamicPolymorphism: UsesDynamicPolymorphism,
257
+ UsesInheritance: UsesInheritance,
258
+ UsesMixins: UsesMixins,
259
+ UsesObjectComposition: UsesObjectComposition,
260
+ UsesStaticMethodOverload: UsesStaticMethodOverload,
261
+ UsesDynamicMethodOverload: UsesDynamicMethodOverload,
262
+ UsesTemplateMethod: UsesTemplateMethod,
263
+ UsesStaticPolymorphism: UsesStaticMethodOverload, // alias for UsesStaticMethodOverload
264
+ };