Skip to content

Commit 77dd3ca

Browse files
committed
Merge branch 'mr/pmderodat/2-bind-arg-order' into 'master'
Refactor the order of arguments for Bind (Python DSL) and %eq (Lkt) See merge request eng/libadalang/langkit!1208
2 parents a6337ea + 3e30be2 commit 77dd3ca

File tree

8 files changed

+313
-72
lines changed

8 files changed

+313
-72
lines changed

langkit/dsl_unparse.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1524,7 +1524,7 @@ def handle_designated_env_macro():
15241524

15251525
elif isinstance(expr, Bind):
15261526
return prio, "%eq({})".format(", ".join(keep([
1527-
ee_prio(P.lowest, expr.from_expr), ee_prio(P.lowest, expr.to_expr),
1527+
ee_prio(P.lowest, expr.to_expr), ee_prio(P.lowest, expr.from_expr),
15281528
"conv_prop={}".format(fqn(expr.conv_prop)) if expr.conv_prop else "",
15291529
"logic_ctx={}".format(ee_prio(P.lowest, expr.logic_ctx)) if expr.logic_ctx else "",
15301530
])))

langkit/expressions/logic.py

Lines changed: 42 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,6 @@ def construct_propagate(
198198
# the support library and the other is generated), they have the
199199
# same structure, so we cast the given one to the expected type.
200200
assert len(arg_vars) == 1
201-
constructor_name = "Solver.Create_N_Propagate"
202201
var_array_expr = SavedExpr("Logic_Vars", arg_vars[0])
203202
saved_exprs.append(var_array_expr)
204203
var_array = LiteralExpr(
@@ -208,34 +207,44 @@ def construct_propagate(
208207
var_length = LiteralExpr(
209208
"{}.N", None, [var_array_expr.result_var_expr]
210209
)
210+
constructor_name = "Solver.Create_N_Propagate"
211211
constructor_args = [
212+
# "To" argument
212213
dest_var,
214+
# "Comb" argument
213215
cls.functor_expr(
214216
f"Logic_Functor_{prop.uid}", prop, var_length
215217
)
216218
if prop else
217219
"Solver_Ifc.No_Combiner",
220+
# "Logic_Vars" argument
218221
var_array,
219222
]
220223
elif len(arg_vars) == 1:
221224
constructor_name = "Solver.Create_Propagate"
222225
constructor_args = [
223-
dest_var,
226+
# "From" argument
224227
arg_vars[0],
228+
# "To" argument
229+
dest_var,
230+
# "Conv" argument
225231
cls.functor_expr(f"Logic_Functor_{prop.uid}", prop)
226232
if prop else
227233
"Solver_Ifc.No_Converter",
228234
]
229235
else:
230236
constructor_name = "Solver.Create_N_Propagate"
231237
constructor_args = [
238+
# "To" argument
232239
dest_var,
240+
# "Comb" argument
233241
cls.functor_expr(
234242
f"Logic_Functor_{prop.uid}", prop,
235243
IntegerLiteralExpr(len(arg_vars))
236244
)
237245
if prop else
238246
"Solver_Ifc.No_Combiner",
247+
# "Logic_Vars" argument
239248
aggregate_expr(
240249
type=None,
241250
assocs=[(str(i), v) for i, v in enumerate(arg_vars, 1)],
@@ -314,12 +323,12 @@ class Bind(AbstractExpression):
314323
Bind(A, B, conv_prop=T.TypeOfA.some_property)
315324
"""
316325

317-
def __init__(self, from_expr, to_expr, conv_prop=None, logic_ctx=None):
326+
def __init__(self, to_expr, from_expr, conv_prop=None, logic_ctx=None):
318327
"""
319-
:param AbstractExpression from_expr: An expression resolving to a
320-
logical variable that is the source of the bind.
321328
:param AbstractExpression to_expr: An expression resolving to a
322329
logical variable that is the destination of the bind.
330+
:param AbstractExpression from_expr: An expression resolving to a
331+
logical variable that is the source of the bind.
323332
:param PropertyDef|None conv_prop: The property to apply on the
324333
value of from_expr that will yield the value to give to to_expr.
325334
For convenience, it can be a property on any subclass of the root
@@ -329,8 +338,8 @@ def __init__(self, from_expr, to_expr, conv_prop=None, logic_ctx=None):
329338
LogicContext.
330339
"""
331340
super().__init__()
332-
self.from_expr = from_expr
333341
self.to_expr = to_expr
342+
self.from_expr = from_expr
334343
self.conv_prop = conv_prop
335344
self.logic_ctx = logic_ctx
336345

@@ -442,20 +451,20 @@ def _construct_logic_var(var_expr) -> ResolvedExpression:
442451
"""
443452
return ResetLogicVar(construct(var_expr, T.LogicVar))
444453

445-
def construct(self):
454+
def construct(self) -> ResolvedExpression:
446455
# Resolve the converter property, make sure it has an acceptable
447456
# signature and generate a functor for it.
448457
self.conv_prop = self._resolve_property(
449458
"Bind's conv_prop", self.conv_prop, 1
450459
)
451460

452-
# Left operand must be a logic variable. Make sure the resulting
461+
# The "to" operand must be a logic variable. Make sure the resulting
453462
# equation will work on a clean logic variable.
454-
lhs = self._construct_logic_var(self.from_expr)
463+
to_expr = self._construct_logic_var(self.to_expr)
455464

456-
# Second one can be either a logic variable or an entity (or an AST
465+
# The "from" one can be either a logic variable or an entity (or a bare
457466
# node that is promoted to an entity).
458-
rhs = construct(self.to_expr)
467+
from_expr = construct(self.from_expr)
459468

460469
logic_ctx = None
461470
if self.logic_ctx:
@@ -465,45 +474,54 @@ def construct(self):
465474
f"Expected LogicContext, got {logic_ctx.type.dsl_name}"
466475
)
467476

468-
if rhs.type.matches(T.LogicVar):
477+
if from_expr.type.matches(T.LogicVar):
469478
# The second operand is a logic variable: this is a Propagate or a
470479
# Unify equation depending on whether we have a conversion
471480
# property.
472481

473482
# For this operand too, make sure it will work on a clean logic
474483
# variable.
475-
rhs = ResetLogicVar(rhs)
484+
from_expr = ResetLogicVar(from_expr)
476485

477486
return (
478487
PropagateExpr.construct_propagate(
479-
lhs, [rhs], self.conv_prop, logic_ctx, abstract_expr=self
488+
to_expr,
489+
[from_expr],
490+
self.conv_prop,
491+
logic_ctx,
492+
abstract_expr=self,
480493
)
481494
if self.conv_prop else
482-
UnifyExpr(lhs, rhs, logic_ctx, abstract_expr=self)
495+
UnifyExpr(to_expr, from_expr, logic_ctx, abstract_expr=self)
483496
)
484497

485498
else:
486499
# The second operand is a value: this is an Assign equation
487500

488-
if rhs.type.matches(T.root_node):
501+
if from_expr.type.matches(T.root_node):
489502
from langkit.expressions import make_as_entity
490-
rhs = make_as_entity(rhs)
503+
from_expr = make_as_entity(from_expr)
491504
else:
492505
check_source_language(
493-
rhs.type.matches(T.root_node.entity)
494-
or rhs.type.matches(T.LogicVar),
506+
from_expr.type.matches(T.root_node.entity)
507+
or from_expr.type.matches(T.LogicVar),
495508
"Right operand must be either a logic variable or an"
496-
f" entity, got {rhs.type.dsl_name}"
509+
f" entity, got {from_expr.type.dsl_name}"
497510
)
498511

499512
# Because of Ada OOP typing rules, for code generation to work
500-
# properly, make sure the type of `rhs` is the root node entity.
501-
if rhs.type is not T.root_node.entity:
513+
# properly, make sure the type of `from_expr` is the root node
514+
# entity.
515+
if from_expr.type is not T.root_node.entity:
502516
from langkit.expressions import Cast
503-
rhs = Cast.Expr(rhs, T.root_node.entity)
517+
from_expr = Cast.Expr(from_expr, T.root_node.entity)
504518

505519
return AssignExpr(
506-
lhs, rhs, self.conv_prop, logic_ctx, abstract_expr=self
520+
to_expr,
521+
from_expr,
522+
self.conv_prop,
523+
logic_ctx,
524+
abstract_expr=self,
507525
)
508526

509527

langkit/lkt_lowering.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1512,8 +1512,8 @@ def match(
15121512
"""
15131513

15141514
eq_signature = FunctionSignature(
1515-
FunctionParamSpec("from"),
15161515
FunctionParamSpec("to"),
1516+
FunctionParamSpec("from"),
15171517
FunctionParamSpec("conv_prop", optional=True, keyword_only=True),
15181518
FunctionParamSpec("logic_ctx", optional=True, keyword_only=True),
15191519
)
@@ -4570,8 +4570,8 @@ def lower_new(type_ref: TypeRepo.Defer) -> AbstractExpression:
45704570
args, _ = eq_signature.match(self.ctx, expr)
45714571
logic_ctx_expr = args.get("logic_ctx")
45724572
return E.Bind(
4573-
lower(args["from"]),
45744573
lower(args["to"]),
4574+
lower(args["from"]),
45754575
conv_prop=self.resolve_property(
45764576
args.get("conv_prop")
45774577
),

testsuite/tests/properties/conv_prop_mistype/expected_concrete_syntax.lkt

Lines changed: 51 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,63 @@ class FooNode implements Node[FooNode] {
1313
}
1414

1515
class Examples: FooNode {
16-
@parse_field e1: RegularExample
17-
@parse_field e2: PlusExample
16+
@parse_field re: RegularExample
17+
@parse_field pe: PlusExample
18+
19+
|" Helper to assign PlusExample/RegularExample nodes to the corresponding
20+
|" logic vars.
21+
fun domains(): Equation =
22+
%domain(node.re.lvar, [node.re]) and %domain(node.pe.lvar, [node.pe])
23+
24+
@exported
25+
fun fail_bind_conv_prop(): Bool = (
26+
%eq(node.pe.lvar, node.re.lvar, conv_prop=PlusExample.conv_prop) and node.domains()
27+
).solve()
28+
29+
@exported
30+
fun fail_nprop_single(): Bool = (
31+
%propagate(node.pe.lvar, PlusExample.conv_prop, node.re.lvar) and node.domains()
32+
).solve()
33+
34+
@exported
35+
fun ok_nprop_multi(): Bool = (
36+
%propagate(node.pe.lvar, PlusExample.comb_prop, node.pe.lvar, node.re.lvar, node.pe.lvar) and node.domains()
37+
).solve()
38+
39+
@exported
40+
fun fail_nprop_multi_1(): Bool = (
41+
%propagate(node.pe.lvar, PlusExample.comb_prop, node.re.lvar, node.re.lvar, node.pe.lvar) and node.domains()
42+
).solve()
43+
44+
@exported
45+
fun fail_nprop_multi_2(): Bool = (
46+
%propagate(node.pe.lvar, PlusExample.comb_prop, node.pe.lvar, node.pe.lvar, node.pe.lvar) and node.domains()
47+
).solve()
48+
49+
@exported
50+
fun fail_nprop_multi_3(): Bool = (
51+
%propagate(node.pe.lvar, PlusExample.comb_prop, node.pe.lvar, node.re.lvar, node.re.lvar) and node.domains()
52+
).solve()
53+
54+
@exported
55+
fun ok_nprop_varargs(): Bool = (
56+
%propagate(node.pe.lvar, PlusExample.ncomb_prop, [node.pe.lvar, node.pe.lvar]) and node.domains()
57+
).solve()
1858

1959
@exported
20-
fun do_solving(): Bool = (
21-
(
22-
%eq(node.e1.lvar, node.e2.lvar, conv_prop=PlusExample.conv_prop) and %domain(node.e1.lvar, [node.e1])
23-
) and %domain(node.e2.lvar, [node.e2])
60+
fun fail_nprop_varargs(): Bool = (
61+
%propagate(node.pe.lvar, PlusExample.ncomb_prop, [node.pe.lvar, node.re.lvar]) and node.domains()
2462
).solve()
2563
}
2664

2765
class PlusExample: FooNode {
28-
fun conv_prop(): Entity[RegularExample] = null[Entity[RegularExample]]
66+
fun conv_prop(): Entity[PlusExample] = self
67+
68+
fun comb_prop(@ignored re: Entity[RegularExample], pe: Entity[PlusExample]): Entity[PlusExample] =
69+
pe
70+
71+
fun ncomb_prop(pe_list: Array[Entity[PlusExample]]): Entity[PlusExample] =
72+
pe_list?[0]
2973
}
3074

3175
class RegularExample: FooNode {
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
with Ada.Exceptions; use Ada.Exceptions;
2+
with Ada.Text_IO; use Ada.Text_IO;
3+
4+
with Libfoolang.Analysis; use Libfoolang.Analysis;
5+
with Libfoolang.Common; use Libfoolang.Common;
6+
7+
procedure Main is
8+
Ctx : constant Analysis_Context := Create_Context;
9+
U : constant Analysis_Unit :=
10+
Ctx.Get_From_Buffer ("main.txt", Buffer => "example +example");
11+
N : Examples;
12+
13+
procedure Check
14+
(Label : String;
15+
Property : access function (N : Examples'Class) return Boolean);
16+
17+
-----------
18+
-- Check --
19+
-----------
20+
21+
procedure Check
22+
(Label : String;
23+
Property : access function (N : Examples'Class) return Boolean)
24+
is
25+
Result : Boolean;
26+
begin
27+
Put_Line ("Calling Examples." & Label & "...");
28+
begin
29+
Result := Property.all (N);
30+
Put_Line ("Result: " & Result'Image);
31+
exception
32+
when Exc : Property_Error =>
33+
Put_Line ("Got a Property_Error: " & Exception_Message (Exc));
34+
end;
35+
New_Line;
36+
end Check;
37+
38+
begin
39+
Put_Line ("main.adb: Running...");
40+
if U.Has_Diagnostics then
41+
raise Program_Error;
42+
end if;
43+
N := U.Root.As_Examples;
44+
45+
Check ("p_fail_bind_conv_prop", P_Fail_Bind_Conv_Prop'Access);
46+
Check ("p_fail_nprop_single", P_Fail_Nprop_Single'Access);
47+
Check ("p_ok_nprop_multi", P_Ok_Nprop_Multi'Access);
48+
Check ("p_fail_nprop_multi_1", P_Fail_Nprop_Multi_1'Access);
49+
Check ("p_fail_nprop_multi_2", P_Fail_Nprop_Multi_2'Access);
50+
Check ("p_fail_nprop_multi_3", P_Fail_Nprop_Multi_3'Access);
51+
Check ("p_ok_nprop_varargs", P_Ok_Nprop_Varargs'Access);
52+
Check ("p_fail_nprop_varargs", P_Fail_Nprop_Varargs'Access);
53+
54+
Put_Line ("main.adb: Done.");
55+
end Main;

testsuite/tests/properties/conv_prop_mistype/main.py

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
1-
main.py: Running...
2-
Evaluating .p_do_solving...
3-
Got a PropertyError: foo:1:1-1:8: mismatching node type for conv_prop
4-
main.py: Done.
1+
main.adb: Running...
2+
Calling Examples.p_fail_bind_conv_prop...
3+
Got a Property_Error: main.txt:1:1-1:8: mismatching node type for conv_prop
4+
5+
Calling Examples.p_fail_nprop_single...
6+
Got a Property_Error: main.txt:1:1-1:8: mismatching node type for conv_prop
7+
8+
Calling Examples.p_ok_nprop_multi...
9+
Result: TRUE
10+
11+
Calling Examples.p_fail_nprop_multi_1...
12+
Got a Property_Error: main.txt:1:1-1:8: mismatching node type for comb_prop
13+
14+
Calling Examples.p_fail_nprop_multi_2...
15+
Got a Property_Error: main.txt:1:9-1:17: mismatching node type for comb_prop
16+
17+
Calling Examples.p_fail_nprop_multi_3...
18+
Got a Property_Error: main.txt:1:9-1:17: mismatching node type for comb_prop
19+
20+
Calling Examples.p_ok_nprop_varargs...
21+
Result: TRUE
22+
23+
Calling Examples.p_fail_nprop_varargs...
24+
Got a Property_Error: main.txt:1:1-1:8: mismatching node type for comb_prop
25+
26+
main.adb: Done.
527
Done

0 commit comments

Comments
 (0)