Unit testing 如何在不向每个规则添加EOF的情况下测试ANTLR翻译 我正在重新编写我的翻译,这次我对测试更加严格,因为这个版本很可能会持续几个星期。

Unit testing 如何在不向每个规则添加EOF的情况下测试ANTLR翻译 我正在重新编写我的翻译,这次我对测试更加严格,因为这个版本很可能会持续几个星期。,unit-testing,antlr,Unit Testing,Antlr,因为您可以从任何节点开始运行访问者,所以您几乎可以编写这样漂亮的小测试 expect(parse("some test code", "startGrammarRule")).toEqual(new ASTForGrammarRule()) 然后为每个访问者函数编写一个(或几个) 除了你调用的规则是一个子规则,所以里面没有“EOF”,所以如果我的语法在其中的某个地方 numberList: NUMBER ( ',' NUMBER )* ; 。。。然后p

因为您可以从任何节点开始运行访问者,所以您几乎可以编写这样漂亮的小测试

expect(parse("some test code", "startGrammarRule")).toEqual(new ASTForGrammarRule())
然后为每个访问者函数编写一个(或几个)

除了你调用的规则是一个子规则,所以里面没有“EOF”,所以如果我的语法在其中的某个地方

numberList: NUMBER ( ',' NUMBER )* ;
。。。然后
parse(“1,2,3”,“numberList”)
只解析“1”(因为它只是一个“EOF”,它会让解析器饿得足以消耗所有字符串)

编辑规则以添加EOF不是第一步。我可以,为我编写测试的每个规则,添加规则的测试版本

numberList: NUMBER ( ',' NUMBER )* ;
numberList_TEST: numberList EOF ;
。。。但这将使语法变得混乱,并使人担心必须始终严格维护
\u测试
规则

我需要一个标志,当我创建一个解析器时,它动态地构造那个伪测试规则,然后从那个里解析,或者类似的东西


有没有更好的方法来为我的解析器编写测试,而我还没有找到呢?

在一个Java项目中,我使用一个自定义匹配器来检查解析的令牌是否是令牌流的100%,如果不是,就会失败

您似乎使用了TypeScript目标,因此在TypeScript中,它可能如下所示:

T.g4 parserMatchers.ts
从“../src/parser/TLexer”导入{TLexer};
从“antlr4ts”导入{BailErrorStrategy,CharStreams,CommonTokenStream};
从“../src/parser/TParser”导入{TParser};
从“antlr4ts/Lexer”导入{Lexer};
期待({
toBeCompletelyParsedBy:(来源:string,规则名称:string)=>{
const lexer=new-TLexer(CharStreams.fromString(source));
lexer.removeErrorListeners();
const tokenStream=新的CommonTokenStream(lexer);
const parser=新的TParser(令牌流);
removeErrorListeners();
parser.errorHandler=new BailErrorStrategy();
const context=parser[ruleName]();
//收集真正的令牌:非隐藏和非EOF令牌
const realTokens=tokenStream.getTokens().filter((t)=>
t、 channel==Lexer.DEFAULT\u TOKEN\u channel&t.type!==Lexer.EOF);
让indexOfStop=realTokens.indexOf(context.stop);
let pass=realTokens.length==(indexOfStop+1);
让消息=()=>{
如果(通过){
返回`预期${source}'不会被规则${ruleName}完全解析,但它确实解析了。`;
}
让冒犯=房地产经纪人[indexOfStop+1];
返回`预期${source}'被规则${ruleName}完全解析,但${officing.text}`+
`(${officing.line}:${officing.charPositionInLine})未包括在内!`;
};
返回{pass,message};
}
});
宣布全球{
名称空间玩笑{
接口匹配器{
toBeCompletelyParsedBy(规则名称:字符串):R
}
}
}
出口{};
在单元测试中,您现在可以执行以下操作:

import'/parserMatchers';
test('numberList解析器规则',()=>{
期望('3,4,5')。被('numberList')完全分解;
期望('3,4,5 FOO')。而不是。被('numberList')完全忽略;
});

也许您可以将语法导入到一个测试语法中,该语法具有规则
test:(nonterm1 | nonterm2 | |……)EOF。该语言可能无法解析,因为在完整语言中从来都不是可选的短语现在正在使用。不过这个想法很有趣,我很喜欢。可能类似于:
test:('numberlist'numberlist)|('otherrule'otherrule)EOF
当然它会解析比你想要的更多的东西。但是你需要检查root的第一个子元素,这样类型才能符合你的期望。我需要做一些修改,才能让我的typescript环境使用代码,但它基本上起到了很好的作用。谢谢不客气@MichaelToy
grammar T;

parse      : numberList EOF;
numberList : NUMBER ( ',' NUMBER )*;

NUMBER : [0-9]+;
ID     : [a-zA-Z]+;
WS     : [ \t\r\n]+ -> channel(HIDDEN);