Xtext:在变量声明中推断类型不在接口生成中工作

时间:2015-07-28 14:33:08

标签: java xtext

我正在编写DSL的模型推理器,它从AbstractModelInferrer扩展而来。到目前为止,我已经成功地为一些语法结构生成了类,但是当我尝试生成一个接口时,类型inferrer不起作用,我得到以下异常:

0    [Worker-2] ERROR org.eclipse.xtext.builder.BuilderParticipant  - Error during compilation of 'platform:/resource/pascani/src/org/example/namespaces/SLA.pascani'.
java.lang.IllegalStateException: equivalent could not be computed

模型推导者代码是:

def dispatch void infer(Namespace namespace, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
    acceptor.accept(processNamespace(namespace, isPreIndexingPhase))
}

def JvmGenericType processNamespace(Namespace namespace, boolean isPreIndexingPhase) {
    namespace.toInterface(namespace.fullyQualifiedName.toString) [
        if (!isPreIndexingPhase) {
            documentation = namespace.documentation
            for (e : namespace.expressions) {
                switch (e) {
                    Namespace: {
                        members +=
                            e.toMethod("get" + Strings.toFirstUpper(e.name), typeRef(e.fullyQualifiedName.toString)) [
                                abstract = true
                            ]
                        members += processNamespace(e, isPreIndexingPhase);
                    }
                    XVariableDeclaration: {
                        members += processNamespaceVarDecl(e)
                    }
                }
            }
        }
    ]
}

def processNamespaceVarDecl(XVariableDeclaration decl) {
    val EList<JvmMember> members = new BasicEList();

    val field = decl.toField(decl.name, inferredType(decl.right))[initializer = decl.right]
    // members += field
    members += decl.toMethod("get" + Strings.toFirstUpper(decl.name), field.type) [
        abstract = true
    ]

    if (decl.isWriteable) {
        members += decl.toMethod("set" + Strings.toFirstUpper(decl.name), typeRef(Void.TYPE)) [
            parameters += decl.toParameter(decl.name, field.type)
            abstract = true
        ]
    }

    return members
}

我尝试在acceptor.accept方法之后使用延迟初始值设定项,但它仍然不起作用。

当我取消注释向界面添加字段的行members += field时,模型推导者工作正常;但是,如您所知,接口不能包含字段。

这对我来说似乎是个错误。我已经阅读了Eclipse论坛中的大量帖子,但似乎没有解决我的问题。如果需要,这是我的语法:

grammar org.pascani.Pascani with org.eclipse.xtext.xbase.Xbase

import "http://www.eclipse.org/xtext/common/JavaVMTypes" as types
import "http://www.eclipse.org/xtext/xbase/Xbase"

generate pascani "http://www.pascani.org/Pascani"

Model
    :   ('package' name = QualifiedName ->';'?)? 
        imports = XImportSection?
        typeDeclaration = TypeDeclaration?
    ;

TypeDeclaration
    :   MonitorDeclaration 
    |   NamespaceDeclaration
    ;

MonitorDeclaration returns Monitor
    :   'monitor' name = ValidID 
        ('using' usings += [Namespace | ValidID] (',' usings += [Namespace | ValidID])*)?  
        body = '{' expressions += InternalMonitorDeclaration* '}'
    ;

NamespaceDeclaration returns Namespace
    :   'namespace' name = ValidID body = '{' expressions += InternalNamespaceDeclaration* '}'
    ;

InternalMonitorDeclaration returns XExpression
    :   XVariableDeclaration
    |   EventDeclaration
    |   HandlerDeclaration
    ;

InternalNamespaceDeclaration returns XExpression
    :   XVariableDeclaration
    |   NamespaceDeclaration
    ;

HandlerDeclaration
    :   'handler' name = ValidID '(' param = FullJvmFormalParameter ')' body = XBlockExpression
    ;

EventDeclaration returns Event
    :   'event' name = ValidID 'raised' (periodically ?= 'periodically')? 'on'? emitter = EventEmitter ->';'?
    ;

EventEmitter
    :   eventType = EventType 'of' emitter = QualifiedName (=> specifier = RelationalEventSpecifier)? ('using' probe = ValidID)?
    |   cronExpression = CronExpression
    ;

enum EventType
    :   invoke
    |   return
    |   change
    |   exception
    ;

RelationalEventSpecifier returns EventSpecifier
    :   EventSpecifier ({RelationalEventSpecifier.left = current} operator = RelationalOperator right = EventSpecifier)*
    ;

enum RelationalOperator
    :   and
    |   or
    ;

EventSpecifier
    :   (below ?= 'below' | above ?= 'above' | equal ?= 'equal' 'to') value = EventSpecifierValue
    |   '(' RelationalEventSpecifier ')'
    ;

EventSpecifierValue
    :   value = Number (percentage ?= '%')?
    |   variable = QualifiedName
    ;

CronExpression
    :   seconds = CronElement       // 0-59
        minutes = CronElement       // 0-59
        hours   = CronElement       // 0-23
        days    = CronElement       // 1-31
        months  = CronElement       // 1-2 or Jan-Dec
        daysOfWeek = CronElement    // 0-6 or Sun-Sat
    |   constant = CronConstant
    ;

enum CronConstant
    :   reboot      // Run at startup
    |   yearly      // 0 0 0 1 1 *
    |   annually    // Equal to @yearly
    |   monthly     // 0 0 0 1 * *
    |   weekly      // 0 0 0 * * 0
    |   daily       // 0 0 0 * * *
    |   hourly      // 0 0 * * * *
    |   minutely    // 0 * * * * *
    |   secondly    // * * * * * *
    ;

CronElement
   :    RangeCronElement | PeriodicCronElement
   ;

RangeCronElement hidden()
   :    TerminalCronElement ({RangeCronElement.start = current} '-' end = TerminalCronElement)?
   ;

TerminalCronElement
   :    expression = (IntLiteral | ValidID | '*' | '?')
   ;

PeriodicCronElement hidden()
   :    expression = TerminalCronElement '/' elements = RangeCronList
   ;

RangeCronList hidden()
   :    elements += RangeCronElement (',' elements +=RangeCronElement)*
   ;

IntLiteral
    :   INT
    ;

更新

在找到解决方案之前,使用字段是继续使用其他内容的一种方法。实际代码是:

def processNamespaceVarDecl(XVariableDeclaration decl) {
    val EList<JvmMember> members = new BasicEList();
    val type = if (decl.right != null) inferredType(decl.right) else decl.type

    members += decl.toMethod("get" + Strings.toFirstUpper(decl.name), type) [
        abstract = true
    ]

    if (decl.isWriteable) {
        members += decl.toMethod("set" + Strings.toFirstUpper(decl.name), typeRef(Void.TYPE)) [
            parameters += decl.toParameter(decl.name, type)
            abstract = true
        ]
    }

    return members
}

1 个答案:

答案 0 :(得分:0)

来自Eclipse论坛的回答:

  

我不知道你做的是不是一个好主意。推词映射   你的概念到java概念,这使得范围界定   表达式。如果你没有表达你的表达的地方那么它   不会工作。他们的类型永远不会被计算

     

因此我认为你有一个使用xbase无法实现的用例   没有自定义。你的语义对我来说不太清楚。

Christian Dietrich

我的回答:

谢谢Christian,我虽然做错了。如果它似乎不是一个常见的用例,那么没有问题,我将确保用户明确定义一个变量类型。

为了澄清一点,命名空间用于定义监视器中使用的变量。这就是为什么命名空间成为一个接口,监视器成为一个类。

Read the Eclipse forum thread