xtext:自定义范围的有效方法

时间:2016-09-26 16:03:52

标签: customization xtext scoping

我尝试像这样定制范围:

在扩展AbstractMyDslScopeProvider的文件MyDslScopeProvider中, 我使用此签名实现了该功能:

override def IScope getScope(EObject context, EReference reference)

我用过这样的案例

if (reference == SpectraPackage.Literals.SOMETHING__POINTER)

但我的语法功能是它有参数,我们可以在本地变量中声明。我不希望那些局部变量和该函数的参数从外部可见,我希望它们只在函数内部可见,所以我做了类似的事情:

      if (contextDecl instanceof function) {

                val fun= contextDecl as function
                val allContentsCurrFile = EcoreUtil2.getAllContentsOfType(fun,Constant)
                EObjectsInScope.addAll(fun.params)
                EObjectsInScope.addAll(allContentsCurrFile)
                return Scopes.scopeFor(EObjectsInScope)

            }
else{
                val removeEobjects = newArrayList()
                EObjectsInScope.addAll(EcoreUtil2.getAllContentsOfType(root,EObject))
                val funList= EcoreUtil2.getAllContentsOfType(root,function) as List<function>
                    for(function f: funList){
                        removeEobjects.addAll(f.varDeclList)
                        removeEobjects.addAll(f.params.params)
                        removeEobjects.addAll(EcoreUtil2.getAllContentsOfType(f,Constant))
                    }

                EObjectsInScope.removeAll(removeEobjects)

                return Scopes.scopeFor(EObjectsInScope)

这对于获取所有EObject并删除我不希望从外部可见的变量(这需要花费很多时间)非常低效。 有一种方法可以提高效率吗? 感谢。

1 个答案:

答案 0 :(得分:0)

编辑:您可能对我对"Xtext: IResourceScopeCache for Avoid expensive scope calculation"

的回答感兴趣

首先,如果你在谈论局部变量,你可能不希望在声明它们之前允许使用局部变量,例如。

function foo() {
  x = x + 1;
  int x = 0;
}

所以你实际上是通过使用getAllContentsOfType()做了太多工作。

您正在尝试使用优化实现什么目标?在功能内部提供更好的内容辅助性能?具有小功能体的大量型号的速度更快?许多大型功能的速度更快?

请记住避免过早优化 - 保持代码可维护性更为重要,并且只有在不能扩展到实际需要处理的工作负载时才能优化速度。您是否使用分析器查找热点?在性能瓶颈方面,人的直觉可能是非常错误的。

无论如何,假设您需要提高作用域的速度,但是您没有大量的工作负载,作为第一个镜头,我建议使用TreeIterator遍历函数体,收集应该可见的局部变量,并使用EcoreUtil2.getAllContainers(context)的返回值作为何时使用prune()以及何时使用next()的指南。

即。

import static extension org.eclipse.xtext.EcoreUtil2.*
// ...

val predecessors = new ArrayList<EObject>

val iterator = EcoreUtils.getAllContents(function, true)
// Could be optimized further
val descentGuide = context.allContainers.dropWhile[it != function].toList.reverseView.iterator

var current = iterator.next
var nextDescent = descentGuide.next
while(current != context) {
  // collect list with local variables here
  predecessors += current
  if(current == nextDescent) {
      // Reached another ancestor of context - will look for the following ancestor next
      nextDescent = descentGuide.next
  } else {
      iterator.prune
  }
  current = iterator.next
}

// Reverse so innermost declarations shadow outer declarations
val localVariables = predecessors.filter(LocalVariableDeclaration).toList.reverseView

我没有编译/测试代码,但我希望这个想法变得清晰。

while循环应该在最后终止,因为在某些时候,将会到达context - 但为了更加健壮,将&& iterator.hasNext添加到while循环可能是有意义的。