我在Alloy中做一个模型来表示Java语言的一个子集。下面我们有这个模型的一些元素:
sig Method {
id : one MethodId,
param: lone Type,
return: one Type,
acc: lone Accessibility,
b: one Block
}
abstract sig Expression {}
abstract sig StatementExpression extends Expression {}
sig MethodInvocation extends StatementExpression{
pExp: lone PrimaryExpression,
id_methodInvoked: one Method,
param: lone Type
}
sig Block {
statements: set StatementExpression
}
pred noRecursiveMethodInvocationCall [] {
all bl:Block | all mi, mi2: MethodInvocation | all m:Method |
bl in m.b && mi in bl.statements
&& mi2 = mi.*(id_methodInvoked.b.statements) =>
m != mi2.id_methodInvoked
}
问题是谓词noRecursiveMethodInvocationCall显然不起作用,因为生成的实例包含以递归方式调用的方法(甚至是间接的,例如m1调用m2,调用m3反过来调用m1)并且我想避免递归
实例是通过另一个模型生成的,见下文:
open javametamodel_withfield_final
one sig BRight, CRight, BLeft, CLeft, Test extends Class{
}
one sig F extends Field{}
fact{
BRight in CRight.extend
BLeft in CLeft.extend
F in BRight.fields
F in CLeft.fields
all c:{Class-BRight-CLeft} | F !in c.fields
}
pred law6RightToLeft[]{
proviso[]
}
pred proviso [] {
some BRight.extend
some BLeft.extend
#(extend.BRight) > 2
#(extend.BLeft) > 2
no cfi:FieldAccess | ( cfi.pExp.id_cf in extend.BRight || cfi.pExp.id_cf in BRight || cfi.pExp.id_cf in extend.BLeft || cfi.pExp.id_cf in BLeft) && cfi.id_fieldInvoked=F
some Method
}
run law6RightToLeft for 9 but 15 Id, 15 Type, 15 Class
拜托,有没有人知道问题是什么?
提前感谢您的关注,
后续查询
仍然关于这个问题,建议的谓词解决了递归问题:
pred noRecursiveMethodInvocationCall [] {
no m:Method
| m in m.^(b.statements.id_methodInvoked)
}
但是,它会导致与另一个谓词不一致(见下文),并且当两个谓词都存在时不会生成实例。
pred atLeastOneMethodInvocNonVoidMethods [] {
all m:Method
| some mi:MethodInvocation
| mi in (m.b).statements
}
知道为什么不能用两个谓词生成实例吗?
答案 0 :(得分:3)
您可能会仔细查看条件
mi2 = mi.*(id_methodInvoked.b.statements)
似乎检查从mi
递归到达的所有语句的集合是否等于单个语句mi2
。现在,除非我再次将自己与多重性混淆,mi2
是一个标量,所以在任何情况下,所讨论的方法都有一个带有多个方法调用语句的块,这个条件不会触发,而且谓词将是真实的。
将=
更改为in
可能是最简单的修复方法,但在这种情况下,我希望您不会获得任何非空实例,因为您正在使用*
并获取反身传递闭包,而不是^
(正传递闭包)。
乍一看,好像情况可能简化为
pred noRecursion {
no m : Method
| m in m.^(b.statements.idMethodInvoked)
}
但也许我错过了一些东西。
Postscript:该问题的后续补充询问为什么在将递归禁止与每个方法至少包含一个方法调用的要求相结合时不会生成实例:
pred atLeastOneMethodInvocNonVoidMethods [] {
all m:Method
| some mi:MethodInvocation
| mi in (m.b).statements
}
也许最简单的方法就是想象构建一个调用图。图的节点是方法,图的弧是方法调用。如果方法M1的主体包含方法M2的调用,则存在从节点M1到节点M2的弧。
如果我们根据图解释这两个谓词,谓词noRecursiveMethodInvocationCall
意味着图是非循环的。谓词atLeastOneMethodInvocNonVoidMethods
表示图中的每个节点至少有一个传出弧。
使用单个方法M尝试。此方法必须包含方法调用,并且此方法调用必须调用M(因为Universe中没有其他方法)。所以我们有一个从M到M的弧,图中有一个循环。但图表不允许有一个循环。因此,我们无法创建满足两个谓词的单方法Universe。
使用两种方法M1和M2再试一次。让M1呼叫M2。现在,M2打电话给谁?它不能在没有循环的情况下调用M1。它不能在没有循环的情况下调用M2。我们再次失败。
我现在没有时间查找它,但我认为你会发现图论的一个基本定理是,如果边的数量等于节点的数量,那么图必须有一个周期