UML::Element的代数规范
学了这么久的maude,也没什么感觉,帖段代码吧。
(omod UML2-KERNEL-ELEMENT is
pr UML2-BASE .
sorts OwnedCommentRC OwnedElementRC .
subsorts OwnedCommentRC < OwnedElementRC < RoleCode .
--- subsorts OwnerRC < RoleCode .
--- 因为模型元素的一般访问次序为树型访问,
--- 所以去掉OwnerRC角色码,以减少重复,
--- 另一个问题是当ownedElement从其容器元素中移到
--- 新的容器元素,则其owner需清除,这为模型转换带
--- 来复杂性,而没有owner成员属性时,当从容器中
--- 移走一个元素N,只要将容器.ownedElements(N.Oid)去掉
--- 即可将N重新绑定到新的容器。
op oe : -> OwnedElementRC [ctor] .
op oc : -> OwnedCommentRC [ctor] .
--- ownedComment: Comment[*] The Comments owned by this element. Subsets Element::ownedElement.
--- /ownedElement: Element[*] The Elements owned by this element. This is a derived union.
--- /owner: Element [0..1] The Element that owns this element. This is a derived union.
class Element | ownedElementCNt : List(ConnNode) . *** 使用列表以支持子类的有序关联端约束
op isOwnedElement : Object Oid -> Bool .
op getOwnedElement : Object Oid -> ConnNode . ***ownedElementCNt中以Oid为索引
op getOwnedElements : Object -> Set(Oid) .
op apdOwnedElement : Object Oid -> Object .
op rmvOwnedElement : Object Oid -> Object .
op isOwnedComment : Object Oid -> Bool .
op getOwnedComment : Object Oid -> ConnNode .
op getOwnedComments : Object -> Set(Oid) .
op apdOwnedComment : Object Oid -> Object .
op rmvOwnedComment : Object Oid -> Object .
vars O O1 O2 : Oid .
vars L L1 : List(ConnNode) .
vars R : RoleCode .
eq isOwnedElement(< O : Element | ownedElementCNt : L >, O1) = isInCN(L, O1) .
eq getOwnedElement(< O : Element | ownedElementCNt : L >, O1) = getCN(L, O1) .
eq getOwnedElements(< O : Element | ownedElementCNt : L >) = getOids(L) .
eq apdOwnedElement(< O : Element | ownedElementCNt : L >, O1) =
< O : Element | ownedElementCNt : apdCN(L, O1, oe) > . ***保证只有一个O。
eq rmvOwnedElement(< O : Element | ownedElementCNt : L >, O1) =
< O : Element | ownedElementCNt : rmvCN(L, O1) > .
----------------------------------------------------------------------------
ceq isOwnedComment(< O : Element | ownedElementCNt : L >, O1) =
true if rc(getCN(L, O1)) :: OwnedCommentRC .
eq isOwnedComment(< O : Element | >, O1) = false [owise] .
ceq getOwnedComment(< O : Element | ownedElementCNt : L ; (O1, R) ; L1 >, O1) =
(O1, R) if R :: OwnedCommentRC .
eq getOwnedComment(< O : Element | ownedElementCNt : L >, O1) =
(nil, nil) [owise] .
eq getOwnedComments(< O : Element | ownedElementCNt : (O1, R) ; L >) =
if R :: OwnedCommentRC then O1 getOwnedComments(< O : Element | ownedElementCNt : L >)
else getOwnedComments(< O : Element | ownedElementCNt : L >)
fi .
eq getOwnedComments(< O : Element | ownedElementCNt : none >) = mt .
eq apdOwnedComment(< O : Element | ownedElementCNt : L >, O1) =
< O : Element | ownedElementCNt : apdCN(L, O1, oc) > . *** 保证只有一个O。
***因为apdXXX保证最多只有一个O,故只需移走一个。
ceq rmvOwnedElement(< O : Element | ownedElementCNt : L ; (O1, R) ; L1 >, O1) =
< O : Element | ownedElementCNt : L ; L1 > if R :: OwnedCommentRC .
eq rmvOwnedElement(< O : Element | >, O1) = < O : Element | > [owise] .
endom)
(omod UML2-KERNEL-ELEMENT-WF is
inc UML2-KERNEL-ELEMENT .
*** public methods, please don't override
msgs check : Oid -> Msg . --- !!! required global variable g-m1CK(true, none) !!!
op groupCkNotOwnThis : Set(Oid) Oid -> Object [ctor object] .
msgs ckNotOwnSelf-r : Oid Bool -> Msg .
*** output method for subclass to do themself check
msgs Element->check-r : Oid Bool -> Msg .
*** private methods
op ckNotOwnSelf : Oid Set(Oid) -> Configuration [ctor] .
op ckOwnedElements : Set(Oid) -> Configuration [ctor] .
vars N S : Oid . *** N : current Node, S : Src
vars B : Bool .
vars R : RoleCode .
vars LT : List(Lmr(String | Oid | Bool)) .
vars L L1 : List(ConnNode) .
vars NS : Set(Oid) .
--- check global error state(only here) and avoid reEnter
crl [Element::check] : check(N) < N : Element | >
g-m1CK(LT, true) => < N : Element | > g-m1CK(("checking...", N, true) ; LT, true)
ckNotOwnSelf(N, getOwnedElements(< N : Element | >))
if not hasChecked(LT, "checking...", N) .
--- crl [Element::check.reEnter] : check(N) < N : Element | >
--- g-m1CK(B, L) => < N : Element | > g-m1CK(B, L)
--- if not B or hasChecked("Element::check.b", N, L) . *** eat check(N) if reEnter
rl [Element::groupCkNotOwnThis.OK] : groupCkNotOwnThis(mt, S)
=> ckNotOwnSelf-r(S, true) .
crl [Element::groupCkNotOwnThis.Fail] : groupCkNotOwnThis(N NS, S)
< N : Element | > => < N : Element | > ckNotOwnSelf-r(S, false)
if isOwnedElement(< N : Element | >, S) .
crl [Element::groupCkNotOwnThis.Cont] : groupCkNotOwnThis(N NS, S)
< N : Element | > => < N : Element | >
groupCkNotOwnThis(NS getOwnedElements(< N : Element | >), S)
if not isOwnedElement(< N : Element | >, S) .
--- ckNotOwnSelf-r
*** finished and OK+(bootstrap owned elements' checking)
rl [Element::ckNotOwnSelf-r.OK+] : ckNotOwnSelf-r(N, true)
< N : Element | > g-m1CK(LT, true) =>
< N : Element | > g-m1CK(("Element::ckNotOwnSelf", N, true) ; LT, true)
Element->check-r(N, true) ckOwnedElements(getOwnedElements(< N : Element | >)) .
rl [Element::ckNotOwnSelf-r.OK-] : ckNotOwnSelf-r(N, true)
< N : Element | > g-m1CK(LT, false) => < N : Element | >
g-m1CK(("Element::ckNotOwnSelf", N, true) ; LT, false) . *** finished and OK-
rl [Element::ckNotOwnSelf.Fail] : ckNotOwnSelf-r(N, false)
< N : Element | > g-m1CK(LT, B) =>
< N : Element | > g-m1CK(("Element::ckNotOwnSelf", N, false) ; LT, false) .
*** finished and FAIL
*** private methods
eq ckNotOwnSelf(N, N NS ) = ckNotOwnSelf-r(N, false) .
eq ckNotOwnSelf(N, mt) = ckNotOwnSelf-r(N, true) .
eq ckNotOwnSelf(N, NS) = groupCkNotOwnThis(NS, N) [owise] .
eq ckOwnedElements(mt) = none .
eq ckOwnedElements(N NS) = check(N) ckOwnedElements(NS) .
endom)