Skip to content

Commit a441e15

Browse files
committed
contracts: Change the assertion lock mechanism
Signed-off-by: Delja <deljarry.florian@gmail.com>
1 parent fb893df commit a441e15

File tree

1 file changed

+33
-76
lines changed

1 file changed

+33
-76
lines changed

src/contracts.nit

Lines changed: 33 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -105,11 +105,6 @@ private class ContractsVisitor
105105
# is `no_contract` annotation was found
106106
var find_no_contract = false
107107

108-
# The reference to the `in_contract` attribute.
109-
# This attribute is used to disable contract verification when you are already in a contract verification.
110-
# Keep the `in_contract` attribute to avoid searching at each contrat
111-
var in_contract_attribute: nullable MAttribute = null
112-
113108
redef fun visit(node)
114109
do
115110
node.create_contracts(self)
@@ -140,78 +135,12 @@ private class ContractsVisitor
140135
end
141136
end
142137

143-
# Inject the incontract attribute (`_in_contract_`) in the `Sys` class
144-
# This attribute allows to check if the contract need to be executed
145-
private fun inject_incontract_in_sys
146-
do
147-
# If the `in_contract_attribute` already know just return
148-
if in_contract_attribute != null then return
149-
150-
var sys_class = toolcontext.modelbuilder.get_mclass_by_name(visited_module, mainmodule, "Sys")
151-
152-
# Try to get the `in_contract` property, if it has already defined in a previously visited module.
153-
var in_contract_property = toolcontext.modelbuilder.try_get_mproperty_by_name(visited_module, sys_class.intro, "__in_contract_")
154-
if in_contract_property != null then
155-
self.in_contract_attribute = in_contract_property.as(MAttribute)
156-
return
157-
end
158-
159-
var bool_false = new AFalseExpr.make(mainmodule.bool_type)
160-
var n_in_contract_attribute = toolcontext.modelbuilder.create_attribute_from_name("__in_contract_", sys_class.intro, mainmodule.bool_type, public_visibility).create_setter(toolcontext.modelbuilder, true).define_default(bool_false)
161-
162-
in_contract_attribute = n_in_contract_attribute.mpropdef.mproperty
163-
end
164-
165-
# Return the `_in_contract_` attribute.
166-
# If the attribute `_in_contract_` does not exist it's injected with `inject_incontract_in_sys`
167-
private fun get_incontract: MAttribute
168-
do
169-
if self.in_contract_attribute == null then inject_incontract_in_sys
170-
return in_contract_attribute.as(not null)
171-
end
172-
173-
# Return an `AIfExpr` with the contract encapsulated by an `if` to check if it's already in a contract verification.
174-
#
175-
# Example:
176-
# ~~~nitish
177-
# class A
178-
# fun bar([...]) is except([...])
179-
#
180-
# fun _contract_bar([...])
181-
# do
182-
# if not sys._in_contract_ then
183-
# sys._in_contract_ = true
184-
# _bar_expect([...])
185-
# sys._in_contract_ = false
186-
# end
187-
# bar([...])
188-
# end
189-
#
190-
# fun _bar_expect([...])
191-
# end
192-
# ~~~~
193-
#
194-
private fun encapsulated_contract_call(visited_method: AMethPropdef, call_to_contracts: Array[ACallExpr]): AIfExpr
138+
# Return an `AIfAssertion` with the contract encapsulated by an `if` to check if it's already in a contract verification.
139+
private fun encapsulated_contract_call(visited_method: AMethPropdef, call_to_contracts: Array[ACallExpr]): AIfInAssertion
195140
do
196-
var sys_property = toolcontext.modelbuilder.model.get_mproperties_by_name("sys").first.as(MMethod)
197-
var callsite_sys = ast_builder.create_callsite(toolcontext.modelbuilder, visited_method, sys_property, true)
198-
199-
var incontract_attribute = get_incontract
200-
201-
var callsite_get_incontract = ast_builder.create_callsite(toolcontext.modelbuilder, visited_method, incontract_attribute.getter.as(MMethod), false)
202-
var callsite_set_incontract = ast_builder.create_callsite(toolcontext.modelbuilder, visited_method, incontract_attribute.setter.as(MMethod), false)
203-
204-
var n_condition = ast_builder.make_not(ast_builder.make_call(ast_builder.make_call(new ASelfExpr, callsite_sys, null), callsite_get_incontract, null))
205-
206-
var n_if = ast_builder.make_if(n_condition, null)
207-
208-
var if_then_block = n_if.n_then.as(ABlockExpr)
209-
210-
if_then_block.add(ast_builder.make_call(ast_builder.make_call(new ASelfExpr, callsite_sys, null), callsite_set_incontract, [new ATrueExpr.make(mainmodule.bool_type)]))
211-
if_then_block.add_all(call_to_contracts)
212-
if_then_block.add(ast_builder.make_call(ast_builder.make_call(new ASelfExpr, callsite_sys, null), callsite_set_incontract, [new AFalseExpr.make(mainmodule.bool_type)]))
213-
214-
return n_if
141+
var n_block = ast_builder.make_block
142+
n_block.add_all(call_to_contracts)
143+
return new AIfInAssertion(n_block)
215144
end
216145
end
217146

@@ -847,3 +776,31 @@ redef class ANewExpr
847776
end
848777
end
849778
end
779+
780+
# Ast representation of the `in_assertion` checking
781+
# Note, the node if is only composed with a then body (`n_body`)
782+
class AIfInAssertion
783+
super AExpr
784+
785+
# The body of the if
786+
var n_body: AExpr is writable
787+
788+
redef fun accept_scope_visitor(v)
789+
do
790+
v.enter_visit_block(n_body, null)
791+
end
792+
793+
redef fun visit_all(v: Visitor)
794+
do
795+
v.enter_visit(n_body)
796+
end
797+
798+
redef fun accept_typing(v)
799+
do
800+
v.visit_stmt(n_body)
801+
802+
self.is_typed = true
803+
804+
self.mtype = n_body.mtype
805+
end
806+
end

0 commit comments

Comments
 (0)