2014-11-07 2 views
0

У меня есть следующие грамматики:Получить объявления из внешнего источника в XText

Model: declarations += Declaration* statements += Statement*; 
Declaration: 'Declare' name=ID; 
Statement: 'Execute' what=[Declaration]; 

С, что я могу писать простые сценарии, как:

Declare step_forward 
Declare turn_right 
Declare turn_left 

Execute step_forward 
Execute turn_left 
Execute step_forward 

Теперь я хочу, чтобы программа Java предоставляет все объявления , так что скрипт содержит только операторы Execute. Я читал около IGlobalScopeProvider, который кажется правильным инструментом для работы, но я понятия не имею, как добавить к нему свои данные и как использовать Xtext.

Итак, как я могу предоставить декларации из внешних по отношению к моей грамматике?

Update

Моя цель была несколько неясна, поэтому я стараюсь, чтобы сделать его более конкретным. Я хочу, чтобы заявления в качестве простых объектов Java, например:

List<Move> declarations = Arrays.asList(
    new Move("step_forward"), 
    new Move("turn_right"), 
    new Move("turn_left")); 

и сценарий должен быть:

Execute step_forward 
Execute turn_left 
Execute step_forward 

ответ

1

Я не совсем уверен, что вы просите. Подумав об этом, я понял следующие возможные вопросы:

1.) Вы хотите разбить скрипт на два файла. Файл a будет содержать только ваши объявления, а файл b будет содержать только сообщения. Но любой атрибут «какой» будет содержать ссылку на объявления файла a.

Это произведение из коробки с вашей грамматикой.

2.) У вас есть какой-либо исходный код Java, который предоставляет класс, который определяет, например, «Declare Interface», и вы хотите, чтобы атрибут «какой» ссылался на этот интерфейс или на классы, реализующие этот интерфейс.

Обновленный ответ Вы должны использовать Xbase на своем языке. Там вы можете определить, что ваш атрибут «what» ссылается на любой тип Java, используя правило Xtypes «JvmTypeReference». Изменения, которые вы должны в вашей грамматики не так сложно, я думаю, что это может выглядеть так:

// Grammar now inherits from the Xbase grammar 
// instead of the common terminals grammar 
grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.xbase.Xbase 

generate myDsl "http://www.xtext.org/example/mydsl/MyDsl" 

Model: 
    declarator=Declarator? 
    statements+=Statement*; 

Declarator: 
    'Declare' name=ID; 

Statement: 
    'Execute' what=JvmTypeReference; 

, вы можете обратиться к любому типу Java (Java API, любые связанные API, определяемые пользователем типы) по указав им свое квалифицированное имя. Это будет выглядеть так: Referring to JVM types look like this in an Xtext language. (Screenshot)

Вы также можете проверить, действителен ли ссылочный тип JVM, например. реализует желаемый интерфейс, который я бы определил с помощью одного, необязательного декларатора в модели. Referenced JVM type is checked whether it is a valid type. (Screenshot)

С Xbase очень легко вывести интерфейс Java для этого элемента модели. Используйте созданный окурок «... mydsl.MyDslJvmModelInferrer»:

class MyDslJvmModelInferrer extends AbstractModelInferrer { 

    @Inject extension JvmTypesBuilder 
    @Inject extension TypeReferences 
    def dispatch void infer(Model element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) { 
     acceptor.accept(
      element.declaration.toInterface('declarator.' + element.declaration.name) [ 
       members += it.toMethod("execute", TypesFactory.eINSTANCE.createJvmVoid.createTypeRef)[] 
      ]) 
    } 
} 

Он получает единый интерфейс, названный по отдельности только один метод „Execute()“.

Затем, реализуйте статические проверки, подобные этому, вы должны использовать сгенерированный заглушка '... mydsl.validation.MyDslValidator»В моем примере это очень быстрый и грязный, но вы должны получить представление о нем:

class MyDslValidator extends AbstractMyDslValidator { 

