Skip to content

Commit 16679b4

Browse files
pmderodatraph-amiard
authored andcommitted
langkit.expressions.logic: refactor Assign/Predicate/Unify codegen
Create one separate ResolvedExpression subclass per equation kind. This will make it easier to add a new equation kind in an upcoming commit (N_Propagate) and makes code more typable. TN: SB20-024 For libadalang/langkit#618
1 parent 20473b1 commit 16679b4

File tree

1 file changed

+188
-88
lines changed

1 file changed

+188
-88
lines changed

langkit/expressions/logic.py

Lines changed: 188 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,165 @@ def untyped_literal_expr(expr_str, operands=[]):
3333
return LiteralExpr(expr_str, no_compiled_type, operands)
3434

3535

36+
class BindExpr(CallExpr):
37+
"""
38+
Base class for resolved expressions that create Assign/Propagate/Unify
39+
equations.
40+
"""
41+
42+
def __init__(self,
43+
constructor_name: str,
44+
constructor_args: List[Union[str, ResolvedExpression]],
45+
abstract_expr: Optional[AbstractExpression] = None):
46+
"""
47+
:param constructor_name: Name of the function to create the equation.
48+
:param constructor_args: Its arguments, exclusing the "Debug_String"
49+
one, which we automatically add.
50+
:param abstract_expr: Reference to the corresponding abstract
51+
expression, if any.
52+
"""
53+
args: List[Union[str, ResolvedExpression]] = list(constructor_args)
54+
if abstract_expr:
55+
args.append(
56+
f"Debug_String => {sloc_info_arg(abstract_expr.location)}"
57+
)
58+
super().__init__(
59+
"Bind_Result",
60+
constructor_name,
61+
T.Equation,
62+
args,
63+
abstract_expr=abstract_expr,
64+
)
65+
66+
@staticmethod
67+
def functor_expr(type_name: str, prop: PropertyDef) -> LiteralExpr:
68+
"""
69+
Return an expression to create a functor for ``Prop``.
70+
71+
:param type_name: Name of the functor derived type.
72+
:param prop: Property called by the functor.
73+
"""
74+
assocs: List[Tuple[str, LiteralExpr]] = [
75+
("Ref_Count", IntegerLiteralExpr(1)),
76+
("Cache_Set", LiteralExpr("False", None)),
77+
("Cache_Key", LiteralExpr("<>", None)),
78+
("Cache_Value", LiteralExpr("<>", None)),
79+
] + [
80+
(dynvar.argument_name, construct(dynvar))
81+
for dynvar in prop.dynamic_vars
82+
]
83+
return aggregate_expr(type_name, assocs)
84+
85+
86+
class AssignExpr(BindExpr):
87+
"""
88+
Resolved expression that creates Unify equations.
89+
"""
90+
91+
def __init__(self,
92+
logic_var: ResolvedExpression,
93+
value: ResolvedExpression,
94+
conv_prop: Optional[PropertyDef],
95+
abstract_expr: Optional[AbstractExpression] = None):
96+
self.logic_var = logic_var
97+
self.value = value
98+
self.conv_prop = conv_prop
99+
100+
constructor_args: List[Union[str, ResolvedExpression]] = [
101+
logic_var,
102+
value,
103+
self.functor_expr(f"Logic_Converter_{conv_prop.uid}", conv_prop)
104+
if conv_prop else
105+
"Solver_Ifc.No_Converter",
106+
]
107+
108+
super().__init__(
109+
"Solver.Create_Assign",
110+
constructor_args,
111+
abstract_expr=abstract_expr
112+
)
113+
114+
@property
115+
def subexprs(self):
116+
return {
117+
'logic_var': self.logic_var,
118+
'value': self.value,
119+
'conv_prop': self.conv_prop,
120+
}
121+
122+
def __repr__(self):
123+
return '<AssignExpr>'
124+
125+
126+
class PropagateExpr(BindExpr):
127+
"""
128+
Resolved expression that creates Propagate equations.
129+
"""
130+
131+
def __init__(self,
132+
dest_var: ResolvedExpression,
133+
arg_var: ResolvedExpression,
134+
conv_prop: Optional[PropertyDef],
135+
abstract_expr: Optional[AbstractExpression] = None):
136+
self.dest_var = dest_var
137+
self.arg_var = arg_var
138+
self.conv_prop = conv_prop
139+
140+
constructor_args: List[Union[str, ResolvedExpression]] = [
141+
dest_var,
142+
arg_var,
143+
self.functor_expr(f"Logic_Converter_{conv_prop.uid}", conv_prop)
144+
if conv_prop else
145+
"Solver_Ifc.No_Converter",
146+
]
147+
148+
super().__init__(
149+
"Solver.Create_Propagate",
150+
constructor_args,
151+
abstract_expr=abstract_expr
152+
)
153+
154+
@property
155+
def subexprs(self):
156+
return {
157+
'dest_var': self.dest_var,
158+
'arg_var': self.arg_var,
159+
'conv_prop': self.conv_prop,
160+
}
161+
162+
def __repr__(self):
163+
return '<PropagateExpr>'
164+
165+
166+
class UnifyExpr(BindExpr):
167+
"""
168+
Resolved expression that creates Unify equations.
169+
"""
170+
171+
def __init__(self,
172+
left_var: ResolvedExpression,
173+
right_var: ResolvedExpression,
174+
abstract_expr: Optional[AbstractExpression] = None):
175+
self.left_var = left_var
176+
self.right_var = right_var
177+
178+
super().__init__(
179+
"Solver.Create_Unify",
180+
[self.left_var, self.right_var],
181+
abstract_expr=abstract_expr
182+
)
183+
184+
@property
185+
def subexprs(self):
186+
return {
187+
'left_var': self.left_var,
188+
'right_var': self.right_var,
189+
}
190+
191+
def __repr__(self):
192+
return '<UnifyExpr>'
193+
194+
36195
@dsl_document
37196
class Bind(AbstractExpression):
38197
"""
@@ -52,76 +211,6 @@ class Bind(AbstractExpression):
52211
Bind(A, B, conv_prop=T.TypeOfA.some_property)
53212
"""
54213

