Xtext

2014-11-07 5 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 

내가 원하는 자바 프로그램은 모든 선언을 제공 따라서 스크립트에는 Execute 문만 포함됩니다. 나는 IGlobalScopeProvider에 대한 일을위한 올바른 도구를 어떻게 보이지만, 나는 그것에 내 데이터를 추가하는 방법, 그리고 Xtext 그것을 사용하게 만드는 방법을 모르겠다.

외부에서 문법에 대한 선언을 제공하려면 어떻게해야합니까?

업데이트

내 목표는 다소 불분명했다, 그래서 나는 더 구체적 만들려고. 나는 예를 들어, 간단한 자바 객체로 선언을 유지하려면 :

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에는 명령문 만 포함됩니다. 그러나 어떤 'what'속성은 File의 선언에 대한 참조를 보유합니다.

문법과 함께 사용하면 즉시 사용할 수 있습니다.

2.) 예를 들어 '선언 인터페이스'를 정의하는 클래스를 제공하는 자바 소스 코드가 있으며 'what'속성이이 인터페이스 또는이 인터페이스를 구현하는 클래스를 참조하도록합니다.

당신은 당신의 언어에서을 Xbase를 사용해야합니다업데이트 대답. 여기서 'what'속성이 Xtypes 규칙 'JvmTypeReference'를 사용하여 모든 Java 유형을 참조하도록 정의 할 수 있습니다.

// 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; 

제 1, 당신은 모든 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)[] 
      ]) 
    } 
} 

그것은 오직 하나의 방법으로 각각 명명 된 하나의 인터페이스를 유도한다 "실행().

그런 다음,이 같은 정적 검사를 구현, 당신은 생성 된 스텁 '... 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) 
    } 
} 

(I 정적 검사를 구현하기 위해 선호 Xtend 프로그래밍 언어를 사용!) 정적 검사 여부를 결정한다 지정된 JvmTypeReference (프로젝트의 Java 클래스)는 선언 된 인터페이스를 구현합니다. 그렇지 않으면 dsl 문서에 경고가 표시됩니다.

잘하면이 질문에 대한 답변을드립니다.

다음 업데이트 : 아이디어가 잘 작동하지 않습니다! Xbase를 사용하지 않고 Xtend를 사용하여 템플릿을 작성할 수는 있지만 좋은 방법으로 사용하는 방법을 상상할 수는 없습니다. 문제는 구멍 클래스 '이동'과 구멍 실행 프로세스를 생성하지 않는다고 가정하는 것입니다. 내가 쓸모있는 코드를 생성하려고 조금 놀았하고 해킹 것으로 보인다! Neverthess, 내 해결책은 다음과 같습니다.

Xtext는 'void doGenerate'메서드를 사용하여 스텁 '... mydsl.generator.MyDslGenerator'를 생성했습니다. 이 방법을 채워야합니다. 내 생각은 다음과 같습니다. 첫째, 두 개의 일반 매개 변수 T와 U로 추상 및 일반 Executor 클래스를 생성합니다. 내 executor 클래스는 반환 값 T를 사용하여 추상 메서드 'executeMoves()'를 사용합니다. 비 프리미티브 'Void'클래스. 이 클래스는 List를 보유하지만 Move 클래스의 하위 클래스로 정의 된 일반 유형 u를 보유합니다.

Move 클래스도 생성되지만 String을 저장할 필드 만 포함됩니다. 그런 다음 파생되어야합니다. 내 '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

실행 문에서 간단한 목록 만 생성하려면 Xbase가 필요하지 않습니다. Xbase는 일반적으로 JVMTypes를 참조하거나 사용자의 언어로 표현식이 필요한 경우에 사용됩니다. 원하는대로 Java 코드를 작성하는 방법에 대한 대답을 살펴보고이를 업데이트했습니다. – Joko