Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions core/src/main/java/fj/Equal.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import fj.data.vector.V6;
import fj.data.vector.V7;
import fj.data.vector.V8;
import fj.parser.Result;

import java.math.BigDecimal;
import java.math.BigInteger;
Expand Down Expand Up @@ -355,6 +356,13 @@ public static <A, B> Equal<Either<A, B>> eitherEqual(final Equal<A> ea, final Eq
));
}

public static <I, A> Equal<Result<I, A>> resultEqual(final Equal<A> ea, final Equal<I> ei) {
Definition<A> eaDef = ea.def;
Definition<I> eiDef= ei.def;
return equalDef((r1, r2) -> eaDef.equal(r1.value(), r2.value()) && eiDef.equal(r1.rest(), r2.rest()));
}


/**
* An equal instance for the {@link Validation} type.
*
Expand Down
20 changes: 20 additions & 0 deletions core/src/main/java/fj/Hash.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import fj.data.vector.V6;
import fj.data.vector.V7;
import fj.data.vector.V8;
import fj.parser.Result;

import java.math.BigDecimal;
import java.math.BigInteger;
Expand Down Expand Up @@ -162,6 +163,25 @@ public static <A, B> Hash<Either<A, B>> eitherHash(final Hash<A> ha, final Hash<
return hash(e -> e.isLeft() ? ha.hash(e.left().value()) : hb.hash(e.right().value()));
}

/**
* A hash instance for the {@link Result} type.
*
* @param ha Hash the <code>Result</code> value.
* @param hi Hash the <code>Result</code> remainder.
* @return A hash instance for the {@link Result} type.
*/
public static <I, A> Hash<Result<I, A>> resultHash(Hash<A> ha, Hash<I> hi) {
return hash(res -> {
final int p = 419;
int r = 239;

r = p * r + ha.hash(res.value());
r = p * r + hi.hash(res.rest());

return r;
});
}

/**
* A hash instance for the {@link Validation} type.
*
Expand Down
14 changes: 14 additions & 0 deletions core/src/main/java/fj/Show.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import fj.data.vector.V6;
import fj.data.vector.V7;
import fj.data.vector.V8;
import fj.parser.Result;

import java.math.BigDecimal;
import java.math.BigInteger;
Expand Down Expand Up @@ -255,6 +256,19 @@ public static <A, B> Show<Either<A, B>> eitherShow(final Show<A> sa, final Show<
fromString("Right(").append(sb.f.f(e.right().value())).append(single(')')));
}

/**
* A show instance for the {@link Result} type.
*
* @param sa Show for the {@link Result} value.
* @param si Show for the {@link Result} remainder.
* @return A show instance for the {@link Result} type.
*/
public static <I, A> Show<Result<I, A>> resultShow(Show<A> sa, Show<I> si) {
return show(res ->
fromString("Result(").append(sa.f.f(res.value()))
.append(single(',')).append(si.f.f(res.rest())).append(single(')')));
}

/**
* A show instance for the {@link Validation} type.
*
Expand Down
19 changes: 19 additions & 0 deletions core/src/main/java/fj/parser/Result.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package fj.parser;

import fj.Equal;
import fj.F;
import fj.Hash;
import fj.Show;

import static fj.Function.curry;

Expand All @@ -21,6 +24,22 @@ private Result(final I i, final A a) {
this.a = a;
}

@Override
public final int hashCode() {
return Hash.resultHash(Hash.<A>anyHash(), Hash.<I>anyHash()).hash(this);
}

@Override
public final String toString() {
return Show.resultShow(Show.<A>anyShow(), Show.<I>anyShow()).showS(this);
}

@Override
public final boolean equals(Object other) {
return Equal.equals0(Result.class, this, other, () -> Equal.resultEqual(Equal.anyEqual(), Equal.anyEqual()));
}


/**
* The remainder of the parse input.
*
Expand Down
52 changes: 52 additions & 0 deletions core/src/test/java/fj/parser/ParserTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package fj.parser;

import fj.F;
import fj.F0;
import fj.data.Stream;
import fj.data.Validation;
import org.junit.Test;

import static fj.parser.Result.result;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.*;

public class ParserTest {
@Test
public void testParserFail() {
final Parser<String, String, Exception> fail = Parser.fail(new ParseException());
assertThat(fail.parse("").fail(), is(new ParseException()));
}

@Test
public void testParserValue() {
final Parser<String, String, Exception> p = Parser.parser(s -> s.isEmpty() ?
Validation.fail(new ParseException()) :
Validation.success(result(s.substring(1), s.substring(0, 1)))
);
final Result<String, String> r = p.parse("abc").success();
assertThat(r.value(), is("a"));
assertThat(r.rest(), is("bc"));
}

@Test
public void testParserBind() {
final Parser<String, String, Exception> p = Parser.value("a");
final Parser<String, String, Exception> fail = Parser.fail(new ParseException());
assertThat(p.bind(o -> fail).parse("aaaa").fail(), is(new ParseException()));
}

@Test
public void testParserStream() {
Stream<Character> s = Stream.fromString("abc");
Result<Stream<Character>, Character> r = Parser.CharsParser.character('a').parse(s).success();
assertThat(r, is(Result.result(Stream.fromString("bc"), 'a')));
}

class ParseException extends Exception {
@Override
public boolean equals (Object obj) {
return (obj instanceof ParseException);
}
}

}