55-
class Expr(CallExpr):
56-
def __init__(self,
57-
conv_prop: PropertyDef,
58-
lhs: ResolvedExpression,
59-
rhs: ResolvedExpression,
60-
abstract_expr: Optional[AbstractExpression] = None):
61-
self.conv_prop = conv_prop
62-
self.lhs = lhs
63-
self.rhs = rhs
64-
65-
constructor_args: List[Union[str, ResolvedExpression]] = [lhs, rhs]
66-
67-
if conv_prop:
68-
constructor_args.append(self.functor_expr(
69-
conv_prop,
70-
f"Conv => Logic_Converter_{self.conv_prop.uid}",
71-
("Cache_Set", LiteralExpr("False", None)),
72-
("Cache_Key", LiteralExpr("<>", None)),
73-
("Cache_Value", LiteralExpr("<>", None)),
74-
))
75-
76-
if abstract_expr:
77-
constructor_args.append(
78-
f"Debug_String => {sloc_info_arg(abstract_expr.location)}"
79-
)
80-
81-
if rhs.type.matches(T.root_node.entity):
82-
fn_name = 'Solver.Create_Assign'
83-
elif conv_prop:
84-
fn_name = 'Solver.Create_Propagate'
85-
else:
86-
fn_name = 'Solver.Create_Unify'
87-
88-
super().__init__(
89-
'Bind_Result', fn_name,
90-
T.Equation, constructor_args,
91-
abstract_expr=abstract_expr
92-
)
93-
94-
@staticmethod
95-
def functor_expr(prop: PropertyDef,
96-
type_name: str,
97-
*components: Tuple[str, LiteralExpr]) -> LiteralExpr:
98-
"""
99-
Return an expression to create a functor for ``Prop``.
100-
101-
:param prop: Property called by the functor.
102-
:param type_name: Name of the functor derived type.
103-
:param components: Additional components (component name and
104-
initialization expression) for the functor.
105-
"""
106-
assocs: List[Tuple[str, LiteralExpr]] = []
107-
assocs.append(("Ref_Count", IntegerLiteralExpr(1)))
108-
assocs.extend(
109-
(dynvar.argument_name, construct(dynvar))
110-
for dynvar in prop.dynamic_vars
111-
)
112-
assocs.extend(components)
113-
114-
return aggregate_expr(type_name, assocs)
115-
116-
@property
117-
def subexprs(self):
118-
return {'conv_prop': self.conv_prop,
119-
'lhs': self.lhs,
120-
'rhs': self.rhs}
121-
122-
def __repr__(self):
123-
return '<Bind.Expr>'
124-
125214
def __init__(self, from_expr, to_expr, conv_prop=None):
126215
"""
127216
:param AbstractExpression from_expr: An expression resolving to a
@@ -201,30 +290,41 @@ def construct(self):
201290
rhs = construct(self.to_expr)
202291

203292
if rhs.type.matches(T.LogicVar):
293+
# The second operand is a logic variable: this is a Propagate or a
294+
# Unify equation depending on whether we have a conversion
295+
# property.
296+
204297
# For this operand too, make sure it will work on a clean logic
205298
# variable.
206299
rhs = ResetLogicVar(rhs)
207-
elif rhs.type.matches(T.root_node):
208-
from langkit.expressions import make_as_entity
209-
rhs = make_as_entity(rhs)
210-
else:
211-
check_source_language(
212-
rhs.type.matches(T.root_node.entity)
213-
or rhs.type.matches(T.LogicVar),
214-
'Right operand must be either a logic variable or an entity,'
215-
' got {}'.format(rhs.type.dsl_name)
300+
301+
return (
302+
PropagateExpr(lhs, rhs, self.conv_prop, abstract_expr=self)
303+
if self.conv_prop else
304+
UnifyExpr(lhs, rhs, abstract_expr=self)
216305
)
217306

218-
# Because of Ada OOP typing rules, for code generation to work
219-
# properly, make sure the type of `rhs` is the root node entity.
220-
if (
221-
rhs.type.matches(T.root_node.entity)
222-
and rhs.type is not T.root_node.entity
223-
):
224-
from langkit.expressions import Cast
225-
rhs = Cast.Expr(rhs, T.root_node.entity)
307+
else:
308+
# The second operand is a value: this is an Assign equation
309+
310+
if rhs.type.matches(T.root_node):
311+
from langkit.expressions import make_as_entity
312+
rhs = make_as_entity(rhs)
313+
else:
314+
check_source_language(
315+
rhs.type.matches(T.root_node.entity)
316+
or rhs.type.matches(T.LogicVar),
317+
"Right operand must be either a logic variable or an"
318+
" entity, got {rhs.type.dsl_name}"
319+
)
320+
321+
# Because of Ada OOP typing rules, for code generation to work
322+
# properly, make sure the type of `rhs` is the root node entity.
323+
if rhs.type is not T.root_node.entity:
324+
from langkit.expressions import Cast
325+
rhs = Cast.Expr(rhs, T.root_node.entity)
226326

227-
return Bind.Expr(self.conv_prop, lhs, rhs, abstract_expr=self)
327+
return AssignExpr(lhs, rhs, self.conv_prop, abstract_expr=self)
228328

229329

230330
class DomainExpr(ComputingExpr):

0 commit comments

Comments
 (0)