A parser combinator library written in Java 8
Java
Latest commit 67cf54b Dec 19, 2016 @kmizu Improve RegexInterpreter
Permalink
Failed to load latest commit information.
src Improve RegexInterpreter Dec 19, 2016
.gitignore Some combinators are implemented Dec 1, 2016
.travis.yml Add .travis.yml Dec 9, 2016
LICENSE Initial commit Aug 29, 2016
README.md Add explanation Dec 9, 2016
pom.xml 0.0.2-SNAPSHOT Dec 9, 2016

README.md

JCombinator: A parser combinator written in Java 8

Gitter Build Status Maven Central Javadoc

JCombinator is yet another parser combinator library for Java 8 or later. JCombinator is written in Java 8 to reduce boilerplate code using lambda expression.

To use jcombinator, Add the following lines to your pom.xml

<dependencies>
    <dependency>
        <groupId>com.github.kmizu</groupId>
        <artifactId>jcombinator</artifactId>
        <version>0.0.1</version>
        <scope>compile</scope>
    </dependency>
</dependencies>

Usage

See JavaDoc and Tests

Example

The following code is a parser of arithmetic expression:

import com.github.kmizu.jcombinator.datatype.Function2;

import static com.github.kmizu.jcombinator.Parser.*;
import static com.github.kmizu.jcombinator.Functions.*;

public class ArithmeticExpression {
    private Rule<Integer> expression() {
        return rule(() ->
            additive().cat(eof()).map(t -> t.extract((result, __) -> result))
        );
    }
    private Rule<Integer> additive() {
        return rule(() -> {
            final Parser<Function2<Integer, Integer, Integer>> Q = string("+").map(op -> (Integer lhs, Integer rhs) -> lhs + rhs);
            final Parser<Function2<Integer, Integer, Integer>> R = string("-").map(op -> (Integer lhs, Integer rhs) -> lhs - rhs);
            return multitive().chain(Q.or(R));
        });
    }
    private Rule<Integer> multitive() {
        return rule(() -> {
            final Parser<Function2<Integer, Integer, Integer>> Q = string("*").map(op -> (Integer lhs, Integer rhs) -> lhs * rhs);
            final Parser<Function2<Integer, Integer, Integer>> R = string("/").map(op -> (Integer lhs, Integer rhs) -> lhs / rhs);
            return primary().chain(Q.or(R));
        });
    }
    private final Rule<Integer> primary() {
        return rule(() ->
            number().or((string("(").cat(expression())).cat(string(")")).map(t -> t.item1().item2()))
        );
    }
    private final Rule<Integer> number() {
        return rule(() ->
            digit().many1().map(digits -> Integer.parseInt(join(digits, "")))
        );
    }

    public void testExpression() {
        Parser<Integer> arithmetic = expression();
        arithmetic.invoke("100").onSuccess(s -> {
            assert ((Integer)100) == s.value();
        });
        arithmetic.invoke("100+200").onSuccess(s -> {
            assert ((Integer)300) == s.value();
        });
        arithmetic.invoke("(1+2)*(3+4)").onSuccess(s -> {
            assert ((Integer)21) == s.value();
        });
        arithmetic.invoke("1+2*3+4").onSuccess(s -> {
            assert ((Integer)11) == s.value();
        });
    }
}