Skip to content

Commit

Permalink
Merge pull request #283 from parsingdata/single-value-expression
Browse files Browse the repository at this point in the history
Add SingleValueExpression to type ValueExpressions that always return a single value
  • Loading branch information
jvdb committed Feb 16, 2019
2 parents 87e0260 + 60fedd2 commit 1744fda
Show file tree
Hide file tree
Showing 33 changed files with 233 additions and 225 deletions.
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); }
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); }
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 @@ -33,19 +33,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 {@link IllegalArgumentException} is thrown.
*/
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 +57,10 @@ 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.");
}
return expand(baseList, countList.head.asNumeric().intValueExact(), new ImmutableList<>()).computeResult();
return count.evalSingle(parseState, encoding)
.filter(countValue -> !countValue.equals(NOT_A_VALUE))
.map(countValue -> expand(baseList, countValue.asNumeric().intValueExact(), new ImmutableList<>()).computeResult())
.orElseThrow(() -> new IllegalArgumentException("Count must evaluate to a non-empty countable value."));
}

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

0 comments on commit 1744fda

Please sign in to comment.