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