    @Check 
    def checkReferredType(Statement s) { 
     val declarator = (s.eContainer as Model).declaration.name 
     for (st : (s.what.type as JvmDeclaredType).superTypes) { 
      if (st.qualifiedName.equals('declarator.' + declarator)) { 
       return 
      } 
     } 
     (s.what.simpleName + " doesn't implement the declarator interface " + declarator). 
      warning(MyDslPackage.eINSTANCE.statement_What) 
    } 
} 

(я использовал предпочтительный язык программирования Xtend для реализации статической проверки!) Статическая проверка определяет, данный JvmTypeReference (который является Java-классом из вашего проекта) реализует объявленный интерфейс. В противном случае это приведет к предупреждению вашего документа dsl.

Надеюсь, это ответит на ваш вопрос.

Следующее обновление: Ваша идея не будет работать так хорошо! Вы можете просто написать шаблон с Xtend для этого без использования Xbase, но я не могу представить, как использовать его в хорошем смысле. Проблема заключается, я полагаю, вы не должны генерировать класс дыр 'Move' и процесс выполнения отверстия. Я немного поиграл, пытаясь создать полезный код и, похоже, взломан! Nevermhess, вот мое решение:

Xtext породил заглушку '... mydsl.generator.MyDslGenerator' для вас с помощью метода 'void doGenerate'. Вы должны заполнить этот метод. Моя идея такова: во-первых, вы создаете абстрактный и общий класс Executor с двумя генерическими параметрами T и U. Затем мой класс-исполнитель имеет абстрактный метод «executeMoves()» с возвращаемым значением T. Если это должно быть недействительным, используйте непримитивный класс «Пустота». Он содержит ваш список, но общий тип u, который определяется как подкласс класса Move.

Класс Move также будет сгенерирован, но только с полем для хранения строки. Затем он должен быть получен. Мой «MyDslGenerator» выглядит так:

class MyDslGenerator implements IGenerator { 
    static var cnt = 0 
    override void doGenerate(Resource resource, IFileSystemAccess fsa) { 
     cnt = 0 
     resource.allContents.filter(typeof(Model)).forEach [ m | 
      fsa.generateFile('mydsl/execution/Move.java', generateMove) 
      fsa.generateFile('mydsl/execution/Executor' + cnt++ + '.java', m.generateExecutor) 
     ] 
    } 

    def generateMove() ''' 
     package mydsl.execution; 
     public class Move { 
      protected String s; 
      public Move(String s) { 
       this.s = s; 
      } 
     } 
    ''' 

    def generateExecutor(Model m) ''' 
     package mydsl.execution; 
     import java.util.List; 
     import java.util.Arrays; 
     /** 
     * The class Executor is abstract because the execution has to implemented somewhere else. 
     * The class Executor is generic because one does not know if the execution has a return 
     * value. If it has no return value, use the not primitive type 'Void': 
     * public class MyExecutor extends Executor_i<Void> {...} 
     */ 
     public abstract class Executor«cnt - 1»<T, U extends Move> { 
      @SuppressWarnings("unchecked") 
      private List<U> declarations = Arrays.<U>asList(
       «FOR Statement s : m.statements» 
        (U) new Move("«s.what.name»")«IF !m.statements.get(m.statements.size - 1).equals(s)»,«ENDIF» 
       «ENDFOR» 
      ); 
      /** 
      * This method return list of moves. 
      */ 
      public List<U> getMoves() { 
       return declarations; 
      } 
      /** 
      * The executor class has to be extended and the extending class has to implement this 
      * method. 
      */ 
      public abstract T executeMoves(); 
     }''' 
} 
+0

Большое спасибо за подробный ответ; но, как вы уже говорили, мой вопрос был неясным. Просто обновил вопрос. Мой язык не будет иметь ничего общего с Java/JVM. Имеет ли смысл использовать Xbase? –

+0

Если вы хотите генерировать простой список из операторов execute, вам не нужен Xbase. Xbase обычно используется, если вы хотите обратиться к JVMTypes или вам нужны некоторые выражения на вашем языке. Посмотрите на ответ, как создать Java-код, как вы хотите, я его обновил. – Joko

Смежные вопросы