Skip to content

Instantly share code, notes, and snippets.

@kmizu
Created July 25, 2017 03:02
Show Gist options
  • Save kmizu/022834268e5daced5b82036b00d13515 to your computer and use it in GitHub Desktop.
Save kmizu/022834268e5daced5b82036b00d13515 to your computer and use it in GitHub Desktop.
Javaで始めるパーザコンビネータの作り方(2) ~ Hello + World! ref: http://qiita.com/kmizu/items/694b2bed2338b57d182a
package parser;
public interface Parser<T> {
ParseResult<T> invoke(String input);
static Parser<String> string(String literal) {
return new StringParser(literal);
}
}
package parser;
public class StringParser implements Parser<String> {
public final String literal;
public StringParser(String literal) {
this.literal = literal;
}
@Override
public ParseResult<String> invoke(String input) {
if(input.startsWith(literal)) {
return new ParseResult.Success<>(literal, input.substring(literal.length()));
}else {
return new ParseResult.Failure<>("expect: " + literal, input);
}
}
}
package parser;
import java.util.function.*;
public interface ParseResult<T> {
public static class Success<T> implements ParseResult<T> {
public final T value;
public final String next;
Success(T value, String next) {
this.value = value;
this.next = next;
}
@Override
public <U> ParseResult<U> map(Function<T, U> fn) {
return new Success<U>(fn.apply(value), next);
}
}
public static class Failure<T> implements ParseResult<T> {
public final String message;
public final String next;
public Failure(String message, String next) {
this.message = message;
this.next = next;
}
@Override
public <U> ParseResult<U> map(Function1<T, U> fn) {
return (ParseResult<U>)this;
}
}
<U> ParseResult<U> map(Function<T, U> fn);
}
Parser<A> pa = ...;
Parser<B> pb = ...;
String input;
ParseResult<A> ra = pa.parse(input);
if(ra instanceof ParseResult.Success<*>) {
String next = ((ParseResult.Success<A>)ra).next;
ParseResult<B> rb = pb.parse(next);
if(rb instanceof ParseResult.Success<*>) {
return build(
((ParseResult.Success<A>)ra),
((ParseResult.Success<B>)rb)
);
} else {
return rb;
}
} else {
return ra;
}
package parser;
public class Tuple2<A, B> {
public final A item1;
public final B item2;
public Tuple2(A item1, B item2) {
this.item1 = item1;
this.item2 = item2;
}
}
ParseResult<A> ra = pa.parse(input);
if(ra instanceof ParseResult.Success<?>) {
String next = ((ParseResult.Success<A>)ra).next;
ParseResult<B> rb = pb.parse(next);
if(rb instanceof ParseResult.Success<?>) {
return new ParseResult.Success<>(
new Tuple2<>(
((ParseResult.Success<A>)ra).value,
((ParseResult.Success<A>)rb).value
),
((ParseResult.Success<A>)rb).next
);
} else {
return rb;
} else {
return ra;
}
package parser;
public class Cat<X, Y> implements Parser<Tuple2<X, Y>> {
private Parser<X> lhs;
private Parser<Y> rhs;
public Cat(Parser<X> lhs, Parser<Y> rhs) {
this.lhs = lhs;
this.rhs = rhs;
}
@Override
public ParseResult<Tuple2<X, Y>> invoke(String input) {
ParseResult<X> lresult = lhs.invoke(input);
if(lresult instanceof ParseResult.Success<?>) {
X value1 = ((ParseResult.Success<X>)lresult).value;
String next = ((ParseResult.Success<X>)lresult).next;
ParseResult<Y> rresult = rhs.invoke(next);
if(rresult instanceof ParseResult.Success<?>) {
Y value2 = ((ParseResult.Success<Y>)rresult).value;
return new ParseResult.Success<>(
new Tuple2<>(value1, value1),
((ParseResult.Success<Y>)rresult).next
);
} else {
return rresult;
}
} else {
return lresult;
}
}
}
package parser;
public interface Parser<T> {
ParseResult<T> invoke(String input);
static Parser<String> string(String literal) {
return new StringParser(literal);
}
default <U> Parser<Tuple2<T, U>> cat(Parser<U> rhs) {
return new Cat<>(this, rhs);
}
}
package parser;
public class Main {
public static void main(String[] args) {
Parser<String> hello = Parser.string("Hello, ");
Parser<String> world = Parser.string("World!");
Parser<Tuple2<String, String>> helloWorld = hello.cat(world);
ParseResult.Success<Tuple2<String, String>> success = (ParseResult.Success<Tuple2<String, String>>)helloWorld.invoke("Hello, World!");
assert "Hello, ".equals(success.item1);
assert "World!".equals(success.item2);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment