Skip to content

Commit

Permalink
parsingdata#186: Implemented list semantics for expressions.
Browse files Browse the repository at this point in the history
  • Loading branch information
ccreeten committed Jul 11, 2017
1 parent f3fb634 commit ba6e4be
Show file tree
Hide file tree
Showing 14 changed files with 177 additions and 32 deletions.
14 changes: 14 additions & 0 deletions core/src/main/java/io/parsingdata/metal/Util.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,17 @@

package io.parsingdata.metal;

import static io.parsingdata.metal.SafeTrampoline.complete;
import static io.parsingdata.metal.SafeTrampoline.intermediate;

import java.io.ByteArrayOutputStream;
import java.util.Optional;
import java.util.zip.DataFormatException;
import java.util.zip.Inflater;

import io.parsingdata.metal.data.ConstantSource;
import io.parsingdata.metal.data.Environment;
import io.parsingdata.metal.data.ImmutableList;
import io.parsingdata.metal.data.ParseGraph;
import io.parsingdata.metal.data.Slice;
import io.parsingdata.metal.encoding.Encoding;
Expand Down Expand Up @@ -98,4 +102,14 @@ public static Optional<Environment> failure() {
return Optional.empty();
}

public static boolean allTrue(final ImmutableList<Boolean> values) {
return allTrueRecursive(values).computeResult();
}

