Skip to content

Instantly share code, notes, and snippets.

@mikaelhg
Last active August 29, 2015 14:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikaelhg/d9a3a81a9454a4e40205 to your computer and use it in GitHub Desktop.
Save mikaelhg/d9a3a81a9454a4e40205 to your computer and use it in GitHub Desktop.
PEG Sandbox
package io.mikael.peg;
import java.util.Arrays;
public class Sandbox {
public static void main(String[] args) {
System.out.printf("character('a', 'h').match(\"far\") = <%s>%n",
character('a', 'h').match("far"));
System.out.printf("oneOrMore(character('a', 'h')).match(\"fabaraba\") = <%s>%n",
oneOrMore(character('a', 'h')).match("fabaraba"));
System.out.printf("character('f').match(\"far\") = <%s>%n",
character('f').match("far"));
System.out.printf("string(\"fa\").match(\"far\") = <%s>%n",
string("fa").match("far"));
System.out.printf("string(\"ab\"), string(\"ba\"), string(\"arb\")).match(\"abbaarb\") = <%s>%n",
sequence(string("ab"), string("ba"), string("arb")).match("abbaarb"));
System.out.printf("oneOrMore(or(character('a'), character('b'))).match(\"abba\")) = <%s>%n",
oneOrMore(or(character('a'), character('b'))).match("abbararara"));
}
@FunctionalInterface
public static interface Rule {
default public Match match(String input) {
return match(input.toCharArray(), 0);
}
public Match match(char[] chars, int i);
}
public static class Match {
public final int length;
public final CharSequence content;
public final boolean matched;
public Match(final int length, final CharSequence content, final boolean matched) {
this.length = length;
this.content = content;
this.matched = matched;
}
@Override public String toString() {
return String.format("Match(%s, %s, %s)", length, content, matched);
}
}
public static class NoMatch extends Match {
public NoMatch() { super(0, null, false); }
@Override public String toString() { return "NoMatch()"; }
}
public static Match match(final CharSequence content) {
return new Match(content.length(), content, true);
}
public static Match match(final char[] content) {
return new Match(content.length, new String(content), true);
}
public static Match match(final char content) {
return new Match(1, Character.toString(content), true);
}
public static Match match(final Match ... matches) {
if (Arrays.stream(matches).anyMatch(m -> !m.matched)) {
return noMatch();
}
final StringBuilder sb = new StringBuilder();
for (final Match m : matches) {
sb.append(m.content);
}
return match(sb);
}
public static Match noMatch() {
return new NoMatch();
}
public static Rule character(final char low, final char high) {
return (chars, i) -> {
if (i < chars.length && chars[i] >= low && chars[i] <= high) {
return match(chars[i]);
} else {
return noMatch();
}
};
}
public static Rule character(final char constant) {
return (chars, i) -> {
if (i < chars.length && chars[i] == constant) {
return match(chars[i]);
} else {
return noMatch();
}
};
}
public static Rule string(final String constant) {
return (chars, i) -> {
final char[] input = constant.toCharArray();
int j = i, k = 0;
for (; j < chars.length && k < input.length; j++, k++) {
if (chars[j] != input[k]) {
return noMatch();
}
}
if (j - i == k && k == input.length) {
return match(input);
}
return noMatch();
};
}
public static Rule sequence(final Rule ... rules) {
return (chars, i) -> {
int j = i;
for (final Rule rule : rules) {
final Match match = rule.match(chars, j);
if (match.matched) {
j += match.length;
} else {
return noMatch();
}
}
return match(Arrays.copyOfRange(chars, i, j));
};
}
public static Rule and(final Rule a, final Rule b) {
return (chars, i) -> {
final Match am = a.match(chars, i);
if (!am.matched) {
return noMatch();
}
final Match bm = b.match(chars, i + am.length);
if (!bm.matched) {
return noMatch();
}
return match(new StringBuilder().append(am.content).append(bm.content));
};
}
public static Rule or(final Rule... choices) {
return (chars, i) -> {
for (final Rule m : choices) {
final Match n = m.match(chars, i);
if (n.matched) {
return n;
}
}
return noMatch();
};
}
Rule not(final Rule m) {
return (chars, i) -> noMatch();
}
public static Rule zeroOrMore(final Rule m) {
return (chars, i) -> {
Match n;
int k = i;
while ((n = m.match(chars, k)).matched) {
k += n.length;
}
return match(Arrays.copyOfRange(chars, i, k));
};
}
public static Rule oneOrMore(final Rule m) {
return (chars, i) -> {
Match n;
int k = 0, matches = 0;
while ((n = m.match(chars, k)).matched) {
k += n.length;
matches++;
}
if (matches < 1) {
throw new RuntimeException("one or more matches expected");
}
return match(Arrays.copyOfRange(chars, i, k));
};
}
public static Rule optional(Rule m) {
return (chars, i) -> noMatch();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment