我正在尝试为木偶风格的声明性语言编写语法。我有我的基本语法和一个 JUnit 测试,试图实现一个 Listener 方法来加载它。JUnit 测试捕获第一个资源而不是第二个资源,这几乎就像resources
规则从未被评估一样。我在我的加载器中添加了日志语句,并且永远不会进入/退出资源。
grammar Bosse;
resources : resource+;
resource : ID LBRACE STRING COLON attributes RBRACE ;
attributes : keyvalue ( COMMA keyvalue )* COMMA? ;
keyvalue : ID ASSIGN expr ;
expr : STRING
| INT
| FLOAT
;
ID : [a-z]+ ;
STRING : SQUOTE (SQESC|.)*? SQUOTE;
SQESC : '\\\'' | '\\\\' ;
INT : DIGIT+ ;
FLOAT : DIGIT+ '.' DIGIT*
| '.' DIGIT+
;
ASSIGN : '=>' ;
LBRACE : '{' ;
RBRACE : '}' ;
fragment
SQUOTE : '\'' ;
COLON : ':' ;
COMMA : ',' ;
WS : (' '|'\n'|'\t'|'\r')+ -> skip ;
fragment
DIGIT : [0-9] ;
我的 BaseListener 实现:
public class BosseLoader extends BosseBaseListener {
private List<Resource> resources = new ArrayList<Resource>();
private String resourceType;
private String resourceTitle;
private Map<String,Object> attributes = new HashMap<String,Object>();
private String parseString(String str) {
str = str.substring(1, str.length()-1);
str.replaceAll("\\\\(.)", "\1");
return str;
}
public List<Resource> getResources() {
return resources;
}
@Override
public void enterResources(ResourcesContext ctx) {
log.finest("entered "+ctx);
}
@Override
public void exitResources(ResourcesContext ctx) {
log.finest("entered "+ctx);
}
@Override
public void enterResource(ResourceContext ctx) {
log.finest("entered "+ctx);
resourceType = ctx.ID().getText();
resourceTitle = parseString(ctx.STRING().getText());
}
@Override
public void exitResource(ResourceContext ctx) {
log.finest("entered "+ctx);
Resource r = new Resource() {
public String getTitle() {
return resourceTitle;
}
public String toString() {
String type = resourceType.substring(0,1).toUpperCase()+resourceType.substring(1);
return type+"["+resourceTitle+"]";
}
};
resources.add(r);
System.out.println(r);
super.exitResource(ctx);
}
@Override
public void enterAttributes(AttributesContext ctx) {
log.finest("entered "+ctx);
attributes = new HashMap<String,Object>();
}
@Override
public void exitKeyvalue(KeyvalueContext ctx) {
log.finest("entered "+ctx);
attributes.put(ctx.ID().getText(),ctx.expr().getText());
}
}
我的 JUnit 测试
@Test
public void testSyntaxDouble() {
System.out.println("testSyntaxDouble()");
String data = "user { 'ruckc' : ensure => 'present' }\n"+
"user { 'cruck' : ensure => 'present' }\n";
BosseLoader loader = new BosseLoader();
BosseLexer lexer = new BosseLexer(new ANTLRInputStream(data));
CommonTokenStream tokens = new CommonTokenStream(lexer);
BosseParser parser = new BosseParser(tokens);
ParseTree tree = parser.resource();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(loader, tree);
assertEquals(2,loader.getResources().size());
Resource r = loader.getResources().get(0);
assertEquals("ruckc", r.getTitle());
assertEquals("User[ruckc]", r.toString());
r = loader.getResources().get(1);
assertEquals("cruck", r.getTitle());
assertEquals("User[cruck]", r.toString());
}
我的测试输出:
testSyntaxDouble()
FINEST: AM org.cruck.bosse.language.BosseLoader enterResource entered []
FINEST: AM org.cruck.bosse.language.BosseLoader enterAttributes entered [19]
FINEST: AM org.cruck.bosse.language.BosseLoader exitKeyvalue entered [22 19]
FINEST: AM org.cruck.bosse.language.BosseLoader exitResource entered []
User[ruckc]
Failed tests:
testSyntaxDouble(org.cruck.bosse.language.BosseLanguageTest): expected:<2> but was:<1>