Skip to content

Commit 16dc654

Browse files
author
Killian Perlin
committed
Implement selector translation
1 parent adba243 commit 16dc654

File tree

5 files changed

+148
-0
lines changed

5 files changed

+148
-0
lines changed

lkql_jit/options/src/main/java/com/adacore/lkql_jit/options/Refactorings/LKQLToLkt.java

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111

1212
public class LKQLToLkt implements Refactoring {
1313

14+
/** Pointer to last-entered selector during rewriting. */
15+
private Liblkqllang.SelectorDecl currentSelector = Liblkqllang.SelectorDecl.NONE;
16+
1417
@Override
1518
public void applyRefactor(Refactoring.State state) {
1619
final var root = state.unit.getRoot();
@@ -30,11 +33,15 @@ private String refactorNode(Liblkqllang.LkqlNode node) {
3033
case Liblkqllang.ParameterDecl paramDecl -> refactorParamDecl(paramDecl);
3134
case Liblkqllang.Match match -> refactorMatch(match);
3235
case Liblkqllang.MatchArm arm -> refactorArm(arm, arm.fPattern(), arm.fExpr());
36+
case Liblkqllang.SelectorArm arm -> refactorArm(arm, arm.fPattern(), arm.fExpr());
3337
case Liblkqllang.SelectorDecl selectorDecl -> refactorSelectorDecl(selectorDecl);
38+
case Liblkqllang.RecExpr recExpr -> refactorRecExpr(recExpr);
3439
case Liblkqllang.BlockBodyExpr bbe -> "var _ = " + refactorGeneric(bbe);
40+
case Liblkqllang.UnitLiteral _ -> "Unit()";
3541
case Liblkqllang.Expr expr when (
3642
expr.parent() instanceof Liblkqllang.TopLevelList
3743
) -> "val _ = " + refactorGeneric(expr);
44+
case Liblkqllang.UniversalPattern _ -> "_";
3845
default -> refactorGeneric(node);
3946
};
4047
}
@@ -185,4 +192,86 @@ private String refactorArm(
185192
textRange(expr.tokenEnd().next(), arm.tokenEnd())
186193
);
187194
}
195+
196+
/*
197+
*
198+
* <annotations> selector <name> <docstring> <arms>
199+
*
200+
* <docstring>\n
201+
* <annotations> fun <name> (this : Any) : Any = match this { <arms> }
202+
*
203+
*/
204+
private String refactorSelectorDecl(Liblkqllang.SelectorDecl selectorDecl) {
205+
// save selector state on entering this function
206+
var previousSelector = currentSelector;
207+
// set new state for nested refactors
208+
currentSelector = selectorDecl;
209+
var s = "";
210+
211+
// pull docstring before declaration
212+
if (!selectorDecl.fDocNode().isNone()) s = refactorNode(selectorDecl.fDocNode()) + "\n";
213+
214+
if (!selectorDecl.fAnnotation().isNone()) s +=
215+
refactorNode(selectorDecl.fAnnotation()) +
216+
selectorDecl.fAnnotation().tokenEnd().next().getText();
217+
218+
final var whitespace = textRange(
219+
(selectorDecl.fDocNode().isNone()
220+
? selectorDecl.fName().tokenEnd().next()
221+
: selectorDecl.fDocNode().tokenEnd().next()),
222+
selectorDecl.fArms().tokenStart().previous()
223+
);
224+
225+
s +=
226+
"fun " +
227+
refactorNode(selectorDecl.fName()) +
228+
"(this : Any) : Any = match this {" +
229+
whitespace +
230+
refactorNode(selectorDecl.fArms()) +
231+
"\n}\n";
232+
233+
// restore previous state on exiting this function
234+
currentSelector = previousSelector;
235+
return s;
236+
}
237+
238+
/*
239+
*
240+
* 1) Expansion of implicit argument
241+
*
242+
* rec(<expr>) --> rec(<expr>, <expr>)
243+
*
244+
* 2) Case disjonction
245+
*
246+
* rec( <left>, <right>) --> <right> :: <selector>(<left>)
247+
* rec(*<left>, <right>) --> <right> :: <left>.iterator.flatMap(<selector>)
248+
* rec( <left>, *<right>) --> <right>.iterator ::: <selector>(<left>)
249+
* rec(*<left>, *<right>) --> <right>.iterator ::: <left>.iterator.flatMap(<selector>)
250+
*
251+
*/
252+
private String refactorRecExpr(Liblkqllang.RecExpr recExpr) {
253+
final var hasRight = !recExpr.fResultExpr().isNone();
254+
255+
final var unpackLeft = recExpr.fRecurseUnpack().pAsBool();
256+
final var unpackRight = hasRight ? recExpr.fResultUnpack().pAsBool() : unpackLeft;
257+
258+
final var left = recExpr.fRecurseExpr();
259+
final var right = hasRight ? recExpr.fResultExpr() : left;
260+
261+
var s = unpackRight ? refactorNode(right) + ".iterator :::" : refactorNode(right) + " ::";
262+
263+
// try to preserve spacing after "," (any newline for example)
264+
if (hasRight && left.tokenEnd().next().getText().equals(",")) {
265+
for (var tok = left.tokenEnd().next().next(); tok.isTrivia(); tok = tok.next()) s +=
266+
tok.getText();
267+
} else {
268+
s += " ";
269+
}
270+
271+
s += unpackLeft
272+
? refactorNode(left) + ".iterator.flatMap(" + currentSelector.fName().getText() + ")"
273+
: currentSelector.fName().getText() + "(" + refactorNode(left) + ")";
274+
275+
return s;
276+
}
188277
}

