Xtext/ANTLR 中的多行文本终止块

Terminating blocks of multiline text in Xtext/ANTLR

我开始掌握 Xtext,但在用多个换行符分隔语义部分时仍然遇到一些问题。

grammar org.example.dsl.MyDsl hidden(WS)

import "http://www.eclipse.org/emf/2002/Ecore" as ecore
generate words "http://www.example.org/dsl

Document:
    sections+=Paragraph+
;

Paragraph:
    lines+=Text+
    ( -> NL)
;

Text: 
    value=WordGroup
    NL
;

WordGroup: SIMPLE_WORD+;

terminal SIMPLE_WORD: 
    ('0'..'9' | 'a'..'z' | 'A'..'Z') 
    ('0'..'9' | 'a'..'z' | 'A'..'Z' | '-' | '_' | '.')*
;
terminal NL: ('\r'? '\n');
terminal WS: (' ' | '\t');

没关系...

    @Test
    def void happyPath() {
        val model = parseHelper.parse('''
            The quick brown fox
            Jumps over the lazy dog

        ''')

        assertThat(model, notNullValue())
        assertThat(model.eResource.errors, equalTo(#[]))
        assertThat(model.sections.size(), equalTo(1))
        assertThat(model.sections.get(0).lines.size(), equalTo(2))
        // It works!
    }

但这不是...

    @Test
    def void noTrailingNewlines() {
        val model = parseHelper.parse('''
            The quick brown fox
            Jumps over the lazy dog
        ''')

        assertThat(model, notNullValue())
        assertThat(model.eResource.errors, equalTo(#[]))
        // Fail ^^^ XtextSyntaxDiagnostic: null:2 mismatched input '<EOF>' expecting RULE_NL
        assertThat(model.sections.size(), equalTo(1))
        assertThat(model.sections.get(0).lines.size(), equalTo(2))
    }

两者都应该是有效的可解析文本,但如果这是找到的最后一个字符,我无法让它接受单个 NL。

我尝试了明显的 ( -> NL?)...

Paragraph:
    lines+=Text+
    ( -> NL?)
;

...这确实会导致测试通过,直到现在我才收到 ANTLR 警告。

正如我所怀疑的那样,这只是解决了问题...

    @Test
    def void multipleParagraphs() {
        val model = parseHelper.parse('''
            The quick brown fox
            Jumps over the lazy dog

            But only on days that end in Y
        ''')

        assertThat(model, notNullValue())
        assertThat(model.eResource.errors, equalTo(#[]))
        assertThat(model.sections.size(), equalTo(2)) //Expected: <2> but: was <1>
    }

我们有一个赢家!

非常感谢@christian-dietrich 和@redknite,他们在帮助我解决问题时对我非常耐心。

Document:
    sections+=Paragraph
    (NL sections+=Paragraph)*
;

Paragraph:
    lines+=Text+
;

Text: 
    value=WordGroup
    NL
;
@Test
def void singleParagraph() {
    val model = parseHelper.parse('''
        The quick brown fox
        Jumps over the lazy dog
    ''')

    assertThat(model, notNullValue())
    assertThat(model.eResource.errors, equalTo(#[]))

    val doc = model.document
    assertThat(doc, notNullValue())
    assertThat(doc.sections.size(), equalTo(1))
    assertThat(doc.sections.get(0).lines.size(), equalTo(2))
}

@Test
def void multiParagraph() {
    val model = parseHelper.parse('''
        The quick brown fox
        Jumps over the lazy dog

        But only on days that end in Y
    ''')

    assertThat(model, notNullValue())
    assertThat(model.eResource.errors, equalTo(#[]))

    val doc = model.document
    assertThat(doc, notNullValue())
    assertThat(doc.sections.size(), equalTo(2))
    assertThat(doc.sections.get(0).lines.size(), equalTo(2))
}

都通过了!