Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SingleValueExpression to type ValueExpressions that always return a single value #283

Merged
merged 8 commits into from
Feb 16, 2019
73 changes: 37 additions & 36 deletions core/src/main/java/io/parsingdata/metal/Shorthand.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@
import io.parsingdata.metal.expression.value.FoldLeft;
import io.parsingdata.metal.expression.value.FoldRight;
import io.parsingdata.metal.expression.value.Reverse;
import io.parsingdata.metal.expression.value.SingleValueExpression;
import io.parsingdata.metal.expression.value.UnaryValueExpression;
import io.parsingdata.metal.expression.value.Value;
import io.parsingdata.metal.expression.value.ValueExpression;
Expand Down Expand Up @@ -90,22 +91,22 @@
public final class Shorthand {

public static final Token EMPTY = def(EMPTY_NAME, 0L);
public static final ValueExpression SELF = new Self();
public static final ValueExpression CURRENT_OFFSET = new CurrentOffset();
public static final ValueExpression CURRENT_ITERATION = new CurrentIteration(con(0));
public static final SingleValueExpression SELF = new Self();
public static final SingleValueExpression CURRENT_OFFSET = new CurrentOffset();
public static final SingleValueExpression CURRENT_ITERATION = new CurrentIteration(con(0));
public static final Expression TRUE = new True();

private Shorthand() {}

public static Token def(final String name, final ValueExpression size, final Expression predicate, final Encoding encoding) { return post(def(name, size, encoding), predicate); }
public static Token def(final String name, final ValueExpression size, final Expression predicate) { return def(name, size, predicate, null); }
public static Token def(final String name, final ValueExpression size, final Encoding encoding) { return new Def(name, size, encoding); }
public static Token def(final String name, final ValueExpression size) { return def(name, size, (Encoding)null); }
public static Token def(final String name, final SingleValueExpression size, final Expression predicate, final Encoding encoding) { return post(def(name, size, encoding), predicate); }
jvdb marked this conversation as resolved.
Show resolved Hide resolved
public static Token def(final String name, final SingleValueExpression size, final Expression predicate) { return def(name, size, predicate, null); }
public static Token def(final String name, final SingleValueExpression size, final Encoding encoding) { return new Def(name, size, encoding); }
public static Token def(final String name, final SingleValueExpression size) { return def(name, size, (Encoding)null); }
public static Token def(final String name, final long size, final Expression predicate, final Encoding encoding) { return def(name, con(size), predicate, encoding); }
public static Token def(final String name, final long size, final Expression predicate) { return def(name, size, predicate, null); }
public static Token def(final String name, final long size, final Encoding encoding) { return def(name, con(size), encoding); }
public static Token def(final String name, final long size) { return def(name, size, (Encoding)null); }
public static Token nod(final ValueExpression size) { return def(EMPTY_NAME, size); }
public static Token nod(final SingleValueExpression size) { return def(EMPTY_NAME, size); }
public static Token nod(final long size) { return nod(con(size)); }
public static Token cho(final String name, final Encoding encoding, final Token token1, final Token token2, final Token... tokens) { return new Cho(name, encoding, token1, token2, tokens); }
public static Token cho(final String name, final Token token1, final Token token2, final Token... tokens) { return cho(name, null, token1, token2, tokens); }
Expand All @@ -115,10 +116,10 @@ private Shorthand() {}
public static Token rep(final String name, final Token token) { return rep(name, token, null); }
public static Token rep(final Token token, final Encoding encoding) { return rep(NO_NAME, token, encoding); }
public static Token rep(final Token token) { return rep(token, null); }
public static Token repn(final String name, final Token token, final ValueExpression n, final Encoding encoding) { return new RepN(name, token, n, encoding); }
public static Token repn(final String name, final Token token, final ValueExpression n) { return repn(name, token, n, null); }
public static Token repn(final Token token, final ValueExpression n, final Encoding encoding) { return repn(NO_NAME, token, n, encoding); }
public static Token repn(final Token token, final ValueExpression n) { return repn(token, n, null); }
public static Token repn(final String name, final Token token, final SingleValueExpression n, final Encoding encoding) { return new RepN(name, token, n, encoding); }
public static Token repn(final String name, final Token token, final SingleValueExpression n) { return repn(name, token, n, null); }
public static Token repn(final Token token, final SingleValueExpression n, final Encoding encoding) { return repn(NO_NAME, token, n, encoding); }
public static Token repn(final Token token, final SingleValueExpression n) { return repn(token, n, null); }
public static Token seq(final String name, final Encoding encoding, final Token token1, final Token token2, final Token... tokens) { return new Seq(name, encoding, token1, token2, tokens); }
public static Token seq(final String name, final Token token1, final Token token2, final Token... tokens) { return seq(name, null, token1, token2, tokens); }
public static Token seq(final Encoding encoding, final Token token1, final Token token2, final Token... tokens) { return seq(NO_NAME, encoding, token1, token2, tokens); }
Expand Down Expand Up @@ -172,40 +173,40 @@ private Shorthand() {}
public static UnaryValueExpression not(final ValueExpression operand) { return new io.parsingdata.metal.expression.value.bitwise.Not(operand); }
public static BinaryValueExpression shl(final ValueExpression left, final ValueExpression right) { return new ShiftLeft(left, right); }
public static BinaryValueExpression shr(final ValueExpression left, final ValueExpression right) { return new ShiftRight(left, right); }
public static ValueExpression con(final long value) { return con(value, DEFAULT_ENCODING); }
public static ValueExpression con(final long value, final Encoding encoding) { return con(ConstantFactory.createFromNumeric(value, encoding)); }
public static ValueExpression con(final String value) { return con(value, DEFAULT_ENCODING); }
public static ValueExpression con(final String value, final Encoding encoding) { return con(ConstantFactory.createFromString(value, encoding)); }
public static ValueExpression con(final Value value) { return new Const(value); }
public static ValueExpression con(final Encoding encoding, final int... values) { return new Const(new CoreValue(createFromBytes(toByteArray(values)), encoding)); }
public static ValueExpression con(final int... values) { return con(DEFAULT_ENCODING, values); }
public static ValueExpression con(final byte[] value) { return con(value, DEFAULT_ENCODING); }
public static ValueExpression con(final byte[] value, final Encoding encoding) { return con(ConstantFactory.createFromBytes(value, encoding)); }
public static SingleValueExpression con(final long value) { return con(value, DEFAULT_ENCODING); }
public static SingleValueExpression con(final long value, final Encoding encoding) { return con(ConstantFactory.createFromNumeric(value, encoding)); }
public static SingleValueExpression con(final String value) { return con(value, DEFAULT_ENCODING); }
public static SingleValueExpression con(final String value, final Encoding encoding) { return con(ConstantFactory.createFromString(value, encoding)); }
public static SingleValueExpression con(final Value value) { return new Const(value); }
public static SingleValueExpression con(final Encoding encoding, final int... values) { return new Const(new CoreValue(createFromBytes(toByteArray(values)), encoding)); }
public static SingleValueExpression con(final int... values) { return con(DEFAULT_ENCODING, values); }
public static SingleValueExpression con(final byte[] value) { return con(value, DEFAULT_ENCODING); }
public static SingleValueExpression con(final byte[] value, final Encoding encoding) { return con(ConstantFactory.createFromBytes(value, encoding)); }
public static ValueExpression len(final ValueExpression operand) { return new Len(operand); }
jvdb marked this conversation as resolved.
Show resolved Hide resolved
public static NameRef ref(final String name) { return ref(name, null); }
public static NameRef ref(final String name, final ValueExpression limit) { return new NameRef(name, limit); }
public static DefinitionRef ref(final Token definition) { return ref(definition, null); }
public static DefinitionRef ref(final Token definition, final ValueExpression limit) { return new DefinitionRef(definition, limit); }
public static ValueExpression first(final ValueExpression operand) { return new First(operand); }
public static ValueExpression last(final ValueExpression operand) { return new Last(operand); }
public static ValueExpression last(final NameRef operand) { return new Last(new NameRef(operand.reference, con(1))); }
public static ValueExpression last(final DefinitionRef operand) { return new Last(new DefinitionRef(operand.reference, con(1))); }
public static SingleValueExpression first(final ValueExpression operand) { return new First(operand); }
public static SingleValueExpression last(final ValueExpression operand) { return new Last(operand); }
public static SingleValueExpression last(final NameRef operand) { return new Last(new NameRef(operand.reference, con(1))); }
public static SingleValueExpression last(final DefinitionRef operand) { return new Last(new DefinitionRef(operand.reference, con(1))); }
public static ValueExpression nth(final ValueExpression values, final ValueExpression indices) { return new Nth(values, indices); }
public static ValueExpression offset(final ValueExpression operand) { return new Offset(operand); }
public static ValueExpression iteration(final int level) { return iteration(con(level)); }
public static ValueExpression iteration(final ValueExpression level) { return new CurrentIteration(level); }
public static SingleValueExpression iteration(final int level) { return iteration(con(level)); }
public static SingleValueExpression iteration(final ValueExpression level) { return new CurrentIteration(level); }
public static ValueExpression cat(final ValueExpression left, final ValueExpression right) { return new Cat(left, right); }
public static ValueExpression cat(final ValueExpression operand) { return new FoldCat(operand); }
public static SingleValueExpression cat(final ValueExpression operand) { return new FoldCat(operand); }
public static ValueExpression elvis(final ValueExpression left, final ValueExpression right) { return new Elvis(left, right); }
public static ValueExpression count(final ValueExpression operand) { return new Count(operand); }
public static ValueExpression foldLeft(final ValueExpression values, final BinaryOperator<ValueExpression> reducer) { return new FoldLeft(values, reducer, null); }
public static ValueExpression foldLeft(final ValueExpression values, final BinaryOperator<ValueExpression> reducer, final ValueExpression initial) { return new FoldLeft(values, reducer, initial); }
public static ValueExpression foldRight(final ValueExpression values, final BinaryOperator<ValueExpression> reducer) { return new FoldRight(values, reducer, null); }
public static ValueExpression foldRight(final ValueExpression values, final BinaryOperator<ValueExpression> reducer, final ValueExpression initial) { return new FoldRight(values, reducer, initial); }
public static ValueExpression fold(final ValueExpression values, final BinaryOperator<ValueExpression> reducer) { return foldRight(values, reducer); }
public static ValueExpression fold(final ValueExpression values, final BinaryOperator<ValueExpression> reducer, final ValueExpression initial) { return foldRight(values, reducer, initial); }
public static SingleValueExpression count(final ValueExpression operand) { return new Count(operand); }
public static SingleValueExpression foldLeft(final ValueExpression values, final BinaryOperator<ValueExpression> reducer) { return new FoldLeft(values, reducer, null); }
public static SingleValueExpression foldLeft(final ValueExpression values, final BinaryOperator<ValueExpression> reducer, final SingleValueExpression initial) { return new FoldLeft(values, reducer, initial); }
public static SingleValueExpression foldRight(final ValueExpression values, final BinaryOperator<ValueExpression> reducer) { return new FoldRight(values, reducer, null); }
public static SingleValueExpression foldRight(final ValueExpression values, final BinaryOperator<ValueExpression> reducer, final SingleValueExpression initial) { return new FoldRight(values, reducer, initial); }
public static SingleValueExpression fold(final ValueExpression values, final BinaryOperator<ValueExpression> reducer) { return foldRight(values, reducer); }
public static SingleValueExpression fold(final ValueExpression values, final BinaryOperator<ValueExpression> reducer, final SingleValueExpression initial) { return foldRight(values, reducer, initial); }
public static ValueExpression rev(final ValueExpression values) { return new Reverse(values); }
public static ValueExpression exp(final ValueExpression base, final ValueExpression count) { return new Expand(base, count); }
public static ValueExpression exp(final ValueExpression base, final SingleValueExpression count) { return new Expand(base, count); }
public static BinaryValueExpression mapLeft(final BiFunction<ValueExpression, ValueExpression, BinaryValueExpression> func, final ValueExpression left, final ValueExpression rightExpand) { return func.apply(left, exp(rightExpand, count(left))); }
public static BinaryValueExpression mapRight(final BiFunction<ValueExpression, ValueExpression, BinaryValueExpression> func, final ValueExpression leftExpand, final ValueExpression right) { return func.apply(exp(leftExpand, count(right)), right); }
public static ValueExpression bytes(final ValueExpression operand) { return new Bytes(operand); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@
package io.parsingdata.metal.expression.value;

import java.util.Objects;
import java.util.Optional;

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

/**
* A {@link ValueExpression} representing a constant value.
* A {@link SingleValueExpression} representing a constant value.
* <p>
* Const has a single operand <code>value</code> (a {@link Value}). When
* evaluated, this value is returned.
*/
public class Const implements ValueExpression {
public class Const implements SingleValueExpression {

public final Value value;

Expand All @@ -38,8 +38,8 @@ public Const(final Value value) {
}

@Override
public ImmutableList<Value> eval(final ParseState parseState, final Encoding encoding) {
return ImmutableList.create(value);
public Optional<Value> evalSingle(final ParseState parseState, final Encoding encoding) {
return Optional.of(value);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@

import static io.parsingdata.metal.Util.bytesToHexString;
import static io.parsingdata.metal.Util.checkNotNull;
import static io.parsingdata.metal.encoding.Encoding.DEFAULT_ENCODING;

import java.math.BigInteger;
import java.util.BitSet;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import static io.parsingdata.metal.expression.value.NotAValue.NOT_A_VALUE;

import java.util.Objects;
import java.util.Optional;

import io.parsingdata.metal.Trampoline;
import io.parsingdata.metal.Util;
Expand All @@ -33,19 +34,20 @@
* A {@link ValueExpression} that expands a result by copying and concatenating
* it a specified amount of times.
* <p>
* An Expand expression has two operands: <code>bases</code> and
* <code>count</code> (both {@link ValueExpression}s). Both operands are
* evaluated. An <code>IllegalStateException</code> is thrown if evaluating
* <code>count</code> yields more than a single value. Multiple copies of the
* result of evaluating <code>bases</code> are concatenated. The amount of copies
* equals the result of evaluating <code>count</code>.
* An Expand expression has two operands: <code>bases</code> (a
* {@link ValueExpression}) and <code>count</code> (a
* {@link SingleValueExpression}). Both operands are evaluated. Multiple copies
* of the result of evaluating <code>bases</code> are concatenated. The amount
* of copies equals the result of evaluating <code>count</code>. If
* <code>count</code> evaluated to an empty value or <code>NOT_A_VALUE</code>,
* an IllegalArgumentException is thrown.
jvdb marked this conversation as resolved.
Show resolved Hide resolved
*/
public class Expand implements ValueExpression {

public final ValueExpression bases;
public final ValueExpression count;
public final SingleValueExpression count;

public Expand(final ValueExpression bases, final ValueExpression count) {
public Expand(final ValueExpression bases, final SingleValueExpression count) {
this.bases = checkNotNull(bases, "bases");
this.count = checkNotNull(count, "count");
}
Expand All @@ -56,11 +58,11 @@ public ImmutableList<Value> eval(final ParseState parseState, final Encoding enc
if (baseList.isEmpty()) {
return baseList;
}
final ImmutableList<Value> countList = count.eval(parseState, encoding);
if (countList.size != 1 || countList.head.equals(NOT_A_VALUE)) {
throw new IllegalArgumentException("Count must evaluate to a single non-empty value.");
final Optional<Value> countValue = count.evalSingle(parseState, encoding);
if (!countValue.isPresent() || countValue.get().equals(NOT_A_VALUE)) {
throw new IllegalArgumentException("Count must evaluate to a non-empty countable value.");
}
return expand(baseList, countList.head.asNumeric().intValueExact(), new ImmutableList<>()).computeResult();
return expand(baseList, countValue.get().asNumeric().intValueExact(), new ImmutableList<>()).computeResult();
jvdb marked this conversation as resolved.
Show resolved Hide resolved
}

private Trampoline<ImmutableList<Value>> expand(final ImmutableList<Value> baseList, final int countValue, final ImmutableList<Value> aggregate) {
Expand Down
Loading