firstOf() ignores overridden fromStringLiteral(String)
The following grammar contains three rules. Each of these rules should match inputs "a" or "b", optionally followed by spaces.
rule1 explicitly matches the trailing whitespace with zeroOrMore(sp()). This rule matches the input "a".
rule2 implicitly matches the trailing whitespace by overriding fromStringLiteral(String) and adding zeroOrMore(sp()). That is: "x" matches this string; "x " matches sequence("x", zeroOrMore(sp())). This rule does NOT match the input "a". This is incorrect.
rule3 is the same as rule2 but also matches cr(). This slight change causes the rule to match the input "a".
Note: it seems that the actual change in rule3 is not important: If at least one non-String argument is present, the rule does match the input "a".
The issue seems to be that if all arguments of firstOf() are string literals, the overloaded fromStringLiteral(String) is ignored.
$ gradle
:compileJava
:processResources UP-TO-DATE
:classes
:run
rule1: true
rule2: false
rule3: true
BUILD SUCCESSFUL
Total time: 5.954 secs
$ cat build.gradle
defaultTasks 'run'
apply plugin: 'application'
apply plugin: 'java'
sourceCompatibility = 1.8
mainClassName = 'app.Main'
dependencies {
compile 'com.github.fge:grappa:2.0.0'
}
repositories {
mavenCentral()
}
$ cat src/main/java/app/Main.java
package app;
import com.github.fge.grappa.Grappa;
import com.github.fge.grappa.buffers.CharSequenceInputBuffer;
import com.github.fge.grappa.parsers.BaseParser;
import com.github.fge.grappa.rules.Rule;
import com.github.fge.grappa.run.ListeningParseRunner;
public class Main {
public static void main(final String[] args) {
final Parser1 parser = Grappa.createParser(Parser1.class);
final CharSequenceInputBuffer buffer = new CharSequenceInputBuffer("a");
System.out.println("rule1: "+new ListeningParseRunner<>(parser.rule1()).run(buffer).isSuccess());
System.out.println("rule2: "+new ListeningParseRunner<>(parser.rule2()).run(buffer).isSuccess());
System.out.println("rule3: "+new ListeningParseRunner<>(parser.rule3()).run(buffer).isSuccess());
}
public static class Parser1 extends BaseParser<Object> {
public Rule rule1() {
return firstOf(sequence(fromStringLiteral("a"), zeroOrMore(sp())), sequence(fromStringLiteral("b"), zeroOrMore(sp())));
}
public Rule rule2() {
return firstOf("a ", "b ");
}
public Rule rule3() {
return firstOf("a ", "b ", cr());
}
@Override
protected Rule fromStringLiteral(final String string) {
return string.endsWith(" ") ? sequence(super.fromStringLiteral(string.substring(0, string.length()-1)), zeroOrMore(sp())) : super.fromStringLiteral(string);
}
}
}
A better example for rule3 would be: firstOf("a ", "b ", NOTHING).