private static SafeTrampoline<Boolean> allTrueRecursive(final ImmutableList<Boolean> values) {
if (values.isEmpty()) { return complete(() -> true); }
if (!values.head) { return complete(() -> false); }
return intermediate(() -> allTrueRecursive(values.tail));
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package io.parsingdata.metal.expression;

import io.parsingdata.metal.data.Environment;
import io.parsingdata.metal.data.ImmutableList;
import io.parsingdata.metal.data.ParseGraph;
import io.parsingdata.metal.encoding.Encoding;

Expand All @@ -35,6 +36,6 @@
@FunctionalInterface
public interface Expression {

boolean eval(ParseGraph graph, Encoding encoding);
ImmutableList<Boolean> eval(ParseGraph graph, Encoding encoding);

}
3 changes: 2 additions & 1 deletion core/src/main/java/io/parsingdata/metal/expression/True.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.util.Objects;

import io.parsingdata.metal.Util;
import io.parsingdata.metal.data.ImmutableList;
import io.parsingdata.metal.data.ParseGraph;
import io.parsingdata.metal.encoding.Encoding;

Expand All @@ -29,7 +30,7 @@
public class True implements Expression {

@Override
public boolean eval(final ParseGraph graph, final Encoding encoding) { return true; }
public ImmutableList<Boolean> eval(final ParseGraph graph, final Encoding encoding) { return ImmutableList.create(true); }

@Override
public String toString() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@

package io.parsingdata.metal.expression.comparison;

import static java.util.function.Function.identity;

import static io.parsingdata.metal.SafeTrampoline.complete;
import static io.parsingdata.metal.SafeTrampoline.intermediate;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.data.transformation.Reversal.reverse;
import static java.util.function.Function.identity;

import java.util.Objects;
import java.util.Optional;
Expand Down Expand Up @@ -58,19 +58,27 @@ public ComparisonExpression(final ValueExpression value, final ValueExpression p
}

@Override
public boolean eval(final ParseGraph graph, final Encoding encoding) {
final ImmutableList<Optional<Value>> values = value == null ? ImmutableList.create(graph.current().map(identity())) : value.eval(graph, encoding);
if (values.isEmpty()) { return false; }
final ImmutableList<Optional<Value>> predicates = predicate.eval(graph, encoding);
if (values.size != predicates.size) { return false; }
return compare(values, predicates).computeResult();
public ImmutableList<Boolean> eval(final ParseGraph graph, final Encoding encoding) {
return compareLists(value == null ? ImmutableList.create(graph.current().map(identity())) : value.eval(graph, encoding), predicate.eval(graph, encoding));
}

private ImmutableList<Boolean> compareLists(final ImmutableList<Optional<Value>> values, final ImmutableList<Optional<Value>> predicates) {
return reverse(padList(compareLists(values, predicates, new ImmutableList<>()).computeResult(), Math.abs(values.size - predicates.size)).computeResult());
}

private SafeTrampoline<ImmutableList<Boolean>> compareLists(final ImmutableList<Optional<Value>> values, final ImmutableList<Optional<Value>> predicates, final ImmutableList<Boolean> results) {
if (values.isEmpty() || predicates.isEmpty()) { return complete(() -> results); }
return intermediate(() -> compareLists(values.tail, predicates.tail, results.add(compare(values.head, predicates.head))));
}

private SafeTrampoline<ImmutableList<Boolean>> padList(final ImmutableList<Boolean> list, final long size) {
if (size <= 0) { return complete(() -> list); }
return intermediate(() -> padList(list.add(false), size - 1));
}

private SafeTrampoline<Boolean> compare(final ImmutableList<Optional<Value>> currents, final ImmutableList<Optional<Value>> predicates) {
if (!currents.head.isPresent() || !predicates.head.isPresent()) { return complete(() -> false); }
final boolean headResult = compare(currents.head.get(), predicates.head.get());
if (!headResult || currents.tail.isEmpty()) { return complete(() -> headResult); }
return intermediate(() -> compare(currents.tail, predicates.tail));
private boolean compare(final Optional<Value> left, final Optional<Value> right) {
if (!left.isPresent() || !right.isPresent()) { return false; }
return compare(left.get(), right.get());
}

public abstract boolean compare(final Value left, final Value right);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package io.parsingdata.metal.expression.logical;

import io.parsingdata.metal.data.ParseGraph;
import io.parsingdata.metal.encoding.Encoding;
import io.parsingdata.metal.expression.Expression;

/**
Expand All @@ -30,8 +28,8 @@ public And(final Expression left, final Expression right) {
}

@Override
public boolean eval(final ParseGraph graph, final Encoding encoding) {
return left.eval(graph, encoding) && right.eval(graph, encoding);
public boolean eval(final boolean left, final boolean right) {
return left && right;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,18 @@

package io.parsingdata.metal.expression.logical;

import static io.parsingdata.metal.SafeTrampoline.complete;
import static io.parsingdata.metal.SafeTrampoline.intermediate;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.data.transformation.Reversal.reverse;

import java.util.Objects;

import io.parsingdata.metal.SafeTrampoline;
import io.parsingdata.metal.Util;
import io.parsingdata.metal.data.ImmutableList;
import io.parsingdata.metal.data.ParseGraph;
import io.parsingdata.metal.encoding.Encoding;
import io.parsingdata.metal.expression.Expression;

/**
Expand All @@ -41,6 +48,27 @@ public BinaryLogicalExpression(final Expression left, final Expression right) {
this.right = checkNotNull(right, "right");
}

@Override
public ImmutableList<Boolean> eval(final ParseGraph graph, final Encoding encoding) {
return evalLists(left.eval(graph, encoding), right.eval(graph, encoding));
}

private ImmutableList<Boolean> evalLists(final ImmutableList<Boolean> lefts, final ImmutableList<Boolean> rights) {
return reverse(padList(evalLists(lefts, rights, new ImmutableList<>()).computeResult(), Math.abs(lefts.size - rights.size)).computeResult());
}

private SafeTrampoline<ImmutableList<Boolean>> evalLists(final ImmutableList<Boolean> lefts, final ImmutableList<Boolean> rights, final ImmutableList<Boolean> results) {
if (lefts.isEmpty() || rights.isEmpty()) { return complete(() -> results); }
return intermediate(() -> evalLists(lefts.tail, rights.tail, results.add(eval(lefts.head, rights.head))));
}

private SafeTrampoline<ImmutableList<Boolean>> padList(final ImmutableList<Boolean> list, final long size) {
if (size <= 0) { return complete(() -> list); }
return intermediate(() -> padList(list.add(false), size - 1));
}

public abstract boolean eval(final boolean left, final boolean right);

@Override
public String toString() {
return getClass().getSimpleName() + "(" + left + "," + right + ")";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package io.parsingdata.metal.expression.logical;

import io.parsingdata.metal.data.ParseGraph;
import io.parsingdata.metal.encoding.Encoding;
import io.parsingdata.metal.expression.Expression;

/**
Expand All @@ -30,8 +28,8 @@ public Not(final Expression operand) {
}

@Override
public boolean eval(final ParseGraph graph, final Encoding encoding) {
return !operand.eval(graph, encoding);
public boolean eval(final boolean value) {
return !value;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package io.parsingdata.metal.expression.logical;

import io.parsingdata.metal.data.ParseGraph;
import io.parsingdata.metal.encoding.Encoding;
import io.parsingdata.metal.expression.Expression;

/**
Expand All @@ -30,8 +28,8 @@ public Or(final Expression left, final Expression right) {
}

@Override
public boolean eval(final ParseGraph graph, final Encoding encoding) {
return left.eval(graph, encoding) || right.eval(graph, encoding);
public boolean eval(final boolean left, final boolean right) {
return left || right;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,18 @@

package io.parsingdata.metal.expression.logical;

import static io.parsingdata.metal.SafeTrampoline.complete;
import static io.parsingdata.metal.SafeTrampoline.intermediate;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.data.transformation.Reversal.reverse;

import java.util.Objects;

import io.parsingdata.metal.SafeTrampoline;
import io.parsingdata.metal.Util;
import io.parsingdata.metal.data.ImmutableList;
import io.parsingdata.metal.data.ParseGraph;
import io.parsingdata.metal.encoding.Encoding;
import io.parsingdata.metal.expression.Expression;

/**
Expand All @@ -39,6 +46,18 @@ public UnaryLogicalExpression(final Expression operand) {
this.operand = checkNotNull(operand, "operand");
}

@Override
public ImmutableList<Boolean> eval(final ParseGraph graph, final Encoding encoding) {
return reverse(eval(operand.eval(graph, encoding), new ImmutableList<>()).computeResult());
}

private SafeTrampoline<ImmutableList<Boolean>> eval(final ImmutableList<Boolean> values, final ImmutableList<Boolean> result) {
if (values.isEmpty()) { return complete(() -> result); }
return intermediate(() -> eval(values.tail, result.add(eval(values.head))));
}

public abstract boolean eval(final boolean value);

@Override
public String toString() {
return getClass().getSimpleName() + "(" + operand + ")";
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/io/parsingdata/metal/token/Post.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.parsingdata.metal.token;

import static io.parsingdata.metal.Util.allTrue;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.Util.failure;
import static io.parsingdata.metal.Util.success;
Expand Down Expand Up @@ -54,7 +55,7 @@ public Post(final String name, final Token token, final Expression predicate, fi
@Override
protected Optional<Environment> parseImpl(final String scope, final Environment environment, final Encoding encoding) throws IOException {
return token.parse(scope, environment.addBranch(this), encoding)
.map(nextEnvironment -> predicate.eval(nextEnvironment.order, encoding) ? success(nextEnvironment.closeBranch()) : failure())
.map(nextEnvironment -> allTrue(predicate.eval(nextEnvironment.order, encoding)) ? success(nextEnvironment.closeBranch()) : failure())
.orElseGet(Util::failure);
}

Expand Down
3 changes: 2 additions & 1 deletion core/src/main/java/io/parsingdata/metal/token/Pre.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package io.parsingdata.metal.token;

import static io.parsingdata.metal.Util.allTrue;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.Util.failure;
import static io.parsingdata.metal.Util.success;
Expand Down Expand Up @@ -54,7 +55,7 @@ public Pre(final String name, final Token token, final Expression predicate, fin

@Override
protected Optional<Environment> parseImpl(final String scope, final Environment environment, final Encoding encoding) throws IOException {
if (!predicate.eval(environment.order, encoding)) {
if (!allTrue(predicate.eval(environment.order, encoding))) {
return failure();
}
return token.parse(scope, environment.addBranch(this), encoding)
Expand Down
6 changes: 4 additions & 2 deletions core/src/main/java/io/parsingdata/metal/token/While.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,18 @@

package io.parsingdata.metal.token;

import static io.parsingdata.metal.Shorthand.expTrue;
import static io.parsingdata.metal.Trampoline.complete;
import static io.parsingdata.metal.Trampoline.intermediate;
import static io.parsingdata.metal.Util.allTrue;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.Util.success;

import java.io.IOException;
import java.util.Objects;
import java.util.Optional;

import static io.parsingdata.metal.Shorthand.expTrue;

import io.parsingdata.metal.Trampoline;
import io.parsingdata.metal.Util;
import io.parsingdata.metal.data.Environment;
Expand Down Expand Up @@ -62,7 +64,7 @@ protected Optional<Environment> parseImpl(final String scope, final Environment
}

private Trampoline<Optional<Environment>> iterate(final String scope, final Environment environment, final Encoding encoding) throws IOException {
if (predicate.eval(environment.order, encoding)) {
if (allTrue(predicate.eval(environment.order, encoding))) {
return token.parse(scope, environment, encoding)
.map(nextEnvironment -> intermediate(() -> iterate(scope, nextEnvironment, encoding)))
.orElseGet(() -> complete(Util::failure));
Expand Down
3 changes: 2 additions & 1 deletion core/src/test/java/io/parsingdata/metal/ArgumentsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.junit.runners.Parameterized.Parameters;

import io.parsingdata.metal.data.Environment;
import io.parsingdata.metal.data.ImmutableList;
import io.parsingdata.metal.data.ParseGraph;
import io.parsingdata.metal.encoding.Encoding;
import io.parsingdata.metal.expression.Expression;
Expand Down Expand Up @@ -72,7 +73,7 @@ public class ArgumentsTest {
final private static String EMPTY_NAME = "";
final private static ValueExpression VALID_VE = con(1);
final private static BinaryOperator<ValueExpression> VALID_REDUCER = (left, right) -> null;
final private static Expression VALID_E = new Expression() { @Override public boolean eval(final ParseGraph graph, final Encoding encoding) { return false; }};
final private static Expression VALID_E = new Expression() { @Override public ImmutableList<Boolean> eval(final ParseGraph graph, final Encoding encoding) { return ImmutableList.create(false); }};
final private static Token VALID_T = new Token("", null) { @Override protected Optional<Environment> parseImpl(final String scope, final Environment environment, final Encoding encoding) throws IOException { return null; } };

private final Class<?> _class;
Expand Down
Loading

0 comments on commit ba6e4be

Please sign in to comment.