问题描述
我有以下 Xtext 语法部分:
AssignmentStatement: (variable=[SymbolicVariable] | array=ArrayVariable) ':=' value=Expression;
ArrayVariable: varName=[SymbolicVariable] '[' index=Expression ']';
SymbolicVariable: name=ID;
和一个测试,其中 id1 和 id2 是 SymbolicVariable,而且 SymbolicVariable 可以是 Expression 的一部分:
id1 := 0 < id2 [ 0 ]
在测试中,id1 和 id2 之前没有定义,因为我是通过语法生成输入作为测试并且不关心语义。我想为它们动态创建对象以摆脱:
错误:无法解析对 SymbolicVariable 'id1' 的引用。
错误:无法解析对 SymbolicVariable 'id2' 的引用。
同时验证。
根据帖子 XText cross-reference to an non-DSL resource 中的想法,我能够创建 ScopeProvider impl 和 Scope impl:
class MyScope extends AbstractPoSTScopeProvider {
override getScope(EObject context,EReference reference) {
val res = context.eResource
var uri = res.URI
val rs = res.resourceSet
val scope = super.getScope(context,reference)
if (context instanceof ArrayVariableImpl) new ScopeWrapper(scope,res) else scope
}
}
class ScopeWrapper implements IScope {
IScope scope;
Resource resource;
protected new(IScope w,Resource res) {
scope = w
resource = res
}
override getSingleElement(Qualifiedname name) {
println("[scope]getSingleElement " + name.toString())
val r = scope.getSingleElement(name)
if (r === null) {
val fac = PoSTPackage.eINSTANCE.getPoSTFactory()
var s = fac.createSymbolicVariable()
s.name = name.toString()
println("[!!!!! ] creation")
Main.isChanged = true //to rerun in cause of modification
val ret = new MyDescr(s,name) //just a wrap
resource.contents += s
ret
} else
r
}
}
这次注入后,出现了id2,我可以用它生成一个代码,但我仍然得到
错误:无法解析对 SymbolicVariable 'id1' 的引用。
并且我在调试期间没有在任何地方看到 id1。
似乎,对于属性,我们需要一些其他魔法。 我应该遵循哪种模式?
解决方法
在测试中,id1 和 id2 之前没有定义,因为我是通过语法生成输入作为测试并且不关心语义。
如果您正在生成文本模型 id1 := 0 < id2 [ 0 ]
,我不确定为什么您不能将其生成为 id1; id2; id1 := 0 < id2 [ 0 ]
,这可能会解决问题。
如果您真的想“动态创建 id1 和 id2”,我认为您需要自定义 IScopeProvider
实现,以便在计算引用 AssignmentStatement.variable
和 ArrayVariable.varName
的范围时,如果父实现返回一个空作用域,那么您只需在内存中创建一个 SymbolicVariable
并在返回的作用域中提供它。