testsuite/drivers/refactor_driver.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,6 @@ def run(self) -> None:
2727
"input.lkql",
2828
]
2929
)
30+
31+
if self.test_env["refactoring"] == "TO_LKQL_V2":
32+
self.check_run(["lkt_parse", "-s", "-f", "test.out"])
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
selector parents
2+
| AdaNode => rec(this.parent, this)
3+
| * => ()
4+
5+
selector super_types
6+
| BaseTypeDecl => rec(*this.p_base_types())
7+
| * => ()
8+
9+
selector children
10+
| AdaNode => rec(*this.children ,this)
11+
| * => ()
12+
13+
selector foo
14+
| Foo => rec(this, *[s, o, m, e, t, h, i, n, g])
15+
16+
selector infinite_sequence
17+
|" Infinite sequence generator
18+
| nb => rec(
19+
nb + 1, # Recurse with value nb + 1
20+
nb # Add nb to the result list
21+
)
22+
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# lkql version: 2
2+
3+
fun parents(this : Any) : Any = match this {
4+
case AdaNode => this :: parents(this.parent)
5+
case _ => Unit()
6+
}
7+
8+
9+
fun super_types(this : Any) : Any = match this {
10+
case BaseTypeDecl => this.p_base_types().iterator ::: this.p_base_types().iterator.flatMap(super_types)
11+
case _ => Unit()
12+
}
13+
14+
15+
fun children(this : Any) : Any = match this {
16+
case AdaNode => this :: this.children.iterator.flatMap(children)
17+
case _ => Unit()
18+
}
19+
20+
21+
fun foo(this : Any) : Any = match this {
22+
case Foo => [s, o, m, e, t, h, i, n, g].iterator ::: foo(this)
23+
}
24+
25+
26+
|" Infinite sequence generator
27+
fun infinite_sequence(this : Any) : Any = match this {
28+
case nb => nb :: # Recurse with value nb + 1
29+
infinite_sequence(nb + 1)
30+
}
31+
32+
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
driver: refactor
2+
refactoring: TO_LKQL_V2

0 commit comments

Comments
 (0)