Environment definition
The Environment type used in the rules for the concrete syntax is
defined according to the following invariants and additional
operations. A diagrammatic view can be found in Figure 13 Environments can be
nested, denoted by the existence of a parent environment. Each
environment keeps a list of named elements, that have a name a
reference to a ModelElement.
Environment
The definition of Environment has the following invariants and
specifications of its operations.
[1] The attribute EMPTY_ENV is really just a helper to avoid having to
say new Environment (...).
context Environment
inv EMPTY_ENV_Definition: EMPTY_ENV.namedElements->isEmpty()
[2] Find a named element in the current environment, not in its
parents, based on a single name.
context Environment::lookupLocal(name :
String) : NamedElement
post: result = namedElements->any(v | v.name = name)
[3] Find a named element in the current environment or recursively in
its parent environment, based on a single name.
context
Environment::lookup(name: String) : ModelElement
post: result = if not
lookupLocal(name).oclIsUndefined() then
lookupLocal(name).referredElement
else
parent.lookup(name)
endif
[4] Find a named element in the current environment or
recursively in its parent environment, based on a path name.
context
Environment::lookupPathName(names: Sequence(String)) : ModelElement
post: let firstNamespace :
ModelElement = lookupLocal( names->first() ).referredElement
in
if firstNamespace.isOclKind(Namespace)
-- indicates a sub namespace of the namespace in
which self is present
then
result =
self.nestedEnvironment().addNamespace(
firstNamespace
).lookupPathName( names->tail() )
else
-- search in
surrounding namespace
result =
parent.lookupPathName( names )
endif
[5] Add a new named element to the environment. Note that this
operation is defined as a query operation so that it can be
used in OCL constraints.
context Environment::addElement (name : String,
elem : ModelElement, imp : Boolean) : Environment
pre : -- the name must not clash with names already
existing in this environment
self.lookupLocal(name).oclIsUndefined()
post: result.parent = self.parent and
result.namedElements->includesAll (self.namedElements) and
result.namedElements->count (v
| v.oclIsNew()) = 1 and
result.namedElements->forAll
(v | v.oclIsNew() implies
v.name = name and v.referredElement = elem)
and
v.mayBeImplicit = imp )
[6] Combine two environments resulting in a new environment. Note that
this operation is defined as a query operation so
that it can be used in OCL constraints.
context Environment::addEnvironment(env :
Environment) : Environment
pre : -- the names must not clash with names already
existing in this environment
enf.namedElements->forAll(nm | self.lookupLocal(nm).oclIsUndefined()
)
post: result.parent = self.parent and
result.namedElements =
self.namedElements->union(env.namedElements)
[7] Add all elements in the namespace to the environment.
context Environment::addNamespace(ns:
Namespace) : Environment
post: result.namedElements =
ns.getEnvironmentWithoutParents().namedElements->union(
self.namedElements)
post: result.parent = self.parent
[8] This operation results in a new environment which has the current
one as its parent.
context
Environment::nestedEnvironment() : Environment
post: result.namedElements->isEmpty()
post: result.parent = self
post: result.oclIsNew()
[9] Lookup a given attribute name of an implicitly named
element in the current environment, including its parents.
context
Environment::lookupImplicitAttribute(name: String) : Attribute
pre: -- none
post: result =
lookupImplicitSourceForAttribute(name).referredElement.oclAsType(Attribute)
[10] Lookup the implicit source belonging to a given attribute
name in the current environment, including the parents.
context
Environment::lookupImplicitSourceForAttribute(name: String) :
NamedElement
pre: -- none
post: let foundElement : NamedElement =
namedElements->select(mayBeImplicit)
->any( ne |
not ne.getType().lookupAttribute(name).oclIsUndefined() ) in
result = if
foundAttribute.oclIsUndefined() then
self.parent.lookupImplicitSource ForAttribute(name)
else
foundElement
end
[11] Lookup up a given association end name of an implicitly
named element in the current environment, including its parents.
context Environment::lookupImplicitAssociationEnd(name: String) :
AssociationEnd
pre: -- none
post: let foundAssociationEnd : AssociationEnd =
namedElements->select(mayBeImplicit)
->any( ne |
not ne.getType().lookupAssociationEnd(name).oclIsUndefined() ) in
result = if foundAssociationEnd.oclIsUndefined() then
self.parent.lookupImplicitAssociationEnd(name)
else
foundAssociationEnd
end
[12] Lookup up an operation of an implicitly named element with
given name and parameter types in the current environment, including
its parents.
context
Environment::lookupImplicitOperation(name: String,
params : Sequence(Classifier)) :
Operation
pre: -- none
post: let foundOperation : Operation =
namedElements->select(mayBeImplicit)
->any( ne | not
ne.getType().lookupOperation(name, params).oclIsUndefined() ) in
result = if
foundOperation.oclIsUndefined() then
self.parent.lookupImplicitOperation(name)
else
foundOperation
end
NamedElement
A named element is a modelelement which is referred to by a name. A
modelement itself has a name, but this is not always the name which is
used to refer to it.
The operation getType() returns the type of the referred modelelement.
context NamedElement::getType() : Classifier
pre: -- none
post: referredElement.oclIsKindOf(VariableDeclaration) implies
result =
referredElement.oclAsType(VariableDeclaration).type
post: referredElement.oclIsKindOf(Classifier) implies
result = referredElement
post: referredElement.oclIsKindOf(State) implies
result = -- TBD: when aligning with UML 2.0
Infrastructure
Namespace
The following additional operation returns the information of the
contents of the namespace in the form of an Environment object, where
Environment is the class defined in this chapter. Note that the parent
association of Environment is not filled.
Because the definition of this operation is completely dependent on the
UML metamodel, and this model will be considerably different in the 2.0
version, the definition is left to be done.
context Namespace::getEnvironmentWithoutParents() : Environment
post: self.isTypeOf(Classifier) implies -- TBD when aligning with UML
2.0 Infrastrcuture
-- include all class features and contained
classifiers
post: self.isTypeOf(Package) implies -- TBD when aligning with UML 2.0
Infrastrcuture
-- include all classifiers and subpackages
post: self.isTypeOf(StateMachine)implies -- TBD when aligning with UML
2.0 Infrastrcuture
-- include all states
post: self.isTypeOf(Subsystem) implies -- TBD when aligning with UML
2.0 Infrastrcuture
-- include all classifiers and subpackages
The following operation returns an Environment that contains a
reference to its parent environment, which is itself created by this
operation by means of a recursive call, and therefore contains a parent
environment too.
context Namespace::getEnvironmentWithParents() : Environment
post: result.NamedElements = self.getEnvironmentWithoutParents()
post: if self.namespace->notEmpty() -- this namespace has an owning
namespace
then result.parent =
self.namespace.getEnvironmentWithParents()
else result.parent = OclUndefined
endif