Skip to content

Commit 35c6c5a

Browse files
committed
Merge branch 'topic/lkql_jit/add_create_from_template' into 'master'
Add the "create_from_template" method in "RewritingContext" Closes #465 See merge request eng/libadalang/langkit-query-language!429
2 parents a405e90 + 8ac58b3 commit 35c6c5a

File tree

10 files changed

+102
-61
lines changed

10 files changed

+102
-61
lines changed

lkql_checker/share/lkql/binary_case_statements.lkql

+10-27
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,4 @@
1-
# Flag a case statement if this statement has only two alternatives, one
2-
# containing exactly one choice, the other containing exactly one choice
3-
# or the `OTHERS' choice.
4-
# This rule has an optional parameter Except_Enums: exclude case statements on
5-
# enumerated types.
6-
7-
fun to_if_stmt(case_stmt) =
1+
fun to_if_stmt(case_stmt, ctx) =
82
|" This function turns the given "case" statement into a if statement.
93
|" Assumes that the "case" has only 2 alternatives.
104
{
@@ -16,33 +10,22 @@ fun to_if_stmt(case_stmt) =
1610
);
1711
match alts[2].f_choices[1]
1812
| OthersDesignator =>
19-
new IfStmt(
20-
f_cond_expr=cond,
21-
f_then_stmts=alts[1].f_stmts,
22-
f_alternatives=new ElsifStmtPartList(),
23-
f_else_part=new ElsePart(alts[2].f_stmts)
13+
ctx.create_from_template(
14+
"if {} then {} else {} end if;",
15+
"if_stmt_rule",
16+
[cond, alts[1].f_stmts, alts[2].f_stmts]
2417
)
2518
| choice =>
26-
new IfStmt(
27-
f_cond_expr=cond,
28-
f_then_stmts=alts[1].f_stmts,
29-
f_alternatives=new ElsifStmtPartList([
30-
new ElsifStmtPart(
31-
f_cond_expr=new RelationOp(
32-
f_left=case_stmt.f_expr,
33-
f_op=new OpEq(),
34-
f_right=choice
35-
),
36-
f_stmts=alts[2].f_stmts
37-
)
38-
]),
39-
f_else_part=null
19+
ctx.create_from_template(
20+
"if {} then {} elsif {} = {} then {} end if;",
21+
"if_stmt_rule",
22+
[cond, alts[1].f_stmts, case_stmt.f_expr, choice, alts[2].f_stmts]
4023
)
4124
}
4225

4326
@check(message="CASE statement can be replaced with IF statement",
4427
category="Style", subcategory="Programming Practice",
45-
auto_fix=(n, ctx) => ctx.replace(n, to_if_stmt(n)))
28+
auto_fix=(n, ctx) => ctx.replace(n, to_if_stmt(n, ctx)))
4629
fun binary_case_statements(node, except_enums = false) =
4730
|" Flag a case statement if this statement has only two alternatives, one
4831
|" containing exactly one choice, the other containing exactly one choice

lkql_checker/share/lkql/use_if_expressions.lkql

+21-21
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,29 @@ fun replace_by_expr(if_stmt, ctx) =
1010
{
1111
val is_return = simple_return(if_stmt.f_then_stmts);
1212
val then_stmt = if_stmt.f_then_stmts[1];
13-
val else_stmt = if_stmt.f_else_part.f_stmts[1];
14-
val if_expr = new ParenExpr(new IfExpr(
15-
f_cond_expr = if_stmt.f_cond_expr,
16-
f_then_expr = if is_return then then_stmt.f_return_expr else then_stmt.f_expr,
17-
f_else_expr = if is_return then else_stmt.f_return_expr else else_stmt.f_expr,
18-
f_alternatives=new ElsifExprPartList([
19-
{
20-
val stmt = part.f_stmts[1];
21-
new ElsifExprPart(
22-
f_cond_expr = part.f_cond_expr,
23-
f_then_expr = if is_return then stmt.f_return_expr else stmt.f_expr
24-
)
25-
}
26-
for part in if_stmt.f_alternatives.children
27-
].to_list)
28-
));
13+
val expr_index = if is_return then 1 else 2;
14+
val template_and_rule = (
15+
if is_return
16+
then ("return (if {} then {} {} else {});", "return_stmt_rule")
17+
else (then_stmt.f_dest.text & " := (if {} then {} {} else {});", "assignment_stmt_rule")
18+
);
2919
ctx.replace(
3020
if_stmt,
31-
if is_return
32-
then new ReturnStmt(if_expr)
33-
else new AssignStmt(
34-
f_dest = then_stmt.f_dest,
35-
f_expr = if_expr
21+
ctx.create_from_template(
22+
template_and_rule[1],
23+
template_and_rule[2],
24+
[
25+
if_stmt.f_cond_expr,
26+
then_stmt[expr_index],
27+
new ElsifExprPartList([
28+
new ElsifExprPart(
29+
f_cond_expr = part.f_cond_expr,
30+
f_then_expr = part.f_stmts[1][expr_index]
31+
)
32+
for part in if_stmt.f_alternatives.children
33+
].to_list),
34+
if_stmt.f_else_part.f_stmts[1][expr_index]
35+
]
3636
)
3737
)
3838
}

lkql_jit/language/src/main/java/com/adacore/lkql_jit/built_ins/methods/RewritingContextMethods.java

+38
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package com.adacore.lkql_jit.built_ins.methods;
77

88
import com.adacore.libadalang.Libadalang;
9+
import com.adacore.libadalang.Libadalang.GrammarRule;
910
import com.adacore.libadalang.Libadalang.MemberReference;
1011
import com.adacore.libadalang.Libadalang.RewritingContext;
1112
import com.adacore.libadalang.Libadalang.RewritingNode;
@@ -15,7 +16,9 @@
1516
import com.adacore.lkql_jit.exception.LKQLRuntimeException;
1617
import com.adacore.lkql_jit.nodes.utils.RewritingNodeConverter;
1718
import com.adacore.lkql_jit.nodes.utils.RewritingNodeConverterNodeGen;
19+
import com.adacore.lkql_jit.runtime.values.lists.LKQLList;
1820
import com.adacore.lkql_jit.utils.LKQLTypesHelper;
21+
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
1922
import com.oracle.truffle.api.dsl.Specialization;
2023
import com.oracle.truffle.api.frame.VirtualFrame;
2124

@@ -181,4 +184,39 @@ public Object executeGeneric(VirtualFrame frame, RewritingContext ctx, Object ob
181184
return ctx;
182185
}
183186
}
187+
188+
@BuiltInMethod(
189+
name = "create_from_template",
190+
doc = "Create a new node from the provided template, filling '{}' with provided" +
191+
" argument, and parsing the template with the specified grammar rule"
192+
)
193+
public abstract static class CreateFromTemplateExpr extends BaseRewritingContextExpr {
194+
195+
@TruffleBoundary
196+
private static GrammarRule ruleFromString(String ruleName) {
197+
return GrammarRule.valueOf(ruleName.toUpperCase());
198+
}
199+
200+
@Specialization
201+
public RewritingNode doGeneric(
202+
VirtualFrame frame,
203+
RewritingContext ctx,
204+
String template,
205+
String grammarRule,
206+
LKQLList arguments
207+
) {
208+
// Translate the provided LKQL list into a rewriting node list
209+
final var args = new RewritingNode[(int) arguments.size()];
210+
for (int i = 0; i < args.length; i++) {
211+
args[i] = convert(frame, arguments.get(i), true);
212+
}
213+
214+
// Then call the internal function to process the template
215+
try {
216+
return ctx.createFromTemplate(template, ruleFromString(grammarRule), args);
217+
} catch (Exception e) {
218+
throw LKQLRuntimeException.fromJavaException(e, this.callNode);
219+
}
220+
}
221+
}
184222
}

