forked from runtimeverification/k
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathResolveFun.java
More file actions
252 lines (230 loc) · 9.58 KB
/
ResolveFun.java
File metadata and controls
252 lines (230 loc) · 9.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
// Copyright (c) 2017-2019 K Team. All Rights Reserved.
package org.kframework.compile;
import org.kframework.attributes.Att;
import org.kframework.builtin.BooleanUtils;
import org.kframework.builtin.KLabels;
import org.kframework.builtin.Sorts;
import org.kframework.definition.Context;
import org.kframework.definition.ContextAlias;
import org.kframework.definition.Module;
import org.kframework.definition.Production;
import org.kframework.definition.ProductionItem;
import org.kframework.definition.Rule;
import org.kframework.definition.Sentence;
import org.kframework.kompile.Kompile;
import org.kframework.kore.InjectedKLabel;
import org.kframework.kore.K;
import org.kframework.kore.KApply;
import org.kframework.kore.KAs;
import org.kframework.kore.KLabel;
import org.kframework.kore.KSequence;
import org.kframework.kore.KToken;
import org.kframework.kore.KVariable;
import org.kframework.kore.Sort;
import org.kframework.kore.TransformK;
import org.kframework.compile.checks.ComputeUnboundVariables;
import org.kframework.utils.errorsystem.KEMException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import static org.kframework.Collections.*;
import static org.kframework.definition.Constructors.*;
import static org.kframework.kore.KORE.*;
/**
* Resolves #fun KApplies.
*
* The rule Ctx[#fun(Pattern)(Expression)] is equivalent to the following sentences assuming some completely unique KLabel #lambda1 not used in any token:
*
* rule Ctx[#lambda1(Expression)]
* syntax K ::= #lambda1(K) [function]
* rule #lambda1(LHS) => RHS
*
* Where LHS is the LHS of Pattern and RHS is the RHS of Pattern.
*
* Note that if a variable is used in the rhs of the fun expression which is not bound in its lhs, it is added as a
* closure parameter to the generated function.
*
* We purposely resolve this construct as early as possible in the pipeline so that later stages which insert implicit
* side conditions into the rule insert them into the correct rule.
*/
public class ResolveFun {
public ResolveFun(boolean kore) {
this.kore = kore;
}
private final boolean kore;
private final Set<Production> funProds = new HashSet<>();
private final Set<Rule> funRules = new HashSet<>();
private Module module;
private final Set<KLabel> klabels = new HashSet<>();
private KLabel getUniqueLambdaLabel(String nameHint1, String nameHint2) {
if (klabels.isEmpty()) {
klabels.addAll(mutable(module.definedKLabels()));
}
int counter = 0;
KLabel freezer;
do {
freezer = KLabel("#lambda" + nameHint1 + "_" + nameHint2 + "_" + (counter++ == 0 ? "" : counter));
} while (klabels.contains(freezer));
klabels.add(freezer);
return freezer;
}
private Rule resolve(Rule rule) {
return new Rule(
transform(rule.body()),
transform(rule.requires()),
transform(rule.ensures()),
rule.att());
}
private K transform(K body) {
return new TransformK() {
@Override
public K apply(KApply k) {
KLabel lbl = k.klabel();
if (!(lbl instanceof KVariable) && lbl.name().equals("#fun2") || lbl.name().equals("#fun3") || lbl.equals(KLabels.IN_K) || lbl.equals(KLabels.NOT_IN_K)) {
String nameHint1 = "", nameHint2 = "";
K arg, body;
if (lbl.name().equals("#fun3")) {
body = KRewrite(k.items().get(0), k.items().get(1));
arg = k.items().get(2);
} else {
body = k.items().get(0);
arg = k.items().get(1);
}
if (arg instanceof KVariable) {
nameHint1 = ((KVariable) arg).name();
} else if (arg instanceof KApply
&& ((KApply) arg).klabel().name().startsWith("#SemanticCastTo")
&& ((KApply) arg).items().get(0) instanceof KVariable) {
nameHint1 = ((KVariable) ((KApply) arg).items().get(0)).name();
}
if (body instanceof KApply) {
nameHint2 = ((KApply) body).klabel().name();
}
KLabel fun = getUniqueLambdaLabel(nameHint1, nameHint2);
Sort lhsSort = sort(RewriteToTop.toLeft(body));
Sort argSort = sort(arg);
Sort lubSort = AddSortInjections.lubSort(lhsSort, argSort, null, body, module);
if (lbl.name().equals("#fun3") || lbl.name().equals("#fun2")) {
funProds.add(funProd(fun, body, lubSort));
funRules.add(funRule(fun, body, k.att()));
} else {
funProds.add(predProd(fun, body, lubSort));
funRules.add(predRule(fun, body, k.att()));
funRules.add(owiseRule(fun, body, lubSort, k.att()));
}
List<K> klist = new ArrayList<>();
klist.add(apply(arg));
klist.addAll(closure(body));
K funCall = KApply(fun, KList(klist));
if (lbl.equals(KLabels.NOT_IN_K)) {
return BooleanUtils.not(funCall);
}
return funCall;
}
return super.apply(k);
}
}.apply(body);
}
private Rule funRule(KLabel fun, K k, Att att) {
return lambdaRule(fun, k, k, att, RewriteToTop::toRight);
}
private Rule predRule(KLabel fun, K k, Att att) {
return lambdaRule(fun, k, k, att, x -> BooleanUtils.TRUE);
}
private Rule owiseRule(KLabel fun, K k, Sort arg, Att att) {
return lambdaRule(fun, KApply(KLabel("#SemanticCastTo" + arg.toString()), KVariable("_Owise")), k, att.add("owise"), x -> BooleanUtils.FALSE);
}
private Rule lambdaRule(KLabel fun, K body, K closure, Att att, UnaryOperator<K> getRHS) {
K resolved = transform(body);
K withAnonVars = new ResolveAnonVar().resolveK(resolved);
List<K> klist = new ArrayList<>();
klist.add(RewriteToTop.toLeft(withAnonVars));
klist.addAll(closure(closure));
return Rule(KRewrite(KApply(fun, KList(klist)), getRHS.apply(withAnonVars)),
BooleanUtils.TRUE, BooleanUtils.TRUE, att);
}
private List<KVariable> closure(K k) {
Set<KEMException> errors = new HashSet<>();
Set<KVariable> vars = new HashSet<>();
List<KVariable> result = new ArrayList<>();
new GatherVarsVisitor(true, errors, vars).apply(k);
new ComputeUnboundVariables(true, errors, vars, result::add).apply(k);
return result;
}
private Production funProd(KLabel fun, K k, Sort arg) {
return lambdaProd(fun, k, arg, sort(RewriteToTop.toRight(k)));
}
private Production predProd(KLabel fun, K k, Sort arg) {
return lambdaProd(fun, k, arg, Sorts.Bool());
}
private Production lambdaProd(KLabel fun, K k, Sort arg, Sort rhs) {
List<ProductionItem> pis = new ArrayList<>();
pis.add(Terminal(fun.name()));
pis.add(Terminal("("));
pis.add(NonTerminal(arg));
for (KVariable var : closure(k)) {
pis.add(Terminal(","));
pis.add(NonTerminal(var.att().getOptional(Sort.class).orElse(Sorts.K())));
}
pis.add(Terminal(")"));
return Production(fun, rhs,
immutable(pis),
Att().add("function"));
}
private Sort sort(K k) {
if (k instanceof KSequence)
return Sorts.K();
if (k instanceof KAs)
return sort(((KAs) k).pattern());
if (k instanceof InjectedKLabel)
return Sorts.KItem();
if (k instanceof KToken)
return ((KToken) k).sort();
if (k instanceof KApply) {
if (kore) {
AddSortInjections inj = new AddSortInjections(module);
return inj.sort(k, Sorts.K());
} else {
return k.att().get(Production.class).sort();
}
}
if (k instanceof KVariable)
return Sorts.K();
throw KEMException.compilerError("Could not compute sort of term", k);
}
private Context resolve(Context context) {
return new Context(
transform(context.body()),
transform(context.requires()),
context.att());
}
private ContextAlias resolve(ContextAlias context) {
return new ContextAlias(
transform(context.body()),
transform(context.requires()),
context.att());
}
public Sentence resolve(Sentence s) {
if (s instanceof Rule) {
return resolve((Rule) s);
} else if (s instanceof Context) {
return resolve((Context) s);
} else if (s instanceof ContextAlias) {
return resolve((ContextAlias) s);
} else {
return s;
}
}
public Module resolve(Module m) {
module = Kompile.subsortKItem(m);
funProds.clear();
funRules.clear();
Set<Sentence> newSentences = stream(m.localSentences()).map(this::resolve).collect(Collectors.toSet());
newSentences.addAll(funProds);
newSentences.addAll(funRules);
return Module(m.name(), m.imports(), immutable(newSentences), m.att());
}
}