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.
- package/.mocharc.json +3 -3
- package/CHANGELOG.md +26 -0
- package/README.md +193 -199
- package/dist/analyzer/GraphBuilder.d.ts +29 -0
- package/dist/analyzer/GraphBuilder.js +99 -0
- package/dist/analyzer/index.d.ts +11 -23
- package/dist/analyzer/index.js +100 -58
- package/dist/analyzer/inspections/functional/functional.d.ts +44 -0
- package/dist/analyzer/inspections/functional/functional.js +149 -0
- package/dist/analyzer/inspections/functional/smells.d.ts +16 -0
- package/dist/analyzer/inspections/functional/smells.js +98 -0
- package/dist/analyzer/inspections/{generic.d.ts → generic/generic.d.ts} +70 -43
- package/dist/analyzer/inspections/generic/generic.js +604 -0
- package/dist/analyzer/inspections/generic/smells.d.ts +61 -0
- package/dist/analyzer/inspections/generic/smells.js +349 -0
- package/dist/analyzer/inspections/imperative/imperative.d.ts +35 -0
- package/dist/analyzer/inspections/imperative/imperative.js +109 -0
- package/dist/analyzer/inspections/imperative/smells.d.ts +16 -0
- package/dist/analyzer/inspections/imperative/smells.js +58 -0
- package/dist/analyzer/inspections/logic/logic.d.ts +32 -0
- package/dist/analyzer/inspections/logic/logic.js +96 -0
- package/dist/analyzer/inspections/logic/smells.d.ts +15 -0
- package/dist/analyzer/inspections/logic/smells.js +60 -0
- package/dist/analyzer/inspections/object/object.d.ts +88 -0
- package/dist/analyzer/inspections/object/object.js +319 -0
- package/dist/analyzer/inspections/object/smells.d.ts +30 -0
- package/dist/analyzer/inspections/object/smells.js +135 -0
- package/dist/analyzer/utils.d.ts +26 -4
- package/dist/analyzer/utils.js +71 -13
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/interpreter/components/EnvBuilder.d.ts +9 -5
- package/dist/interpreter/components/EnvBuilder.js +100 -30
- package/dist/interpreter/components/Operations.d.ts +4 -4
- package/dist/interpreter/components/Operations.js +17 -2
- package/dist/interpreter/components/PatternMatcher.d.ts +47 -17
- package/dist/interpreter/components/PatternMatcher.js +264 -119
- package/dist/interpreter/components/RuntimeContext.d.ts +35 -0
- package/dist/interpreter/components/RuntimeContext.js +93 -0
- package/dist/interpreter/components/TestRunner.d.ts +18 -0
- package/dist/interpreter/components/TestRunner.js +103 -0
- package/dist/interpreter/components/Visitor.d.ts +63 -57
- package/dist/interpreter/components/Visitor.js +508 -173
- package/dist/interpreter/components/logic/LogicEngine.d.ts +29 -0
- package/dist/interpreter/components/logic/LogicEngine.js +259 -0
- package/dist/interpreter/components/logic/LogicResolver.d.ts +53 -0
- package/dist/interpreter/components/logic/LogicResolver.js +471 -0
- package/dist/interpreter/components/logic/LogicTranslator.d.ts +14 -0
- package/dist/interpreter/components/logic/LogicTranslator.js +99 -0
- package/dist/interpreter/components/runtimes/FunctionRuntime.d.ts +12 -0
- package/dist/interpreter/components/runtimes/FunctionRuntime.js +147 -0
- package/dist/interpreter/components/runtimes/LazyRuntime.d.ts +19 -0
- package/dist/interpreter/components/runtimes/LazyRuntime.js +269 -0
- package/dist/interpreter/components/runtimes/ObjectRuntime.d.ts +35 -0
- package/dist/interpreter/components/runtimes/ObjectRuntime.js +126 -0
- package/dist/interpreter/entities.d.ts +105 -0
- package/dist/interpreter/entities.js +96 -0
- package/dist/interpreter/errors.d.ts +1 -1
- package/dist/interpreter/index.d.ts +4 -12
- package/dist/interpreter/index.js +10 -13
- package/dist/interpreter/trampoline.d.ts +17 -0
- package/dist/interpreter/trampoline.js +38 -0
- package/dist/interpreter/utils.d.ts +4 -7
- package/dist/interpreter/utils.js +25 -17
- package/dist/tester/index.d.ts +25 -0
- package/dist/tester/index.js +108 -0
- package/dist/utils/helpers.d.ts +0 -4
- package/dist/utils/helpers.js +20 -24
- package/package.json +2 -2
- package/src/analyzer/GraphBuilder.ts +142 -0
- package/src/analyzer/index.ts +185 -132
- package/src/analyzer/inspections/functional/functional.ts +121 -0
- package/src/analyzer/inspections/functional/smells.ts +102 -0
- package/src/analyzer/inspections/{generic.ts → generic/generic.ts} +581 -499
- package/src/analyzer/inspections/generic/smells.ts +365 -0
- package/src/analyzer/inspections/imperative/imperative.ts +101 -0
- package/src/analyzer/inspections/imperative/smells.ts +54 -0
- package/src/analyzer/inspections/logic/logic.ts +90 -0
- package/src/analyzer/inspections/logic/smells.ts +54 -0
- package/src/analyzer/inspections/{object.ts → object/object.ts} +264 -282
- package/src/analyzer/inspections/object/smells.ts +144 -0
- package/src/analyzer/utils.ts +109 -26
- package/src/index.ts +3 -2
- package/src/interpreter/components/EnvBuilder.ts +202 -97
- package/src/interpreter/components/Operations.ts +99 -81
- package/src/interpreter/components/PatternMatcher.ts +475 -254
- package/src/interpreter/components/RuntimeContext.ts +119 -0
- package/src/interpreter/components/TestRunner.ts +151 -0
- package/src/interpreter/components/Visitor.ts +1065 -493
- package/src/interpreter/components/logic/LogicEngine.ts +519 -0
- package/src/interpreter/components/logic/LogicResolver.ts +858 -0
- package/src/interpreter/components/logic/LogicTranslator.ts +149 -0
- package/src/interpreter/components/runtimes/FunctionRuntime.ts +227 -0
- package/src/interpreter/components/runtimes/LazyRuntime.ts +334 -0
- package/src/interpreter/components/runtimes/ObjectRuntime.ts +224 -0
- package/src/interpreter/errors.ts +47 -47
- package/src/interpreter/index.ts +52 -59
- package/src/interpreter/trampoline.ts +71 -0
- package/src/interpreter/utils.ts +84 -79
- package/src/tester/index.ts +128 -0
- package/src/utils/helpers.ts +67 -73
- package/tests/analyzer/functional.spec.ts +207 -221
- package/tests/analyzer/generic.spec.ts +178 -100
- package/tests/analyzer/helpers.spec.ts +83 -83
- package/tests/analyzer/logic.spec.ts +237 -292
- package/tests/analyzer/oop.spec.ts +323 -338
- package/tests/analyzer/transitive.spec.ts +166 -0
- package/tests/interpreter/EnvBuilder.spec.ts +183 -178
- package/tests/interpreter/FunctionRuntime.spec.ts +223 -234
- package/tests/interpreter/LazyRuntime.spec.ts +225 -190
- package/tests/interpreter/LogicEngine.spec.ts +327 -194
- package/tests/interpreter/LogicSubstitution.spec.ts +80 -0
- package/tests/interpreter/ObjectRuntime.spec.ts +606 -0
- package/tests/interpreter/Operations.spec.ts +220 -220
- package/tests/interpreter/PatternSystem.spec.ts +213 -189
- package/tests/interpreter/Tests.spec.ts +122 -0
- package/tests/interpreter/interpreter.spec.ts +991 -937
- package/tests/tester/Tester.spec.ts +153 -0
- package/tsconfig.build.json +15 -7
- package/tsconfig.json +25 -17
- package/dist/analyzer/inspections/functional.d.ts +0 -46
- package/dist/analyzer/inspections/functional.js +0 -123
- package/dist/analyzer/inspections/generic.js +0 -427
- package/dist/analyzer/inspections/imperative.d.ts +0 -37
- package/dist/analyzer/inspections/imperative.js +0 -105
- package/dist/analyzer/inspections/logic.d.ts +0 -49
- package/dist/analyzer/inspections/logic.js +0 -140
- package/dist/analyzer/inspections/object.d.ts +0 -83
- package/dist/analyzer/inspections/object.js +0 -235
- package/dist/interpreter/components/FunctionRuntime.d.ts +0 -8
- package/dist/interpreter/components/FunctionRuntime.js +0 -52
- package/dist/interpreter/components/LazyRuntime.d.ts +0 -7
- package/dist/interpreter/components/LazyRuntime.js +0 -75
- package/dist/interpreter/components/LogicEngine.d.ts +0 -21
- package/dist/interpreter/components/LogicEngine.js +0 -152
- package/dist/interpreter/components/LogicResolver.d.ts +0 -11
- package/dist/interpreter/components/LogicResolver.js +0 -87
- package/src/analyzer/inspections/functional.ts +0 -159
- package/src/analyzer/inspections/imperative.ts +0 -129
- package/src/analyzer/inspections/logic.ts +0 -166
- package/src/interpreter/components/FunctionRuntime.ts +0 -79
- package/src/interpreter/components/LazyRuntime.ts +0 -97
- package/src/interpreter/components/LogicEngine.ts +0 -227
- package/src/interpreter/components/LogicResolver.ts +0 -130
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
import { Exist, Goal, LiteralPattern, SymbolPrimitive, Variable, VariablePattern, } from "@yukigo/ast";
|
|
2
|
-
import { solveGoal, success, } from "./LogicResolver.js";
|
|
3
|
-
import { PatternResolver } from "./PatternMatcher.js";
|
|
4
|
-
import { createStream } from "../utils.js";
|
|
5
|
-
import { InterpreterError } from "../errors.js";
|
|
6
|
-
export class LogicEngine {
|
|
7
|
-
env;
|
|
8
|
-
config;
|
|
9
|
-
evaluator;
|
|
10
|
-
constructor(env, config, evaluator) {
|
|
11
|
-
this.env = env;
|
|
12
|
-
this.config = config;
|
|
13
|
-
this.evaluator = evaluator;
|
|
14
|
-
}
|
|
15
|
-
solveQuery(node) {
|
|
16
|
-
return this.evaluator.evaluate(node.expression);
|
|
17
|
-
}
|
|
18
|
-
solveGoal(node) {
|
|
19
|
-
const patterns = node.args;
|
|
20
|
-
const generator = solveGoal(this.env, node.identifier.value, patterns, (body, substs) => this.solveConjunction(body, substs));
|
|
21
|
-
return this.handleOutputMode(generator);
|
|
22
|
-
}
|
|
23
|
-
solveFindall(node) {
|
|
24
|
-
if (!(node.goal instanceof Goal))
|
|
25
|
-
throw new InterpreterError("solveFindall", "Findall expects a Goal");
|
|
26
|
-
const goalPatterns = node.goal.args.map((arg) => {
|
|
27
|
-
return this.expressionToPattern(arg);
|
|
28
|
-
});
|
|
29
|
-
const generator = solveGoal(this.env, node.goal.identifier.value, goalPatterns, (b, s) => this.solveConjunction(b, s));
|
|
30
|
-
const results = [];
|
|
31
|
-
for (const res of generator)
|
|
32
|
-
results.push(this.instantiateTemplate(node.template, res.substs));
|
|
33
|
-
return results;
|
|
34
|
-
}
|
|
35
|
-
solveExist(node) {
|
|
36
|
-
const generator = solveGoal(this.env, node.identifier.value, node.patterns, (body, substs) => this.solveConjunction(body, substs));
|
|
37
|
-
return this.handleOutputMode(generator);
|
|
38
|
-
}
|
|
39
|
-
*solveConjunction(expressions, substs) {
|
|
40
|
-
if (expressions.length === 0) {
|
|
41
|
-
yield success(substs);
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
|
-
const [head, ...tail] = expressions;
|
|
45
|
-
let headGen = null;
|
|
46
|
-
if (head instanceof Goal) {
|
|
47
|
-
const args = head.args.map((arg) => this.instantiateExpressionAsPattern(arg, substs));
|
|
48
|
-
headGen = solveGoal(this.env, head.identifier.value, args, (b, s) => this.solveConjunction(b, s));
|
|
49
|
-
}
|
|
50
|
-
else if (head instanceof Exist) {
|
|
51
|
-
const patterns = head.patterns.map((pat) => this.substitutePattern(pat, substs));
|
|
52
|
-
headGen = solveGoal(this.env, head.identifier.value, patterns, (b, s) => this.solveConjunction(b, s));
|
|
53
|
-
}
|
|
54
|
-
if (headGen) {
|
|
55
|
-
// backtracking
|
|
56
|
-
for (const headResult of headGen) {
|
|
57
|
-
const newSubsts = new Map([...substs, ...headResult.substs]);
|
|
58
|
-
yield* this.solveConjunction(tail, newSubsts);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
else {
|
|
62
|
-
// imperative
|
|
63
|
-
const result = this.evaluator.evaluate(head);
|
|
64
|
-
if (result)
|
|
65
|
-
yield* this.solveConjunction(tail, substs);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
expressionToPattern(expr) {
|
|
69
|
-
if (expr instanceof VariablePattern)
|
|
70
|
-
return expr;
|
|
71
|
-
if (expr instanceof Variable) {
|
|
72
|
-
const name = expr.identifier.value;
|
|
73
|
-
if (/^[A-Z_]/.test(name))
|
|
74
|
-
return new VariablePattern(expr.identifier);
|
|
75
|
-
}
|
|
76
|
-
try {
|
|
77
|
-
const val = this.evaluator.evaluate(expr);
|
|
78
|
-
return this.primitiveToPattern(val);
|
|
79
|
-
}
|
|
80
|
-
catch (e) {
|
|
81
|
-
if (expr instanceof Variable)
|
|
82
|
-
return new VariablePattern(expr.identifier);
|
|
83
|
-
throw e;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
primitiveToPattern(val) {
|
|
87
|
-
if (typeof val === "number" ||
|
|
88
|
-
typeof val === "string" ||
|
|
89
|
-
typeof val === "boolean")
|
|
90
|
-
return new LiteralPattern(new SymbolPrimitive(String(val)));
|
|
91
|
-
// TODO: Manejar arrays/listas complejas si es necesario
|
|
92
|
-
throw new InterpreterError("primitiveToPattern", `Cannot convert value ${val} to Logic Pattern`);
|
|
93
|
-
}
|
|
94
|
-
instantiateExpressionAsPattern(expr, substs) {
|
|
95
|
-
const patternBase = this.expressionToPattern(expr);
|
|
96
|
-
return this.substitutePattern(patternBase, substs);
|
|
97
|
-
}
|
|
98
|
-
substitutePattern(pat, substs, visited = new Set()) {
|
|
99
|
-
if (pat instanceof VariablePattern) {
|
|
100
|
-
const name = pat.name.value;
|
|
101
|
-
if (visited.has(name))
|
|
102
|
-
return pat;
|
|
103
|
-
const val = substs.get(name);
|
|
104
|
-
if (val) {
|
|
105
|
-
const newVisited = new Set(visited);
|
|
106
|
-
newVisited.add(name);
|
|
107
|
-
return this.substitutePattern(val, substs, newVisited);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
return pat;
|
|
111
|
-
}
|
|
112
|
-
instantiateTemplate(template, substs) {
|
|
113
|
-
const pat = this.instantiateExpressionAsPattern(template, substs);
|
|
114
|
-
if (pat instanceof LiteralPattern)
|
|
115
|
-
return this.evaluator.evaluate(pat.name);
|
|
116
|
-
throw new Error("Complex template instantiation not fully implemented");
|
|
117
|
-
}
|
|
118
|
-
handleOutputMode(gen) {
|
|
119
|
-
const mode = this.config.outputMode || "first";
|
|
120
|
-
switch (mode) {
|
|
121
|
-
case "stream": {
|
|
122
|
-
const self = this;
|
|
123
|
-
return createStream(function* () {
|
|
124
|
-
for (const res of gen)
|
|
125
|
-
yield self.formatLogicResult(res.substs);
|
|
126
|
-
});
|
|
127
|
-
}
|
|
128
|
-
case "all": {
|
|
129
|
-
const res = [];
|
|
130
|
-
for (const r of gen)
|
|
131
|
-
res.push(this.formatLogicResult(r.substs));
|
|
132
|
-
return res;
|
|
133
|
-
}
|
|
134
|
-
case "first": {
|
|
135
|
-
const next = gen.next();
|
|
136
|
-
if (next.done)
|
|
137
|
-
return false;
|
|
138
|
-
return this.formatLogicResult(next.value.substs);
|
|
139
|
-
}
|
|
140
|
-
default:
|
|
141
|
-
throw new InterpreterError("handleOutputMode", `Unsupported mode: ${mode}. Supported modes: all | stream | first`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
formatLogicResult(substs) {
|
|
145
|
-
const solutions = new Map();
|
|
146
|
-
const resolver = new PatternResolver();
|
|
147
|
-
substs.forEach((pattern, key) => {
|
|
148
|
-
solutions.set(key, pattern.accept(resolver));
|
|
149
|
-
});
|
|
150
|
-
return { success: true, solutions };
|
|
151
|
-
}
|
|
152
|
-
}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { Expression, Pattern } from "@yukigo/ast";
|
|
2
|
-
import { EnvStack } from "../index.js";
|
|
3
|
-
export type Substitution = Map<string, Pattern>;
|
|
4
|
-
export type InternalLogicResult = {
|
|
5
|
-
success: true;
|
|
6
|
-
substs: Substitution;
|
|
7
|
-
};
|
|
8
|
-
export type BodySolver = (expressions: Expression[], env: Substitution) => Generator<InternalLogicResult>;
|
|
9
|
-
export declare function success(substs: Substitution): InternalLogicResult;
|
|
10
|
-
export declare function solveGoal(envs: EnvStack, predicateName: string, args: Pattern[], solveBody: BodySolver): Generator<InternalLogicResult>;
|
|
11
|
-
export declare function unify(t1: Pattern, t2: Pattern, argEnv?: Substitution): Substitution | null;
|
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import { Fact, FunctorPattern, ListPattern, LiteralPattern, Rule, VariablePattern, WildcardPattern, isRuntimePredicate, } from "@yukigo/ast";
|
|
2
|
-
import { lookup } from "../utils.js";
|
|
3
|
-
import { InterpreterError } from "../errors.js";
|
|
4
|
-
export function success(substs) {
|
|
5
|
-
return { success: true, substs };
|
|
6
|
-
}
|
|
7
|
-
function unifyParameters(patterns, args) {
|
|
8
|
-
const subst = new Map();
|
|
9
|
-
for (let i = 0; i < patterns.length; i++) {
|
|
10
|
-
const match = unify(patterns[i], args[i], subst);
|
|
11
|
-
if (!match)
|
|
12
|
-
return [, false];
|
|
13
|
-
match.forEach((v, k) => subst.set(k, v));
|
|
14
|
-
}
|
|
15
|
-
return [subst, true];
|
|
16
|
-
}
|
|
17
|
-
export function* solveGoal(envs, predicateName, args, solveBody) {
|
|
18
|
-
const pred = lookup(envs, predicateName);
|
|
19
|
-
if (!pred || !isRuntimePredicate(pred))
|
|
20
|
-
return;
|
|
21
|
-
for (const clause of pred.equations) {
|
|
22
|
-
if (clause.patterns.length !== args.length)
|
|
23
|
-
continue;
|
|
24
|
-
const [substs, matches] = unifyParameters(clause.patterns, args);
|
|
25
|
-
if (!matches)
|
|
26
|
-
continue;
|
|
27
|
-
if (clause instanceof Fact) {
|
|
28
|
-
yield success(substs);
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
if (clause instanceof Rule) {
|
|
32
|
-
const bodyGenerator = solveBody(clause.expressions, substs);
|
|
33
|
-
for (const finalResult of bodyGenerator)
|
|
34
|
-
yield success(finalResult.substs);
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
throw new InterpreterError("*solveGoal", `Unexpected node: ${JSON.stringify(clause)}`);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
function resolve(node, env) {
|
|
41
|
-
if (node instanceof VariablePattern) {
|
|
42
|
-
const name = node.name.toString();
|
|
43
|
-
if (env.has(name))
|
|
44
|
-
return resolve(env.get(name), env);
|
|
45
|
-
}
|
|
46
|
-
return node;
|
|
47
|
-
}
|
|
48
|
-
export function unify(t1, t2, argEnv) {
|
|
49
|
-
const env = argEnv ?? new Map();
|
|
50
|
-
const r1 = resolve(t1, env);
|
|
51
|
-
const r2 = resolve(t2, env);
|
|
52
|
-
if (r1 === r2)
|
|
53
|
-
return env;
|
|
54
|
-
if (r1 instanceof WildcardPattern || r2 instanceof WildcardPattern)
|
|
55
|
-
return env;
|
|
56
|
-
if (r1 instanceof VariablePattern) {
|
|
57
|
-
env.set(r1.name.value, r2);
|
|
58
|
-
return env;
|
|
59
|
-
}
|
|
60
|
-
if (r2 instanceof VariablePattern) {
|
|
61
|
-
env.set(r2.name.value, r1);
|
|
62
|
-
return env;
|
|
63
|
-
}
|
|
64
|
-
if (r1 instanceof LiteralPattern && r2 instanceof LiteralPattern)
|
|
65
|
-
return r1.name.equals(r2.name) ? env : null;
|
|
66
|
-
if (r1 instanceof FunctorPattern && r2 instanceof FunctorPattern) {
|
|
67
|
-
if (r1.identifier.value !== r2.identifier.value)
|
|
68
|
-
return null;
|
|
69
|
-
if (r1.args.length !== r2.args.length)
|
|
70
|
-
return null;
|
|
71
|
-
for (let i = 0; i < r1.args.length; i++) {
|
|
72
|
-
if (!unify(r1.args[i], r2.args[i], env))
|
|
73
|
-
return null;
|
|
74
|
-
}
|
|
75
|
-
return env;
|
|
76
|
-
}
|
|
77
|
-
if (r1 instanceof ListPattern && r2 instanceof ListPattern) {
|
|
78
|
-
if (r1.elements.length !== r2.elements.length)
|
|
79
|
-
return null;
|
|
80
|
-
for (let i = 0; i < r1.elements.length; i++) {
|
|
81
|
-
if (!unify(r1.elements[i], r2.elements[i], env))
|
|
82
|
-
return null;
|
|
83
|
-
}
|
|
84
|
-
return env;
|
|
85
|
-
}
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
@@ -1,159 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ApplicationPattern,
|
|
3
|
-
AsPattern,
|
|
4
|
-
ASTNode,
|
|
5
|
-
CompositionExpression,
|
|
6
|
-
ConsPattern,
|
|
7
|
-
ConstructorPattern,
|
|
8
|
-
Fact,
|
|
9
|
-
For,
|
|
10
|
-
Function,
|
|
11
|
-
FunctorPattern,
|
|
12
|
-
GuardedBody,
|
|
13
|
-
Lambda,
|
|
14
|
-
ListComprehension,
|
|
15
|
-
ListPattern,
|
|
16
|
-
LiteralPattern,
|
|
17
|
-
Rule,
|
|
18
|
-
StopTraversalException,
|
|
19
|
-
TraverseVisitor,
|
|
20
|
-
TuplePattern,
|
|
21
|
-
UnionPattern,
|
|
22
|
-
WildcardPattern,
|
|
23
|
-
Yield,
|
|
24
|
-
} from "yukigo-ast";
|
|
25
|
-
import { InspectionMap, executeVisitor } from "../utils.js";
|
|
26
|
-
|
|
27
|
-
export class FunctionVisitor extends TraverseVisitor {
|
|
28
|
-
private readonly targetBinding: string;
|
|
29
|
-
protected isInsideTargetScope: boolean = false; // this flag helps to check nested functions inside the targetBinding scope
|
|
30
|
-
constructor(binding: string) {
|
|
31
|
-
super();
|
|
32
|
-
this.targetBinding = binding;
|
|
33
|
-
}
|
|
34
|
-
visitFunction(node: Function): void {
|
|
35
|
-
const currentFunctionName = node.identifier.value;
|
|
36
|
-
|
|
37
|
-
// if not inside scope then is top-level
|
|
38
|
-
if (!this.isInsideTargetScope) {
|
|
39
|
-
if (!this.targetBinding || currentFunctionName === this.targetBinding) {
|
|
40
|
-
this.isInsideTargetScope = true;
|
|
41
|
-
this.traverseCollection(node.equations);
|
|
42
|
-
this.isInsideTargetScope = false;
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
// if inside the scope of targetBinding then traverse
|
|
48
|
-
this.traverseCollection(node.equations);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
export class UsesComposition extends FunctionVisitor {
|
|
53
|
-
visitCompositionExpression(node: CompositionExpression): void {
|
|
54
|
-
throw new StopTraversalException();
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
export class UsesAnonymousVariable extends TraverseVisitor {
|
|
58
|
-
private readonly targetBinding: string;
|
|
59
|
-
protected isInsideTargetScope: boolean = false;
|
|
60
|
-
|
|
61
|
-
constructor(binding: string) {
|
|
62
|
-
super();
|
|
63
|
-
this.targetBinding = binding;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
visitWildcardPattern(node: WildcardPattern): void {
|
|
67
|
-
throw new StopTraversalException();
|
|
68
|
-
}
|
|
69
|
-
visitFunction(node: Function): void {
|
|
70
|
-
this.enterScope(node, node.equations);
|
|
71
|
-
}
|
|
72
|
-
visitFact(node: Fact): void {
|
|
73
|
-
this.enterScope(node, node.patterns);
|
|
74
|
-
}
|
|
75
|
-
visitRule(node: Rule): void {
|
|
76
|
-
this.enterScope(node, node.patterns);
|
|
77
|
-
}
|
|
78
|
-
private enterScope(node: Function | Fact | Rule, children: ASTNode[]): void {
|
|
79
|
-
const nodeName = node.identifier.value;
|
|
80
|
-
if (!this.isInsideTargetScope) {
|
|
81
|
-
if (!this.targetBinding || nodeName === this.targetBinding) {
|
|
82
|
-
this.isInsideTargetScope = true;
|
|
83
|
-
this.traverseCollection(children);
|
|
84
|
-
this.isInsideTargetScope = false;
|
|
85
|
-
}
|
|
86
|
-
return;
|
|
87
|
-
}
|
|
88
|
-
this.traverseCollection(children);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
export class UsesComprehension extends FunctionVisitor {
|
|
92
|
-
visitListComprehension(node: ListComprehension): void {
|
|
93
|
-
throw new StopTraversalException();
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
export class UsesGuards extends FunctionVisitor {
|
|
97
|
-
visitGuardedBody(node: GuardedBody): void {
|
|
98
|
-
throw new StopTraversalException();
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
export class UsesLambda extends FunctionVisitor {
|
|
102
|
-
visitLambda(node: Lambda): void {
|
|
103
|
-
throw new StopTraversalException();
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
export class UsesYield extends FunctionVisitor {
|
|
107
|
-
visitYield(node: Yield): void {
|
|
108
|
-
throw new StopTraversalException();
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
export class UsesPatternMatching extends FunctionVisitor {
|
|
112
|
-
visitConsPattern(node: ConsPattern): void {
|
|
113
|
-
throw new StopTraversalException();
|
|
114
|
-
}
|
|
115
|
-
visitAsPattern(node: AsPattern): void {
|
|
116
|
-
throw new StopTraversalException();
|
|
117
|
-
}
|
|
118
|
-
visitListPattern(node: ListPattern): void {
|
|
119
|
-
throw new StopTraversalException();
|
|
120
|
-
}
|
|
121
|
-
visitTuplePattern(node: TuplePattern): void {
|
|
122
|
-
throw new StopTraversalException();
|
|
123
|
-
}
|
|
124
|
-
visitLiteralPattern(node: LiteralPattern): void {
|
|
125
|
-
throw new StopTraversalException();
|
|
126
|
-
}
|
|
127
|
-
visitApplicationPattern(node: ApplicationPattern): void {
|
|
128
|
-
throw new StopTraversalException();
|
|
129
|
-
}
|
|
130
|
-
visitConstructorPattern(node: ConstructorPattern): void {
|
|
131
|
-
throw new StopTraversalException();
|
|
132
|
-
}
|
|
133
|
-
visitUnionPattern(node: UnionPattern): void {
|
|
134
|
-
throw new StopTraversalException();
|
|
135
|
-
}
|
|
136
|
-
visitFunctorPattern(node: FunctorPattern): void {
|
|
137
|
-
throw new StopTraversalException();
|
|
138
|
-
}
|
|
139
|
-
visitWildcardPattern(node: WildcardPattern): void {
|
|
140
|
-
throw new StopTraversalException();
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
export const functionalInspections: InspectionMap = {
|
|
145
|
-
UsesComposition: (node, args, binding) =>
|
|
146
|
-
executeVisitor(node, new UsesComposition(binding)),
|
|
147
|
-
UsesAnonymousVariable: (node, args, binding) =>
|
|
148
|
-
executeVisitor(node, new UsesAnonymousVariable(binding)),
|
|
149
|
-
UsesComprehension: (node, args, binding) =>
|
|
150
|
-
executeVisitor(node, new UsesComprehension(binding)),
|
|
151
|
-
UsesGuards: (node, args, binding) =>
|
|
152
|
-
executeVisitor(node, new UsesGuards(binding)),
|
|
153
|
-
UsesLambda: (node, args, binding) =>
|
|
154
|
-
executeVisitor(node, new UsesLambda(binding)),
|
|
155
|
-
UsesYield: (node, args, binding) =>
|
|
156
|
-
executeVisitor(node, new UsesYield(binding)),
|
|
157
|
-
UsesPatternMatching: (node, args, binding) =>
|
|
158
|
-
executeVisitor(node, new UsesPatternMatching(binding)),
|
|
159
|
-
};
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Enumeration,
|
|
3
|
-
ForLoop,
|
|
4
|
-
Function,
|
|
5
|
-
Procedure,
|
|
6
|
-
Repeat,
|
|
7
|
-
StopTraversalException,
|
|
8
|
-
Switch,
|
|
9
|
-
TraverseVisitor,
|
|
10
|
-
While,
|
|
11
|
-
} from "yukigo-ast";
|
|
12
|
-
import { InspectionMap, executeVisitor } from "../utils.js";
|
|
13
|
-
|
|
14
|
-
export class BindingVisitor extends TraverseVisitor {
|
|
15
|
-
private readonly targetBinding: string;
|
|
16
|
-
protected isInsideTargetScope: boolean = false; // this flag helps to check nested functions inside the targetBinding scope
|
|
17
|
-
constructor(binding: string) {
|
|
18
|
-
super();
|
|
19
|
-
this.targetBinding = binding;
|
|
20
|
-
}
|
|
21
|
-
visitProcedure(node: Procedure): void {
|
|
22
|
-
const currentFunctionName = node.identifier.value;
|
|
23
|
-
|
|
24
|
-
// if not inside scope then is top-level
|
|
25
|
-
if (!this.isInsideTargetScope) {
|
|
26
|
-
if (!this.targetBinding || currentFunctionName === this.targetBinding) {
|
|
27
|
-
this.isInsideTargetScope = true;
|
|
28
|
-
this.traverseCollection(node.equations);
|
|
29
|
-
this.isInsideTargetScope = false;
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
return;
|
|
33
|
-
}
|
|
34
|
-
// if inside the scope of targetBinding then traverse
|
|
35
|
-
this.traverseCollection(node.equations);
|
|
36
|
-
}
|
|
37
|
-
visitFunction(node: Function): void {
|
|
38
|
-
const currentFunctionName = node.identifier.value;
|
|
39
|
-
|
|
40
|
-
// if not inside scope then is top-level
|
|
41
|
-
if (!this.isInsideTargetScope) {
|
|
42
|
-
if (!this.targetBinding || currentFunctionName === this.targetBinding) {
|
|
43
|
-
this.isInsideTargetScope = true;
|
|
44
|
-
this.traverseCollection(node.equations);
|
|
45
|
-
this.isInsideTargetScope = false;
|
|
46
|
-
return;
|
|
47
|
-
}
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
// if inside the scope of targetBinding then traverse
|
|
51
|
-
this.traverseCollection(node.equations);
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export class DeclaresEnumeration extends TraverseVisitor {
|
|
56
|
-
private readonly enumName: string;
|
|
57
|
-
constructor(enumName: string) {
|
|
58
|
-
super();
|
|
59
|
-
this.enumName = enumName;
|
|
60
|
-
}
|
|
61
|
-
visitEnumeration(node: Enumeration): void {
|
|
62
|
-
if (node.identifier.value === this.enumName) throw StopTraversalException;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
export class DeclaresProcedure extends TraverseVisitor {
|
|
66
|
-
private readonly procedureName: string;
|
|
67
|
-
constructor(procedureName: string) {
|
|
68
|
-
super();
|
|
69
|
-
this.procedureName = procedureName;
|
|
70
|
-
}
|
|
71
|
-
visitProcedure(node: Procedure): void {
|
|
72
|
-
if (node.identifier.value === this.procedureName)
|
|
73
|
-
throw StopTraversalException;
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
export class UsesForLoop extends BindingVisitor {
|
|
77
|
-
visitForLoop(node: ForLoop): void {
|
|
78
|
-
throw StopTraversalException;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
export class UsesWhile extends BindingVisitor {
|
|
82
|
-
visitWhile(node: While): void {
|
|
83
|
-
throw StopTraversalException;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
export class UsesRepeat extends BindingVisitor {
|
|
87
|
-
visitRepeat(node: Repeat): void {
|
|
88
|
-
throw StopTraversalException;
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
export class UsesLoop extends BindingVisitor {
|
|
92
|
-
visitForLoop(node: ForLoop): void {
|
|
93
|
-
throw StopTraversalException;
|
|
94
|
-
}
|
|
95
|
-
visitWhile(node: While): void {
|
|
96
|
-
throw StopTraversalException;
|
|
97
|
-
}
|
|
98
|
-
visitRepeat(node: Repeat): void {
|
|
99
|
-
throw StopTraversalException;
|
|
100
|
-
}
|
|
101
|
-
// visitForEach(node: ForEach): void {
|
|
102
|
-
// throw StopTraversalException;
|
|
103
|
-
// }
|
|
104
|
-
}
|
|
105
|
-
export class UsesSwitch extends BindingVisitor {
|
|
106
|
-
visitSwitch(node: Switch): void {
|
|
107
|
-
throw StopTraversalException;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
export const imperativeInspections: InspectionMap = {
|
|
112
|
-
DeclaresEnumeration: (node, args) =>
|
|
113
|
-
executeVisitor(node, new DeclaresEnumeration(args[0])),
|
|
114
|
-
DeclaresProcedure: (node, args) =>
|
|
115
|
-
executeVisitor(node, new DeclaresProcedure(args[0])),
|
|
116
|
-
UsesForEach: (node, args) => {
|
|
117
|
-
throw Error("Inspection not implemented");
|
|
118
|
-
},
|
|
119
|
-
UsesForLoop: (node, args, binding) =>
|
|
120
|
-
executeVisitor(node, new UsesForLoop(binding)),
|
|
121
|
-
UsesRepeat: (node, args, binding) =>
|
|
122
|
-
executeVisitor(node, new UsesRepeat(binding)),
|
|
123
|
-
UsesWhile: (node, args, binding) =>
|
|
124
|
-
executeVisitor(node, new UsesWhile(binding)),
|
|
125
|
-
UsesLoop: (node, args, binding) =>
|
|
126
|
-
executeVisitor(node, new UsesLoop(binding)),
|
|
127
|
-
UsesSwitch: (node, args, binding) =>
|
|
128
|
-
executeVisitor(node, new UsesSwitch(binding)),
|
|
129
|
-
};
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
Assignment,
|
|
3
|
-
AssignOperation,
|
|
4
|
-
Exist,
|
|
5
|
-
Fact,
|
|
6
|
-
Findall,
|
|
7
|
-
Forall,
|
|
8
|
-
Not,
|
|
9
|
-
Rule,
|
|
10
|
-
StopTraversalException,
|
|
11
|
-
SymbolPrimitive,
|
|
12
|
-
TraverseVisitor,
|
|
13
|
-
UnifyOperation,
|
|
14
|
-
} from "yukigo-ast";
|
|
15
|
-
import { InspectionMap, executeVisitor } from "../utils.js";
|
|
16
|
-
import { isYukigoPrimitive } from "yukigo-ast";
|
|
17
|
-
|
|
18
|
-
export abstract class DeclaresBinding extends TraverseVisitor {
|
|
19
|
-
protected readonly targetBinding: string;
|
|
20
|
-
|
|
21
|
-
constructor(binding: string) {
|
|
22
|
-
super();
|
|
23
|
-
this.targetBinding = binding;
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
export class DeclaresFact extends DeclaresBinding {
|
|
27
|
-
visitFact(node: Fact): void {
|
|
28
|
-
const bindingName = node.identifier.value;
|
|
29
|
-
if (!this.targetBinding || bindingName === this.targetBinding)
|
|
30
|
-
throw new StopTraversalException();
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
export class DeclaresRule extends DeclaresBinding {
|
|
34
|
-
visitRule(node: Rule): void {
|
|
35
|
-
const bindingName = node.identifier.value;
|
|
36
|
-
if (!this.targetBinding || bindingName === this.targetBinding)
|
|
37
|
-
throw new StopTraversalException();
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
export class DeclaresPredicate extends DeclaresBinding {
|
|
41
|
-
visitFact(node: Fact): void {
|
|
42
|
-
new DeclaresFact(this.targetBinding).visitFact(node);
|
|
43
|
-
}
|
|
44
|
-
visitRule(node: Rule): void {
|
|
45
|
-
new DeclaresRule(this.targetBinding).visitRule(node);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
export class PredicateVisitor extends TraverseVisitor {
|
|
50
|
-
private readonly targetBinding: string;
|
|
51
|
-
protected isInsideTargetScope: boolean = false; // this flag helps to check nested functions inside the targetBinding scope
|
|
52
|
-
constructor(binding: string) {
|
|
53
|
-
super();
|
|
54
|
-
this.targetBinding = binding;
|
|
55
|
-
}
|
|
56
|
-
visitFact(node: Fact): void {
|
|
57
|
-
const nodeName = node.identifier.value;
|
|
58
|
-
if (!this.isInsideTargetScope) {
|
|
59
|
-
if (nodeName === this.targetBinding) {
|
|
60
|
-
this.isInsideTargetScope = true;
|
|
61
|
-
this.traverseCollection(node.patterns);
|
|
62
|
-
this.isInsideTargetScope = false;
|
|
63
|
-
}
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
this.traverseCollection(node.patterns);
|
|
67
|
-
}
|
|
68
|
-
visitRule(node: Rule): void {
|
|
69
|
-
const nodeName = node.identifier.value;
|
|
70
|
-
if (!this.isInsideTargetScope) {
|
|
71
|
-
if (nodeName === this.targetBinding) {
|
|
72
|
-
this.isInsideTargetScope = true;
|
|
73
|
-
this.traverseCollection(node.expressions);
|
|
74
|
-
this.isInsideTargetScope = false;
|
|
75
|
-
}
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
this.traverseCollection(node.expressions);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export class UsesFindall extends TraverseVisitor {
|
|
83
|
-
visitFindall(node: Findall): void {
|
|
84
|
-
throw new StopTraversalException();
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
export class UsesForall extends TraverseVisitor {
|
|
88
|
-
visitForall(node: Forall): void {
|
|
89
|
-
throw new StopTraversalException();
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
export class UsesNot extends TraverseVisitor {
|
|
93
|
-
visitNot(node: Not): void {
|
|
94
|
-
throw new StopTraversalException();
|
|
95
|
-
}
|
|
96
|
-
visitExist(node: Exist): void {
|
|
97
|
-
if (node.identifier.value === "not") throw new StopTraversalException();
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
export class UsesUnificationOperator extends PredicateVisitor {
|
|
101
|
-
visitUnifyOperation(node: UnifyOperation): void {
|
|
102
|
-
throw new StopTraversalException();
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
export class UsesCut extends PredicateVisitor {
|
|
106
|
-
visitExist(node: Exist): void {
|
|
107
|
-
if (node.identifier.value === "!") throw new StopTraversalException();
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
export class UsesFail extends PredicateVisitor {
|
|
111
|
-
visitExist(node: Exist): void {
|
|
112
|
-
if (node.identifier.value === "fail") throw new StopTraversalException();
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
export class HasRedundantReduction extends TraverseVisitor {
|
|
116
|
-
private readonly targetBinding: string;
|
|
117
|
-
protected isInsideTargetScope: boolean = false;
|
|
118
|
-
|
|
119
|
-
constructor(binding: string) {
|
|
120
|
-
super();
|
|
121
|
-
this.targetBinding = binding;
|
|
122
|
-
}
|
|
123
|
-
visitRule(node: Rule): void {
|
|
124
|
-
// Only inspect the specified rule if a binding is provided
|
|
125
|
-
if (this.targetBinding && node.identifier.value !== this.targetBinding)
|
|
126
|
-
return;
|
|
127
|
-
|
|
128
|
-
// Check each unification in the rule's body
|
|
129
|
-
for (const bodyElement of node.expressions) {
|
|
130
|
-
if (bodyElement instanceof AssignOperation) {
|
|
131
|
-
const left = bodyElement.left;
|
|
132
|
-
const right = bodyElement.right;
|
|
133
|
-
|
|
134
|
-
if (!(left instanceof SymbolPrimitive)) continue;
|
|
135
|
-
|
|
136
|
-
const redundantReductionParameters = isYukigoPrimitive(right);
|
|
137
|
-
const redundantReductionFunctors = right instanceof Exist;
|
|
138
|
-
|
|
139
|
-
// Check if reduction is redundant
|
|
140
|
-
const isRedundant =
|
|
141
|
-
redundantReductionParameters || redundantReductionFunctors;
|
|
142
|
-
|
|
143
|
-
if (isRedundant) throw new StopTraversalException();
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
export const logicInspections: InspectionMap = {
|
|
150
|
-
DeclaresFact: (node, args, binding) =>
|
|
151
|
-
executeVisitor(node, new DeclaresFact(binding)),
|
|
152
|
-
DeclaresRule: (node, args, binding) =>
|
|
153
|
-
executeVisitor(node, new DeclaresRule(binding)),
|
|
154
|
-
DeclaresPredicate: (node, args, binding) =>
|
|
155
|
-
executeVisitor(node, new DeclaresPredicate(binding)),
|
|
156
|
-
UsesFindall: (node, args, binding) => executeVisitor(node, new UsesFindall()),
|
|
157
|
-
UsesForall: (node, args, binding) => executeVisitor(node, new UsesForall()),
|
|
158
|
-
UsesNot: (node, args, binding) => executeVisitor(node, new UsesNot()),
|
|
159
|
-
UsesUnificationOperator: (node, args, binding) =>
|
|
160
|
-
executeVisitor(node, new UsesUnificationOperator(binding)),
|
|
161
|
-
UsesCut: (node, args, binding) => executeVisitor(node, new UsesCut(binding)),
|
|
162
|
-
UsesFail: (node, args, binding) =>
|
|
163
|
-
executeVisitor(node, new UsesFail(binding)),
|
|
164
|
-
HasRedundantReduction: (node, args, binding) =>
|
|
165
|
-
executeVisitor(node, new HasRedundantReduction(binding)),
|
|
166
|
-
};
|