testsuite/tests/checks/binary_case_statements/test.out

+1-7
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,7 @@ Patched "binary_case_statements.adb":
3131
procedure Main is
3232
procedure Test (I : Integer);
3333
begin
34-
if 1 =1 then null;
35-
else null;
36-
end if;if 1 =1 then Test (2);
37-
elsif 1 =2 then Test (1);
38-
end if;if True =True then null;
39-
elsif True =False then null;
40-
end if;case 1 is -- NOFLAG
34+
if 1=1 then null;else null;end if;if 1=1 then Test(2);elsif 1=2 then Test(1);end if;if True=True then null;elsif True=False then null;end if;case 1 is -- NOFLAG
4135
when 1 | 2 => null;
4236
when others => null;
4337
end case;

testsuite/tests/checks/binary_case_statements_enums/test.out

+1-3
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,5 @@ begin
2424
when others => null;
2525
end case;
2626

27-
if 1 =1 then null;
28-
else null;
29-
end if;end Paths;
27+
if 1=1 then null;else null;end if;end Paths;
3028

testsuite/tests/checks/use_if_expressions/test.out

+3-3
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ Patched "stmt.adb":
3131
function Stmt (X : in out Integer) return Integer is
3232
Y : Integer;
3333
begin
34-
return(if X = 1 then 1 else 2);if X = 1 then -- NOFLAG
34+
return(if X=1 then 1 else 2);if X = 1 then -- NOFLAG
3535
null;
3636
else
3737
null;
3838
end if;
3939

40-
return(if X = 1 then 1 elsif X = 2 then 2 else 3);if X = 1 then -- NOFLAG
40+
return(if X=1 then 1 elsif X=2 then 2 else 3);if X = 1 then -- NOFLAG
4141
return 1;
4242
elsif X = 2 then
4343
X := 2;
@@ -53,7 +53,7 @@ begin
5353
X := 0;
5454
end if;
5555

56-
X :=(if X >= 2 then X + 1 elsif X <= 0 then X - 1 else 0);if X > 0 then -- NOFLAG
56+
X:=(if X>=2 then X+1 elsif X<=0 then X-1 else 0);if X > 0 then -- NOFLAG
5757
return 2;
5858
end if;
5959

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
@check(
2+
message="Custom rule violation",
3+
auto_fix=(n, ctx) => ctx.replace(
4+
n,
5+
ctx.create_from_template("Call_Something ({});", "call_stmt_rule", [n.f_label_name])
6+
)
7+
)
8+
fun custom(node) = node is GotoStmt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
procedure Main is
2+
begin
3+
goto lbl; -- FLAG
4+
end Main;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
main.adb:3:4: rule violation: Custom rule violation
2+
3 | goto lbl; -- FLAG
3+
| ^^^^^^^^^
4+
5+
Patched "main.adb":
6+
===================
7+
8+
procedure Main is
9+
begin
10+
Call_Something(lbl);end Main;
11+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
driver: checker
2+
input_sources:
3+
- main.adb
4+
rule_name: custom
5+
auto_fix: True

0 commit comments

Comments
 (0)