9.4.1 环境

环境的定义具有如下不变式和操作规约。

[1] 属性EMPTYP_ENV用作一个助手以避免 new Environment(...)

context Environment
inv EMPTY_ENV_Definition: EMPTY_ENV.namedElements->isEmpty()

[2] 基于名称来当前环境(而非在它的父亲)中查找一个命名元素。

context Environment::lookupLocal(name : String) : NamedElement
post: result = namedElements->any(v | v.name = name)

[3] 基于名称在当前的环境或它的福环境中递归的查找一个命名元素。

context Environment::lookup(name: String) : ModelElement
post: result = if not lookupLocal(name).oclIsUndefined() then
                lookupLocal(name).referredElement
                else
                    parent.lookup(name)
                endif

[4] 基于路径名在当前的环境或它的父环境中递归的查找一个命名元素。

context Environment::lookupPathName(names: Sequence(String)) : ModelElement
post: let firstNamespace : ModelElement = lookupLocal( names->first() ).referredElement
in
    if firstNamespace.oclIsKindOf(Namespace)
    -- indicates a sub namespace of the namespace in which self is present
    then
        result = self.nestedEnvironment().addNamespace(
            firstNamespace ).lookupPathName( names->subSequence(2, names->size()) )
    else
    -- search in surrounding namespace
        result = parent.lookupPathName( names )
    endif

[5] 向环境中添加新的命名元素。注意该操作定义为一个只读操作,因此可以用于OCL约束。

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] 合并两个环境产生一个新环境。注意该操作被定义为一个只读操作,从而可以用于OCL约束。

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] 把命名空间中的所有元素添加到环境中。

context Environment::addNamespace(ns: Namespace) : Environment
post: result.namedElements = ns.getEnvironmentWithoutParents().namedElements->union(
                                                                self.namedElements)
post: result.parent = self.parent

[8] 在当前环境内产生一个新的环境。

context Environment::nestedEnvironment() : Environment
post: result.namedElements->isEmpty()
post: result.parent = self
post: result.oclIsNew()

[9] 在当前环境(包括它的父亲)内查找一个隐式命名元素的给定属性名)。

context Environment::lookupImplicitAttribute(name: String) : Attribute
pre: -- none
post: result =
    lookupImplicitSourceForAttribute(name).referredElement.oclAsType(Attribute)

[10] 在当前的环境(包括它的父亲)内查找一个给定属性名的隐式source。

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 foundElement.oclIsUndefined() then
        self.parent.lookupImplicitSource ForAttribute(name)
        else
            foundElement
        endif

[11] 在当前的环境(包括它的父亲)内查找一个隐式命名元素的给定关联端。

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
        endif

[12] 在当前的环境(包括它的父亲)内利用给定的名称和参数类型查找一个隐式命名元素的操作。

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
      endif

在OCL 2.0和2.2中,关键字可以加下划线前缀来用作一个名称。因此,为了兼容性,对带有下划线前缀的simpleNameCS[A]名称的查找需要执行两次。第一次查找带下划线前缀的,如果没有找到,再查找不带下划线前缀的。

对于simpleNameCS[B]或[C](有单引号包裹)的名称不需要进行二次查找。

删除下划线前缀的第二次查找在OCL 2.3中已经不推荐使用,并将在OCL 3.0中不再支持。对于此不推荐的使用,工具实现者应用提供一个告警消息。

results matching ""

    No results matching ""