Есть ли способ объединить области в xtext, когда QualifiedNames невозможно? - PullRequest
0 голосов
/ 07 августа 2020

Предположим следующую простую грамматику

(настоящая грамматика намного сложнее, и я хочу использовать неквалифицированные имена, чтобы различать guish различные типы ссылок, сохраняя простые "точечные" выражения для любого типа ссылок (исходная грамматика очень разрешительна на своем языке выражений).

Простой пример грамматики

Model: elements+=Element*;

Element: Entity | Field | Eval;

Entity:
  "entity" name=ID "{" members+=Element* "}";

Field:
  "field" name=ID ":" type=[Entity|ID];

Declaration:
  Field | Entity

Eval: "eval" Expression;

Expression: DotExpr;

DotExpr returns Expression:
  [Declaration|ID] ({DotExpr.head=current} '.' tail=[Declaration|ID])*;

Текст программы, написанный на эта грамматика может выглядеть так (включая пример того, что я хочу заставить работать):

Пример языкового содержимого

entity Orb {}

entity Foo {
  entity Bar {
    field orb : Orb
  }
}

entity Foo {
  entity Raboof {
    field foo : Foo.Bar

    // here for `foo` the scope of the referenced 
    // field `foo` needs to be computed
    // (indirect scope of the entity `Bar` in `Foo`
    //  referenced by the referenced field `foo`)
    eval foo.orb

    // Here for `Foo` and `Bar` the default
    // referencing mechanism would work
    // (direct scope of the referenced entity `Bar` in `Foo`)
    eval Foo.Bar.orb
  }
}

// these should also both be valid and resolve accordingly:
eval Foo.Bar
eval Foo.Raboof

Простое определение области для DotExpr, которое нарушает желаемое поведение

class ExampleScopeProvider extends AbstractExampleScopeProvider {
    override getScope(EObject context, EReference reference) {

        if (reference == ExamplePackage.eINSTANCE.dotExpr_Tail) {
            val dotExpr = context.eContainer as DotExpr
            val head = dotExpr.head

            // if its an indirect reference:
            if (head instanceof Field) {
              return Scopes::scopeFor(head.type.members)
            }
            // otherwise just directly get the entities members
            return Scopes::scopeFor(dotExpr.head.members)
        }

        return super.getScope(context, reference)
    }
}

Вышеупомянутое разрешение области видимости будет работать отлично, когда есть уникальные имена, но как только я захочу разрешить что-то, как указано выше, где Foo должен одновременно помещать члены обеих сущностей с именем Foo в область видимости (Bar и Raboof) он, конечно, ломается.

То, что я думал до сих пор

С квалифицированными именами * 10 27 * Конечно, самый простой способ добиться желаемого поведения - разрешить QualifiedName ссылку, тогда весь процесс будет работать из коробки без какой-либо необходимой дополнительной работы. Но это сломает желаемая функциональность с косвенными ссылками, также использующая точку (.) для выбора. Я мог бы разрешить квалифицированные имена и изменить правило выбора с помощью другого грамматического элемента, такого как ->, чтобы я имел для ссылки на косвенные ссылки через, например, foo->orb, но я бы очень хотел, чтобы грамматика была как можно более простой и интуитивно понятной и избегала введения другого элемента syntacti c. Custom scoping Вероятно, решение заключается в каком-то способе настраиваемой области видимости, но я пока не мог этого понять. Возможно, можно объединить области действия всех объектов, которые выбраны левой стороной DotExpr когда я хочу разрешить правую сторону. Но я не уверен, будет ли это наиболее эффективным решением, и особенно нетривиальным. Что-то вроде этого: class ExampleScopeProvider extends AbstractExampleScopeProvider { override getScope(EObject context, EReference reference) { if (reference == ExamplePackage.eINSTANCE.dotExpr_Tail) { val containingDotExpr = context.eContainer as DotExpr val parentScope = super.getScope( containingDotExpr, ExamplePackage.eINSTANCE.dotExpr_Head) val membersOfAllParentScopeEntities = parentScope.map(obj|obj.EObjectOrProxy.members).flatten return Scopes::scopeFor(membersOfAllParentScopeEntities) } return super.getScope(context, reference) } } Есть ли другой, возможно, канонический или распространенный способ чтобы добиться этого слияния областей видимости?
...