2008-01-21 19:34:45 +00:00
|
|
|
signature TRANSFORM_LIBRARY =
|
|
|
|
sig
|
|
|
|
|
|
|
|
(**
|
|
|
|
* Generate an OCL constraint guaranteeing that source is unique over the
|
|
|
|
* supplied binary associations.
|
|
|
|
* @params {source,associations}
|
|
|
|
* @param source classifier that needs a uniqueness constraint
|
|
|
|
* @param associations binary associations the uniqueness constraint is
|
|
|
|
* defined over. An n-ary association are not a valid argument.
|
|
|
|
* @return an OCL constraint expressing the uniqueness requirement
|
|
|
|
*)
|
2008-01-22 17:29:47 +00:00
|
|
|
val uniquenessOclConstraint : Rep_Core.Classifier ->
|
|
|
|
Rep_Core.association list
|
|
|
|
-> Rep_Core.constraint
|
2008-01-21 19:34:45 +00:00
|
|
|
|
|
|
|
(**
|
|
|
|
* @params {source,multis,binaryAssocs}
|
|
|
|
*)
|
2008-01-22 17:29:47 +00:00
|
|
|
val multiplicityOclConstraint: Rep_Core.Classifier -> (int*int) list list ->
|
2008-01-24 21:08:57 +00:00
|
|
|
Rep_Core.associationend list ->
|
2008-01-23 15:43:03 +00:00
|
|
|
Rep_Core.constraint list
|
2008-01-24 21:08:57 +00:00
|
|
|
val consistencyOclConstraint: Rep_Core.Classifier ->
|
|
|
|
Rep_Core.Classifier ->
|
|
|
|
Rep_Core.associationend ->
|
|
|
|
Rep_Core.associationend list ->
|
|
|
|
Rep_Core.associationend list ->
|
|
|
|
(Rep_Core.Classifier * Rep_Core.constraint list)
|
2008-01-21 19:34:45 +00:00
|
|
|
|
2008-01-27 15:36:57 +00:00
|
|
|
(**
|
|
|
|
* Works through the list of classifiers and updates uses of oldAssoc
|
|
|
|
* to the appropriate association in newAssocs.
|
|
|
|
*
|
|
|
|
* @params {classifiers,(oldAssoc,newAssocs)}
|
|
|
|
* @param classifiers
|
|
|
|
* @param oldAssoc the association that has been removed from the model
|
|
|
|
* @param newAssocs the associations that have replaced oldAssoc
|
|
|
|
* @return the list of classifiers with references to the old association
|
|
|
|
* removed
|
|
|
|
*)
|
|
|
|
val updateAssociationReferences: Rep_Core.Classifier list ->
|
|
|
|
(Rep_Core.association *
|
|
|
|
Rep_Core.association list) list ->
|
|
|
|
Rep_Core.Classifier list
|
|
|
|
|
2008-01-21 19:34:45 +00:00
|
|
|
(**
|
2008-01-22 17:29:47 +00:00
|
|
|
* @params {association,assocMembers}
|
2008-01-21 19:34:45 +00:00
|
|
|
* @param association n-ary association that should be split into it's binary
|
|
|
|
* links.
|
2008-01-22 17:29:47 +00:00
|
|
|
* @param assocMembers defines the ordering of the returned values, namely it
|
|
|
|
* defines the ordering of clsses.
|
2008-01-21 19:34:45 +00:00
|
|
|
* @return a tuple containting a list classifiers, a list of role names, a list
|
|
|
|
* of association ends and a list of binary associations:
|
|
|
|
* (clsses, roleNames, oppAends, splitAssocs).
|
|
|
|
* Each "line" is associated with a classifier of clsses: roleName 1, oppAends
|
|
|
|
* 1 and splitAssocs 1 belong to clsses 1.
|
|
|
|
* Each element of the result lists:
|
|
|
|
* clsses: Classifiers of the association
|
|
|
|
* roleNames: unqualified role name that denoted the associated classifier in
|
|
|
|
* the original association
|
|
|
|
* oppAends: the opposite aends of the newly generated binary associations,
|
|
|
|
* that the associated classifier from clsses is part of.
|
|
|
|
* splitAssocs: ass oppAends, only the full binary association
|
|
|
|
*)
|
2008-01-22 17:29:47 +00:00
|
|
|
val splitNAryAssociation: Rep_Core.association -> Rep_Core.Classifier list ->
|
|
|
|
(Rep_Core.Classifier list * string list *
|
|
|
|
Rep_Core.associationend list list *
|
|
|
|
Rep_Core.association list list)
|
2008-01-21 19:34:45 +00:00
|
|
|
|
|
|
|
(**
|
|
|
|
* Rearrange the oppRefAends to mirror the ordering of oppAends
|
|
|
|
* @params {oppRefAends,oppAends}
|
|
|
|
* @param oppRefAends
|
|
|
|
* @param oppAends
|
|
|
|
* @return the elements of oppRefAends in the same order as oppAends, given
|
|
|
|
* the classifier and the role name
|
|
|
|
*)
|
2008-01-22 17:29:47 +00:00
|
|
|
val matchAends: Rep_Core.associationend list ->
|
|
|
|
Rep_Core.associationend list ->
|
|
|
|
Rep_Core.associationend list
|
2008-01-21 19:34:45 +00:00
|
|
|
|
|
|
|
(**
|
|
|
|
*
|
|
|
|
*)
|
2008-01-24 21:08:57 +00:00
|
|
|
val matchAendsAtClassifier: Rep_Core.associationend list ->
|
|
|
|
(Rep_Core.Classifier * string) list
|
|
|
|
-> Rep_Core.associationend list
|
|
|
|
|
|
|
|
val matchClassifiersAtAend: Rep_Core.associationend list ->
|
|
|
|
Rep_Core.Classifier list ->
|
|
|
|
(Rep_Core.Classifier list *
|
|
|
|
Rep_Core.Classifier list )
|
2008-01-21 19:34:45 +00:00
|
|
|
|
2008-01-22 17:29:47 +00:00
|
|
|
(**
|
|
|
|
* Form binary associations between
|
|
|
|
* @params {source,targets,aends}
|
|
|
|
* @param source one of the ends for each of the binary associations
|
|
|
|
* @param targets each target is the second aend in exactly one of the
|
|
|
|
* resulting associations
|
|
|
|
* @param aends original associationends at the targets. The returned
|
|
|
|
* associationends. oppRefAends are in the same order as the
|
|
|
|
* supplied aends and denote the new association ends
|
|
|
|
* @returns (binaryAssocs,oppRefAends)
|
|
|
|
*)
|
2008-01-21 19:34:45 +00:00
|
|
|
val binaryAssociations: Rep_Core.Classifier -> Rep_Core.Classifier list ->
|
2008-01-22 17:29:47 +00:00
|
|
|
Rep_Core.associationend list ->
|
|
|
|
(Rep_Core.association list *
|
|
|
|
Rep_Core.associationend list)
|
2008-01-21 19:34:45 +00:00
|
|
|
|
2008-01-22 17:29:47 +00:00
|
|
|
val nextUid: unit -> string
|
2008-01-21 19:34:45 +00:00
|
|
|
(**
|
|
|
|
* Helper function for generating new, unique classes within a given
|
|
|
|
* package.
|
|
|
|
*)
|
2008-01-22 17:29:47 +00:00
|
|
|
val newDummyClass: Rep_OclType.Path -> Rep_Core.Classifier
|
2008-01-21 19:34:45 +00:00
|
|
|
|
2008-01-23 15:43:03 +00:00
|
|
|
val fixAends: Rep_OclTerm.OclTerm -> Rep_Core.associationend list
|
|
|
|
-> (Rep_OclTerm.OclTerm * Rep_OclTerm.OclTerm list)
|
|
|
|
|
2008-01-21 19:34:45 +00:00
|
|
|
val isPureNAryAssoc: Rep_Core.association -> bool
|
2008-01-27 15:36:57 +00:00
|
|
|
val isPureQualifier: Rep_Core.association -> bool
|
2008-01-25 14:56:51 +00:00
|
|
|
val isPureAcAssoc: Rep_Core.association -> bool
|
2008-01-21 19:34:45 +00:00
|
|
|
(**
|
|
|
|
* returns true iif assoc is purely a binary association, without any
|
|
|
|
* additional adornments, such as aggregation, qualifier, association class,
|
|
|
|
* etc.
|
|
|
|
* @params {assoc}
|
|
|
|
* @param assoc association to be tested
|
|
|
|
* @return true iif assoc is a pure binary association
|
|
|
|
*)
|
|
|
|
val isPureBinAssoc : Rep_Core.association -> bool
|
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
(**
|
|
|
|
* returns the path of an association end. The path of an association end
|
|
|
|
* is <path_of_association>@[<name_of_aend>].
|
|
|
|
* @params {aend}
|
|
|
|
* @param aend association end
|
|
|
|
* @return path of association end
|
|
|
|
*)
|
|
|
|
val path_of_aend : Rep_Core.associationend -> Rep_OclType.Path
|
|
|
|
|
|
|
|
val role_of_aend : Rep_Core.associationend -> string
|
|
|
|
(**
|
|
|
|
* returns the type of the classifier this association end belongs to.
|
|
|
|
* @params {aend}
|
|
|
|
* @param aend association end
|
|
|
|
* @return type of the classifier at the association end
|
|
|
|
*)
|
|
|
|
val type_of_aend : Rep_Core.associationend -> Rep_OclType.OclType
|
|
|
|
(**
|
|
|
|
* returns the association this association end belongs to.
|
|
|
|
* @params {aend}
|
|
|
|
* @param aend association end
|
|
|
|
* @return the path of the enclosing association
|
|
|
|
*)
|
|
|
|
val association_of_aend : Rep_Core.associationend -> Rep_OclType.Path
|
|
|
|
(**
|
|
|
|
* returns the name of the association end. The name of the association
|
|
|
|
* end is the last part of the association end's path.
|
|
|
|
* @params {aend}
|
|
|
|
* @param aend association end
|
|
|
|
* @return name of the association end as string.
|
|
|
|
*)
|
|
|
|
val name_of_aend : Rep_Core.associationend -> string
|
|
|
|
(**
|
|
|
|
* returns the list of specified multiplicities for this association end.
|
|
|
|
* @params {aend}
|
|
|
|
* @param aend association end
|
|
|
|
* @return the list of multiplicities of this association end. If there are
|
|
|
|
* no multiplicities, an empty list is returned.
|
|
|
|
*)
|
|
|
|
val multiplicities_of_aend : Rep_Core.associationend -> (int*int) list
|
|
|
|
|
|
|
|
(**
|
|
|
|
* Remove all multiplicities from the association
|
|
|
|
* @params {assoc}
|
|
|
|
* @param assoc association
|
|
|
|
* @return assoc with all multiplicities removed
|
|
|
|
*)
|
|
|
|
val stripMultiplicities : Rep_Core.association -> Rep_Core.association
|
|
|
|
(* result: (Variable list , OCL expression for set intersection)*)
|
|
|
|
val reachableSet : Rep_Core.associationend -> Rep_Core.associationend list -> (Rep_OclTerm.OclTerm list * Rep_OclTerm.OclTerm)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
val modifyAssociationsOfClassifier: Rep_Core.association list ->
|
|
|
|
Rep_Core.association list ->
|
|
|
|
Rep_Core.Classifier -> Rep_Core.Classifier
|
|
|
|
|
|
|
|
|
|
|
|
val withinBounds : Rep_OclTerm.OclTerm -> (int*int) -> Rep_OclTerm.OclTerm
|
|
|
|
val withinAendMultiplicities : Rep_Core.associationend -> Rep_Core.associationend list -> string -> Rep_Core.constraint
|
|
|
|
val injectiveConstraint : Rep_OclType.Path -> Rep_OclType.OclType -> Rep_Core.associationend list -> string -> Rep_Core.constraint
|
|
|
|
val updateClassifiersWithConstraints: Rep_Core.Classifier list ->
|
|
|
|
Rep_OclType.OclType ->
|
|
|
|
Rep_Core.constraint list ->
|
|
|
|
Rep_Core.Classifier list
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-01-22 17:29:47 +00:00
|
|
|
val uid: int ref
|
2008-01-21 19:34:45 +00:00
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
val multiplicity_of_aend: Rep_Core.associationend -> (int * int) list
|
2008-01-23 19:21:52 +00:00
|
|
|
val package_of_aend: Rep_Core.associationend -> Rep_OclType.Path
|
|
|
|
val name_of_association: Rep_Core.association -> Rep_OclType.Path
|
|
|
|
val package_of_association: Rep_Core.association -> Rep_OclType.Path
|
|
|
|
val variableFromAend: Rep_Core.associationend -> Rep_OclTerm.OclTerm
|
|
|
|
val variableFromClassifier: Rep_Core.Classifier -> Rep_OclTerm.OclTerm
|
|
|
|
val quantifyForAll: Rep_OclTerm.OclTerm list -> Rep_OclTerm.OclTerm ->
|
|
|
|
Rep_OclTerm.OclTerm
|
2008-01-23 15:43:03 +00:00
|
|
|
|
2008-01-22 17:29:47 +00:00
|
|
|
exception InvalidArguments of string
|
2008-01-22 14:21:28 +00:00
|
|
|
end
|
2008-01-21 19:34:45 +00:00
|
|
|
|
2008-01-22 17:29:47 +00:00
|
|
|
|
2008-01-21 19:34:45 +00:00
|
|
|
structure Transform_Library:TRANSFORM_LIBRARY =
|
|
|
|
struct
|
|
|
|
|
2008-01-22 14:21:28 +00:00
|
|
|
open library
|
|
|
|
open StringHandling
|
2008-01-22 17:29:47 +00:00
|
|
|
open Rep_OclTerm
|
|
|
|
open Rep_OclHelper
|
|
|
|
open Rep_Core
|
|
|
|
|
|
|
|
exception InvalidArguments of string
|
|
|
|
|
|
|
|
val uid = ref 0
|
|
|
|
|
|
|
|
fun nextUid () = (uid := !uid + 1; "_S"^(Int.toString (!uid)))
|
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
fun get_short_name (path:Path):string =
|
|
|
|
List.last path
|
|
|
|
|
2008-01-27 15:36:57 +00:00
|
|
|
fun stripMultiplicities ({name,aends,qualifiers,aclass}:association):
|
|
|
|
association =
|
2008-01-24 21:08:57 +00:00
|
|
|
let
|
|
|
|
fun handleAend {name,aend_type,multiplicity,visibility,
|
|
|
|
ordered,init} =
|
2008-01-27 15:36:57 +00:00
|
|
|
{name=name,
|
|
|
|
aend_type=aend_type,
|
|
|
|
multiplicity=[],
|
|
|
|
visibility=visibility,
|
|
|
|
ordered=ordered,
|
|
|
|
init=init}
|
2008-01-24 21:08:57 +00:00
|
|
|
in
|
|
|
|
{name = name,
|
|
|
|
aends = map handleAend aends,
|
2008-01-27 15:36:57 +00:00
|
|
|
qualifiers = [] (* FIXME: sensible?*),
|
2008-01-24 21:08:57 +00:00
|
|
|
aclass = aclass}
|
|
|
|
end
|
|
|
|
|
|
|
|
fun multiplicity_of_aend ({aend_type,multiplicity,...}:associationend) =
|
|
|
|
multiplicity
|
2008-01-23 15:43:03 +00:00
|
|
|
|
|
|
|
(* (JD) -> Rep_Core? *)
|
2008-01-24 21:08:57 +00:00
|
|
|
fun path_of_aend ({name,aend_type,...}:associationend) = name
|
|
|
|
fun name_of_aend ({name,aend_type,...}:associationend) =
|
|
|
|
short_name_of_path name
|
2008-01-23 15:43:03 +00:00
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
fun role_of_aend ({name,aend_type,...}:associationend) = List.last name
|
2008-01-23 15:43:03 +00:00
|
|
|
|
|
|
|
(* (JD) -> Rep_Core? *)
|
2008-01-24 21:08:57 +00:00
|
|
|
fun type_of_aend ({name,aend_type,...}:associationend) = aend_type
|
2008-01-23 15:43:03 +00:00
|
|
|
|
|
|
|
(* (JD) -> Rep_Core? *)
|
2008-01-24 21:08:57 +00:00
|
|
|
fun association_of_aend ({name,aend_type,...}:associationend) =
|
2008-01-23 15:43:03 +00:00
|
|
|
List.take(name, (List.length name)-1)
|
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
fun package_of_aend ({name,aend_type,...}:associationend) =
|
2008-01-23 15:43:03 +00:00
|
|
|
List.take(name, List.length name - 2)
|
|
|
|
|
2008-01-27 15:36:57 +00:00
|
|
|
fun name_of_association ({name,aends,qualifiers,aclass}:association) = name
|
2008-01-23 15:43:03 +00:00
|
|
|
|
2008-01-27 15:36:57 +00:00
|
|
|
fun package_of_association ({name,aends,qualifiers,aclass}:association) =
|
2008-01-23 15:43:03 +00:00
|
|
|
List.take(name, List.length name - 1)
|
|
|
|
|
|
|
|
(* (JD) -> Rep_Core? *)
|
2008-01-24 21:08:57 +00:00
|
|
|
fun multiplicities_of_aend ({aend_type,multiplicity,...}:associationend) =
|
|
|
|
multiplicity
|
2008-01-23 15:43:03 +00:00
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
fun short_name_of_aend ({name,aend_type,...}:associationend) =
|
|
|
|
short_name_of_path name
|
2008-01-23 15:43:03 +00:00
|
|
|
|
|
|
|
|
2008-01-22 17:29:47 +00:00
|
|
|
fun quantifyForAll variables body =
|
|
|
|
let
|
|
|
|
fun quantify (variable as Variable(_,varType),body) =
|
|
|
|
ocl_forAll (ocl_allInstances (Literal (List.last (path_of_OclType
|
|
|
|
varType),
|
|
|
|
varType)))
|
|
|
|
[variable] body
|
|
|
|
in
|
|
|
|
(* right most variable at the inner most position *)
|
|
|
|
foldr quantify body variables
|
|
|
|
end
|
2008-01-22 14:21:28 +00:00
|
|
|
|
2008-01-22 17:29:47 +00:00
|
|
|
|
2008-01-27 15:36:57 +00:00
|
|
|
fun isPureBinAssoc {name,aends=[a,b],qualifiers=[],aclass=NONE} = true
|
2008-01-22 17:29:47 +00:00
|
|
|
| isPureBinAssoc _ = false
|
|
|
|
|
2008-01-27 15:36:57 +00:00
|
|
|
fun isPureNAryAssoc {name,aends,qualifiers=[],aclass=NONE} =
|
|
|
|
List.length aends > 1
|
|
|
|
| isPureNAryAssoc _ = false
|
2008-01-22 17:29:47 +00:00
|
|
|
|
2008-01-27 15:36:57 +00:00
|
|
|
fun isPureQualifier {name,aends,qualifiers,aclass=NONE} =
|
|
|
|
List.length qualifiers > 1
|
|
|
|
| isPureQualifier _ = false
|
|
|
|
|
|
|
|
fun isPureAcAssoc {name,aends,qualifiers=[],aclass=SOME ac} =
|
|
|
|
List.length aends > 1
|
|
|
|
| isPureAcAssoc _ = false
|
2008-01-25 14:56:51 +00:00
|
|
|
|
2008-01-22 17:29:47 +00:00
|
|
|
fun newDummyClass package =
|
|
|
|
Class{name=Classifier (package@["Dummy"^ nextUid ()]),
|
|
|
|
parent=NONE,
|
|
|
|
attributes=[],
|
|
|
|
operations=[],
|
|
|
|
associations=[],
|
|
|
|
invariant=[],
|
|
|
|
stereotypes=[],
|
|
|
|
interfaces=[],
|
|
|
|
thyname=NONE,
|
|
|
|
activity_graphs=[]}
|
2008-01-21 19:34:45 +00:00
|
|
|
|
|
|
|
fun addAssociations newAssocs associations =
|
|
|
|
let
|
2008-01-22 17:29:47 +00:00
|
|
|
in
|
|
|
|
associations (* FIXME *)
|
2008-01-21 19:34:45 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
fun removeAssociations oldAssocs associations =
|
|
|
|
let
|
2008-01-22 17:29:47 +00:00
|
|
|
in
|
|
|
|
associations (* FIXME *)
|
2008-01-21 19:34:45 +00:00
|
|
|
end
|
|
|
|
|
2008-01-27 15:36:57 +00:00
|
|
|
fun updateAssociationReferences classifiers [] = classifiers
|
|
|
|
| updateAssociationReferences classifiers ((oldAssoc,newAssocs)::rem) =
|
|
|
|
let
|
|
|
|
in
|
|
|
|
classifiers (*FIXME*)
|
|
|
|
end
|
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
fun updateClassifiersWithConstraints classifiers oclType constraints =
|
|
|
|
let
|
|
|
|
val (match,rem) = List.partition (fn cls => type_of cls = oclType)
|
|
|
|
classifiers
|
|
|
|
in
|
|
|
|
map (addInvariants constraints) match @ rem
|
|
|
|
end
|
|
|
|
|
|
|
|
fun reachableSet (_:associationend) ([]:associationend list) =
|
|
|
|
error "rep_transform.get_reachableSet: empty source list"
|
|
|
|
| reachableSet (target:associationend) ([source]:associationend list) =
|
|
|
|
let
|
|
|
|
val src_var = Variable(name_of_aend source ,type_of_aend source)
|
|
|
|
in
|
|
|
|
([src_var], ocl_aendcall src_var (path_of_aend target)
|
|
|
|
(type_of_aend target))
|
|
|
|
end
|
|
|
|
| reachableSet (target:associationend) (source::rest) =
|
|
|
|
let
|
|
|
|
val (old_vars,intermediate) = reachableSet target rest
|
|
|
|
val src_var = Variable(name_of_aend source ,type_of_aend source)
|
|
|
|
val new_set = ocl_aendcall src_var (path_of_aend target)
|
|
|
|
(type_of_aend target)
|
|
|
|
in
|
|
|
|
(src_var::old_vars ,ocl_intersection_set new_set intermediate)
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
fun withinBounds (set:Rep_OclTerm.OclTerm) ((lower,upper):int*int):Rep_OclTerm.OclTerm =
|
|
|
|
let
|
|
|
|
val size = ocl_size set
|
|
|
|
val lower_lit = Literal (Int.toString lower,Integer)
|
|
|
|
val upper_lit = Literal (Int.toString upper,Integer)
|
|
|
|
val lower_bound = ocl_geq size lower_lit
|
|
|
|
val upper_bound = ocl_leq size upper_lit
|
|
|
|
in
|
|
|
|
ocl_and lower_bound upper_bound
|
|
|
|
end
|
|
|
|
|
|
|
|
fun withinAendMultiplicities targetAend sourceAends name =
|
|
|
|
let
|
|
|
|
val _ = trace function_calls "withinAendMultiplicities\n"
|
|
|
|
val tgtMultiplicities = multiplicities_of_aend targetAend
|
|
|
|
val tgtName = name_of_aend targetAend
|
|
|
|
val tgtType = type_of_aend targetAend
|
|
|
|
val (variables,set) = reachableSet targetAend sourceAends
|
|
|
|
val constrBody = ocl_or_all (map (withinBounds set) tgtMultiplicities)
|
|
|
|
val tgtVariable = Variable(tgtName^nextUid (),tgtType)
|
|
|
|
val allInstances = ocl_allInstances tgtVariable
|
|
|
|
val constrComplete = ocl_forAll allInstances variables constrBody
|
|
|
|
val constraint = (SOME name,constrComplete)
|
|
|
|
in
|
|
|
|
constraint
|
|
|
|
end
|
|
|
|
|
|
|
|
fun injectiveConstraint (source_path:Path) (source_type:OclType) (targets:associationend list) (name:string):constraint =
|
|
|
|
let
|
|
|
|
val source_name = get_short_name source_path
|
|
|
|
val src_var = Variable(source_name,source_type)
|
|
|
|
fun role_bounds src_var aend =
|
|
|
|
let
|
|
|
|
val name = path_of_aend aend
|
|
|
|
val aend_type = type_of_aend aend
|
|
|
|
val set = ocl_aendcall src_var name aend_type
|
|
|
|
val size = ocl_size set
|
|
|
|
val bounds = ocl_eq size (Literal("1",Integer))
|
|
|
|
in
|
|
|
|
bounds
|
|
|
|
end
|
|
|
|
fun role_equals src_var src2_var aend =
|
|
|
|
let
|
|
|
|
val name = path_of_aend aend
|
|
|
|
val aend_type = type_of_aend aend
|
|
|
|
val set = ocl_aendcall src_var name aend_type
|
|
|
|
val size = ocl_size set
|
|
|
|
val match = ocl_eq size (Literal("1",Integer))
|
|
|
|
in
|
|
|
|
match
|
|
|
|
end
|
|
|
|
val roles = map (role_bounds src_var) targets
|
|
|
|
val roles_part = ocl_and_all roles
|
|
|
|
val allInstances = ocl_allInstances src_var
|
|
|
|
val src_var2 = Variable(source_name^"2",source_type)
|
|
|
|
val matches = map (role_equals src_var src_var2) targets
|
|
|
|
val matches_anded = ocl_and_all roles
|
|
|
|
val matches_equal = ocl_eq src_var src_var2
|
|
|
|
val matches_imp = ocl_implies matches_anded matches_equal
|
|
|
|
val allInstances2 = ocl_allInstances src_var2
|
|
|
|
val matches_part = ocl_forAll allInstances2 [src_var2] matches_imp
|
|
|
|
val constr_body = ocl_and roles_part matches_part
|
|
|
|
val constr_complete = ocl_forAll allInstances [src_var] constr_body
|
|
|
|
in
|
|
|
|
(SOME name,constr_complete)
|
|
|
|
end
|
|
|
|
|
|
|
|
fun modifyAssociationsOfClassifier (newAssociations:association list)
|
|
|
|
(oldAssociations:association list)
|
2008-01-22 17:29:47 +00:00
|
|
|
(Class{name,parent,attributes,
|
|
|
|
operations,associations,invariant,
|
|
|
|
stereotypes,interfaces,thyname,
|
|
|
|
activity_graphs}) =
|
2008-01-21 19:34:45 +00:00
|
|
|
Class{name=name,
|
|
|
|
parent=parent,
|
|
|
|
attributes=attributes,
|
|
|
|
operations=operations,
|
|
|
|
associations= addAssociations newAssociations (removeAssociations
|
2008-01-22 17:29:47 +00:00
|
|
|
oldAssociations
|
2008-01-21 19:34:45 +00:00
|
|
|
associations),
|
|
|
|
invariant=invariant,
|
|
|
|
stereotypes=stereotypes,
|
|
|
|
interfaces=interfaces,
|
|
|
|
thyname=thyname,
|
|
|
|
activity_graphs=activity_graphs}
|
2008-01-22 17:29:47 +00:00
|
|
|
| modifyAssociationsOfClassifier newAssociations oldAssociations
|
|
|
|
(AssociationClass{name,parent,attributes,
|
|
|
|
operations,associations,
|
|
|
|
invariant,association,
|
|
|
|
stereotypes,interfaces,
|
|
|
|
thyname,activity_graphs}) =
|
2008-01-21 19:34:45 +00:00
|
|
|
AssociationClass{name=name,
|
|
|
|
parent=parent,
|
|
|
|
attributes=attributes,
|
|
|
|
operations=operations,
|
|
|
|
associations= addAssociations newAssociations
|
2008-01-22 17:29:47 +00:00
|
|
|
(removeAssociations oldAssociations
|
2008-01-21 19:34:45 +00:00
|
|
|
associations),
|
2008-01-22 17:29:47 +00:00
|
|
|
association=association,
|
2008-01-21 19:34:45 +00:00
|
|
|
invariant=invariant,
|
|
|
|
stereotypes=stereotypes,
|
|
|
|
interfaces=interfaces,
|
|
|
|
thyname=thyname,
|
|
|
|
activity_graphs=activity_graphs}
|
|
|
|
|
2008-01-22 17:29:47 +00:00
|
|
|
| modifyAssociationsOfClassifier newAssociations oldAssociations
|
|
|
|
(Primitive{name,parent,operations,
|
|
|
|
associations,invariant,
|
|
|
|
stereotypes,interfaces,
|
|
|
|
thyname}) =
|
2008-01-21 19:34:45 +00:00
|
|
|
Primitive {name=name,
|
|
|
|
parent=parent,
|
|
|
|
operations=operations,
|
|
|
|
associations= addAssociations newAssociations
|
2008-01-22 17:29:47 +00:00
|
|
|
(removeAssociations oldAssociations
|
2008-01-21 19:34:45 +00:00
|
|
|
associations),
|
|
|
|
invariant=invariant,
|
|
|
|
stereotypes=stereotypes,
|
|
|
|
interfaces=interfaces,
|
|
|
|
thyname=thyname}
|
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
fun uniquenessOclConstraint (source:Classifier) (associations:association list) =
|
2008-01-21 19:34:45 +00:00
|
|
|
let
|
2008-01-27 15:36:57 +00:00
|
|
|
fun assocAendCalls (self:OclTerm) (iter:OclTerm) {name,aends,qualifiers,
|
|
|
|
aclass} =
|
2008-01-21 19:34:45 +00:00
|
|
|
let
|
2008-01-27 15:36:57 +00:00
|
|
|
val [{name,aend_type,...}] =
|
|
|
|
filter (fn {aend_type,name,multiplicity,ordered,visibility,
|
|
|
|
init} => Rep_OclHelper.type_of self <> aend_type)
|
|
|
|
aends
|
2008-01-21 19:34:45 +00:00
|
|
|
val selfCall = ocl_aendcall self name (Collection aend_type)
|
|
|
|
val iterCall = ocl_aendcall iter name (Collection aend_type)
|
|
|
|
in
|
|
|
|
ocl_eq selfCall iterCall
|
|
|
|
end
|
2008-01-27 15:36:57 +00:00
|
|
|
|
2008-01-21 19:34:45 +00:00
|
|
|
val _ = trace function_calls "uniquenessOclConstraint\n"
|
|
|
|
val selfVar = self (type_of source)
|
2008-01-22 17:29:47 +00:00
|
|
|
val iterVar = Variable ("other"^nextUid (),type_of source)
|
2008-01-21 19:34:45 +00:00
|
|
|
val aendCalls = map (assocAendCalls selfVar iterVar) associations
|
2008-01-22 17:29:47 +00:00
|
|
|
val oclBody = ocl_implies (ocl_and_all aendCalls) (ocl_eq selfVar
|
2008-01-27 15:36:57 +00:00
|
|
|
iterVar)
|
2008-01-21 19:34:45 +00:00
|
|
|
val constr = quantifyForAll [iterVar] oclBody
|
|
|
|
in
|
|
|
|
(SOME "Uniqueness", constr)
|
|
|
|
end
|
|
|
|
|
2008-01-25 14:56:51 +00:00
|
|
|
fun binaryAssociations (source:Classifier) (targets:Classifier list) aends:
|
|
|
|
(association list * associationend list)=
|
2008-01-21 19:34:45 +00:00
|
|
|
let
|
|
|
|
val _ = trace function_calls "binaryAssociations\n"
|
2008-01-27 15:36:57 +00:00
|
|
|
fun generateAssociation target: (association * associationend)=
|
2008-01-21 19:34:45 +00:00
|
|
|
let
|
2008-01-24 21:08:57 +00:00
|
|
|
val assocName = package_of source @
|
2008-01-22 17:29:47 +00:00
|
|
|
["BinaryAssoc"^nextUid ()]
|
2008-01-23 15:43:03 +00:00
|
|
|
val oppAend = {name=assocName@[short_name_of target],
|
2008-01-22 17:29:47 +00:00
|
|
|
aend_type=type_of target,
|
|
|
|
multiplicity=[(1,1)],
|
|
|
|
ordered=false,
|
|
|
|
visibility=XMI_DataTypes.public,
|
2008-01-25 14:56:51 +00:00
|
|
|
init=NONE}:associationend
|
2008-01-21 19:34:45 +00:00
|
|
|
in
|
2008-01-22 17:29:47 +00:00
|
|
|
({name= assocName,
|
2008-01-23 15:43:03 +00:00
|
|
|
aends=[{name=assocName@ [short_name_of source],
|
|
|
|
aend_type=type_of source,
|
|
|
|
multiplicity=[],
|
|
|
|
ordered=false,
|
|
|
|
visibility=XMI_DataTypes.public,
|
|
|
|
init=NONE},
|
|
|
|
oppAend],
|
2008-01-27 15:36:57 +00:00
|
|
|
qualifiers=[],
|
2008-01-23 15:43:03 +00:00
|
|
|
aclass=NONE},
|
|
|
|
oppAend)
|
2008-01-22 17:29:47 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
fun order [] (x::xs) =
|
|
|
|
raise InvalidArguments ("binaryAssociations.order:"^
|
|
|
|
"arguments don't agree\n")
|
|
|
|
| order (x::xs) [] =
|
|
|
|
raise InvalidArguments ("binaryAssociations.order:"^
|
|
|
|
"arguments don't agree\n")
|
2008-01-25 14:56:51 +00:00
|
|
|
| order pairs ({name=refName,aend_type,multiplicity,
|
|
|
|
ordered,init,visibility}::aends) =
|
2008-01-22 17:29:47 +00:00
|
|
|
let
|
2008-01-25 14:56:51 +00:00
|
|
|
val ([oppAend],rem) = List.partition (fn (_,
|
|
|
|
{name=oppAendName,
|
|
|
|
aend_type,multiplicity,
|
|
|
|
ordered,visibility,
|
|
|
|
init}) =>
|
2008-01-24 21:08:57 +00:00
|
|
|
oppAendName = refName)
|
|
|
|
pairs
|
2008-01-22 17:29:47 +00:00
|
|
|
in
|
2008-01-27 15:36:57 +00:00
|
|
|
(oppAend :: (order rem aends))
|
2008-01-21 19:34:45 +00:00
|
|
|
end
|
2008-01-22 17:29:47 +00:00
|
|
|
|
|
|
|
|
2008-01-27 15:36:57 +00:00
|
|
|
val pairs:(association * associationend) list =
|
|
|
|
map generateAssociation targets
|
|
|
|
val orderedPairs:(association * associationend) list = order pairs aends
|
2008-01-21 19:34:45 +00:00
|
|
|
in
|
2008-01-27 15:36:57 +00:00
|
|
|
ListPair.unzip orderedPairs: (association list * associationend list)
|
2008-01-21 19:34:45 +00:00
|
|
|
end
|
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
fun variableFromAend ({name,aend_type,...}:associationend) =
|
2008-01-23 15:43:03 +00:00
|
|
|
Variable (toLower (short_name_of_path name)^nextUid (),aend_type)
|
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
fun variableFromClassifier (cls:Classifier) =
|
2008-01-23 15:43:03 +00:00
|
|
|
Variable (toLower (short_name_of cls)^nextUid () ,type_of cls)
|
2008-01-21 19:34:45 +00:00
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
fun roleToAend source ({name,aend_type,...}:associationend) =
|
2008-01-21 19:34:45 +00:00
|
|
|
ocl_aendcall source name (Collection aend_type)
|
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
fun fixAends source (aends:associationend list) =
|
2008-01-21 19:34:45 +00:00
|
|
|
let
|
|
|
|
fun equal (a,b) = ocl_eq a b
|
|
|
|
|
|
|
|
val vars = map variableFromAend aends
|
|
|
|
val roles = map (roleToAend source) aends
|
2008-01-24 21:08:57 +00:00
|
|
|
val body = ocl_and_all (map equal (ListPair.zip (roles,vars)))
|
2008-01-23 15:43:03 +00:00
|
|
|
val sourceType = Rep_OclHelper.type_of source
|
|
|
|
val ocl = ocl_select (ocl_allInstances
|
|
|
|
(Literal (short_name_of_OclType sourceType,
|
|
|
|
sourceType)))
|
2008-01-21 19:34:45 +00:00
|
|
|
source body
|
|
|
|
in
|
|
|
|
(ocl,vars)
|
|
|
|
end
|
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
fun multiplicityOclConstraint source multis oppAends =
|
2008-01-21 19:34:45 +00:00
|
|
|
let
|
2008-01-23 15:43:03 +00:00
|
|
|
val _ = trace function_calls "multiplicityOclConstraint\n"
|
2008-01-21 19:34:45 +00:00
|
|
|
fun bound set (low,high) =
|
2008-01-23 15:43:03 +00:00
|
|
|
ocl_and (ocl_leq (ocl_size set) (Literal(Int.toString high,Integer)))
|
|
|
|
(ocl_geq (ocl_size set) (Literal(Int.toString low,Integer)))
|
2008-01-21 19:34:45 +00:00
|
|
|
|
|
|
|
fun iterate _ [] done [] = []
|
2008-01-22 17:29:47 +00:00
|
|
|
| iterate source (multi::ys) done (a::xs) =
|
2008-01-21 19:34:45 +00:00
|
|
|
let
|
|
|
|
val (set,vars) = fixAends source (xs@done)
|
|
|
|
val body = ocl_or_all (map (bound set) multi)
|
|
|
|
in
|
2008-01-22 17:29:47 +00:00
|
|
|
(SOME "MultiplicityConstraint",quantifyForAll vars body)::
|
2008-01-23 15:43:03 +00:00
|
|
|
(iterate source ys (a::done) xs)
|
2008-01-21 19:34:45 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
val selfVar = self (type_of source)
|
|
|
|
in
|
2008-01-24 21:08:57 +00:00
|
|
|
iterate selfVar multis [] oppAends
|
2008-01-21 19:34:45 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
fun consistencyOclConstraint source reference selfAend roles refRoles =
|
|
|
|
let
|
|
|
|
val _ = trace function_calls "consistencyOclConstraint\n"
|
2008-01-24 21:08:57 +00:00
|
|
|
fun implies selfVar refVar {name=selfPath,aend_type=selfType,
|
|
|
|
multiplicity,init,visibility,ordered}
|
|
|
|
((role as {name=newPath,aend_type=newType,ordered=ord2,
|
|
|
|
init=init2,multiplicity=mult2,visibility=vis2}),
|
|
|
|
{name=refPath,aend_type=refType,multiplicity=multi3,
|
|
|
|
init=init3,visibility=vis3,ordered=ord3}) =
|
2008-01-21 19:34:45 +00:00
|
|
|
let
|
|
|
|
val var = variableFromAend role
|
2008-01-23 15:43:03 +00:00
|
|
|
val refVarType = Rep_OclHelper.type_of refVar
|
|
|
|
val refLit = Literal (short_name_of_OclType refVarType,
|
|
|
|
refVarType)
|
|
|
|
val link = ocl_exists (ocl_aendcall selfVar newPath
|
2008-01-21 19:34:45 +00:00
|
|
|
(Collection newType))
|
|
|
|
var ocl_true
|
2008-01-23 15:43:03 +00:00
|
|
|
val refOther = ocl_aendcall refVar refPath (Collection newType)
|
|
|
|
val refSelf = ocl_aendcall refVar selfPath (Collection selfType)
|
|
|
|
val included = ocl_exists (ocl_allInstances refLit) refVar
|
|
|
|
(ocl_and (ocl_eq refOther refVar)
|
|
|
|
(ocl_eq refSelf selfVar))
|
2008-01-21 19:34:45 +00:00
|
|
|
val body = ocl_implies link included
|
|
|
|
in
|
2008-01-22 17:29:47 +00:00
|
|
|
(SOME "ConsistencyConstraint", quantifyForAll [var] body)
|
2008-01-21 19:34:45 +00:00
|
|
|
end
|
|
|
|
|
2008-01-23 15:43:03 +00:00
|
|
|
val selfVar = self (type_of source)
|
|
|
|
val refVar = variableFromClassifier reference
|
2008-01-21 19:34:45 +00:00
|
|
|
|
|
|
|
in
|
2008-01-24 21:08:57 +00:00
|
|
|
(source, map (implies selfVar refVar selfAend )
|
|
|
|
(ListPair.zip (roles,refRoles)))
|
2008-01-21 19:34:45 +00:00
|
|
|
end
|
|
|
|
|
2008-01-27 15:36:57 +00:00
|
|
|
fun splitNAryAssociation (association as {name=assocPath::assocName,qualifiers,
|
2008-01-22 17:29:47 +00:00
|
|
|
aends,aclass}) classifiers =
|
2008-01-21 19:34:45 +00:00
|
|
|
let
|
|
|
|
val _ = trace function_calls "splitNAryAssociation\n"
|
2008-01-24 21:08:57 +00:00
|
|
|
fun updateClassifier ((clsType,newAssocs),classifiers) =
|
2008-01-21 19:34:45 +00:00
|
|
|
let
|
2008-01-27 15:36:57 +00:00
|
|
|
val ([cls],rem) = List.partition (fn x => type_of x = clsType )
|
|
|
|
classifiers
|
|
|
|
val modifiedCls = modifyAssociationsOfClassifier newAssocs
|
2008-01-22 17:29:47 +00:00
|
|
|
[association]
|
|
|
|
cls
|
2008-01-21 19:34:45 +00:00
|
|
|
in
|
2008-01-27 15:36:57 +00:00
|
|
|
modifiedCls::rem
|
2008-01-21 19:34:45 +00:00
|
|
|
end
|
2008-01-24 21:08:57 +00:00
|
|
|
|
2008-01-21 19:34:45 +00:00
|
|
|
fun iterate done [] = []
|
2008-01-23 19:21:52 +00:00
|
|
|
| iterate done ((aend as {name,aend_type,multiplicity,ordered,
|
2008-01-24 21:08:57 +00:00
|
|
|
visibility,init})::xs) =
|
2008-01-21 19:34:45 +00:00
|
|
|
let
|
2008-01-24 21:08:57 +00:00
|
|
|
fun makeAssoc (sourceAend as {name,aend_type,multiplicity,init,
|
|
|
|
ordered,visibility})
|
|
|
|
{name=targetName,aend_type=targetType,init=init2,
|
|
|
|
ordered=ord2,multiplicity=mult2,visibility=vis2} =
|
2008-01-21 19:34:45 +00:00
|
|
|
let
|
2008-01-22 17:29:47 +00:00
|
|
|
val assocPath = package_of_aend sourceAend
|
2008-01-23 15:43:03 +00:00
|
|
|
val assocName = short_name_of_path (association_of_aend
|
|
|
|
sourceAend)
|
2008-01-22 17:29:47 +00:00
|
|
|
val role = role_of_aend sourceAend
|
2008-01-23 15:43:03 +00:00
|
|
|
val newAssocName = assocPath@[assocName^ nextUid ()]
|
2008-01-22 17:29:47 +00:00
|
|
|
val oppAend = {name=newAssocName@[List.last targetName],
|
2008-01-21 19:34:45 +00:00
|
|
|
aend_type=targetType,
|
|
|
|
multiplicity=[],
|
|
|
|
ordered=false,
|
2008-01-22 17:29:47 +00:00
|
|
|
visibility=XMI_DataTypes.public,
|
2008-01-21 19:34:45 +00:00
|
|
|
init=NONE}
|
|
|
|
val binaryAssoc = {name=newAssocName,
|
|
|
|
aends=[{name=newAssocName@[role],
|
|
|
|
aend_type=aend_type,
|
|
|
|
multiplicity=[],
|
|
|
|
ordered=false,
|
2008-01-22 17:29:47 +00:00
|
|
|
visibility=XMI_DataTypes.public,
|
2008-01-21 19:34:45 +00:00
|
|
|
init=NONE},
|
|
|
|
oppAend],
|
2008-01-27 15:36:57 +00:00
|
|
|
qualifiers=[],
|
2008-01-21 19:34:45 +00:00
|
|
|
aclass=NONE}
|
|
|
|
in
|
|
|
|
(oppAend,binaryAssoc)
|
|
|
|
end
|
2008-01-27 15:36:57 +00:00
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
val (oppAends,binaryAssocs) = ListPair.unzip (map (makeAssoc aend)
|
|
|
|
(done@xs))
|
|
|
|
val role = short_name_of_path name
|
2008-01-21 19:34:45 +00:00
|
|
|
in
|
|
|
|
(aend_type,role,oppAends,binaryAssocs)::
|
|
|
|
(iterate (aend::done) xs)
|
|
|
|
end
|
2008-01-22 17:29:47 +00:00
|
|
|
|
|
|
|
fun order [] (x::xs) =
|
|
|
|
raise InvalidArguments ("splitNAryAssociation.order:"^
|
|
|
|
"arguments don't agree\n")
|
|
|
|
| order (x::xs) [] =
|
|
|
|
raise InvalidArguments ("splitNAryAssociation.order:"^
|
|
|
|
"arguments don't agree\n")
|
|
|
|
| order pairs (cls::clsses) =
|
|
|
|
let
|
2008-01-24 21:08:57 +00:00
|
|
|
val ([oppAend],rem) = List.partition (fn (oppType,_,_,_) =>
|
|
|
|
type_of cls = oppType)
|
2008-01-22 17:29:47 +00:00
|
|
|
pairs
|
|
|
|
in
|
2008-01-23 15:43:03 +00:00
|
|
|
oppAend :: (order rem clsses)
|
2008-01-22 17:29:47 +00:00
|
|
|
end
|
|
|
|
|
2008-01-23 15:43:03 +00:00
|
|
|
fun unzip4 [] = ([],[],[],[])
|
2008-01-22 17:29:47 +00:00
|
|
|
| unzip4 ((a,b,c,d)::xs) =
|
2008-01-21 19:34:45 +00:00
|
|
|
let
|
2008-01-23 15:43:03 +00:00
|
|
|
val (az,bs,cs,ds) = unzip4 xs
|
2008-01-21 19:34:45 +00:00
|
|
|
in
|
|
|
|
(a::az,b::bs,c::cs,d::ds)
|
|
|
|
end
|
|
|
|
|
2008-01-23 15:43:03 +00:00
|
|
|
fun getPaths assocs = map name_of_association assocs
|
2008-01-21 19:34:45 +00:00
|
|
|
|
|
|
|
(* generate new associations *)
|
2008-01-23 15:43:03 +00:00
|
|
|
val pairs = iterate [] aends
|
2008-01-24 21:08:57 +00:00
|
|
|
val (types,roleNames,oppAends,splitAssocs) = unzip4 (order pairs
|
2008-01-27 15:36:57 +00:00
|
|
|
classifiers)
|
|
|
|
|
2008-01-21 19:34:45 +00:00
|
|
|
(* update associations in classifiers to the new names *)
|
|
|
|
val modifiedClassifiers = foldl updateClassifier classifiers
|
2008-01-24 21:08:57 +00:00
|
|
|
(ListPair.zip (types,splitAssocs))
|
2008-01-21 19:34:45 +00:00
|
|
|
in
|
|
|
|
(modifiedClassifiers, roleNames, oppAends, splitAssocs)
|
|
|
|
end
|
|
|
|
|
|
|
|
(* target type and role name is unqiue, even with reflexive links *)
|
2008-01-24 21:08:57 +00:00
|
|
|
fun matchAends (oppRefAends:associationend list) oppAends =
|
2008-01-22 17:29:47 +00:00
|
|
|
let
|
2008-01-24 21:08:57 +00:00
|
|
|
fun findMatch {aend_type=oppAendType,name=oppName,multiplicity,init,
|
|
|
|
ordered,visibility} =
|
|
|
|
hd (List.filter (fn {aend_type=refAendType,name=refName,ordered,
|
|
|
|
visibility,init,multiplicity} =>
|
|
|
|
oppAendType = refAendType andalso
|
|
|
|
List.last oppName = List.last refName)
|
2008-01-23 15:43:03 +00:00
|
|
|
oppRefAends)
|
2008-01-22 17:29:47 +00:00
|
|
|
in
|
2008-01-24 21:08:57 +00:00
|
|
|
map findMatch oppAends
|
2008-01-22 17:29:47 +00:00
|
|
|
end
|
|
|
|
|
2008-01-24 21:08:57 +00:00
|
|
|
fun matchClassifiersAtAend aends classifiers =
|
|
|
|
let
|
|
|
|
fun match {name,aend_type,ordered,init,multiplicity,visibility} =
|
|
|
|
hd (List.filter (fn cls => type_of cls = aend_type)
|
|
|
|
classifiers)
|
|
|
|
|
|
|
|
fun remove (cls,classifiers) =
|
|
|
|
#2 (List.partition (fn x => type_of x = type_of cls) classifiers)
|
|
|
|
|
|
|
|
val matched = map match aends
|
|
|
|
val rem = foldl remove classifiers matched
|
|
|
|
in
|
|
|
|
(matched,rem)
|
|
|
|
end
|
|
|
|
|
2008-01-21 19:34:45 +00:00
|
|
|
(* target type and role name is still unqiue for classifiers and role *)
|
2008-01-24 21:08:57 +00:00
|
|
|
fun matchAendsAtClassifier oppRefAends pairs =
|
2008-01-21 19:34:45 +00:00
|
|
|
let
|
2008-01-24 21:08:57 +00:00
|
|
|
fun matchAend (cls,role) =
|
|
|
|
hd (filter (fn {aend_type,name,multiplicity,init,
|
|
|
|
ordered,visibility} =>
|
2008-01-23 15:43:03 +00:00
|
|
|
type_of cls = aend_type andalso
|
|
|
|
role = short_name_of_path name) oppRefAends)
|
2008-01-21 19:34:45 +00:00
|
|
|
in
|
2008-01-24 21:08:57 +00:00
|
|
|
map matchAend pairs
|
2008-01-21 19:34:45 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
|
2008-01-22 14:21:28 +00:00
|
|
|
end
|