Skip to content

Commit

Permalink
When doing #70, we forgot to convert Ref's limit argument to SingleVa…
Browse files Browse the repository at this point in the history
…lueExpression. Discovered when preparing for #285.
  • Loading branch information
jvdb committed Feb 10, 2021
1 parent bcd3673 commit a3df037
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 24 deletions.
4 changes: 2 additions & 2 deletions core/src/main/java/io/parsingdata/metal/Shorthand.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,9 +185,9 @@ private Shorthand() {}
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 NameRef ref(final String name, final SingleValueExpression 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 DefinitionRef ref(final Token definition, final SingleValueExpression limit) { return new DefinitionRef(definition, limit); }
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))); }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import static io.parsingdata.metal.expression.value.NotAValue.NOT_A_VALUE;

import java.util.Objects;
import java.util.Optional;
import java.util.function.Predicate;

import io.parsingdata.metal.Trampoline;
Expand All @@ -32,6 +33,7 @@
import io.parsingdata.metal.data.ParseState;
import io.parsingdata.metal.data.ParseValue;
import io.parsingdata.metal.encoding.Encoding;
import io.parsingdata.metal.expression.value.SingleValueExpression;
import io.parsingdata.metal.expression.value.Value;
import io.parsingdata.metal.expression.value.ValueExpression;
import io.parsingdata.metal.token.Token;
Expand All @@ -49,37 +51,32 @@ public class Ref<T> implements ValueExpression {

public final T reference;
public final Predicate<ParseValue> predicate;
public final ValueExpression limit;
public final SingleValueExpression limit;

private Ref(final T reference, final Predicate<ParseValue> predicate, final ValueExpression limit) {
private Ref(final T reference, final Predicate<ParseValue> predicate, final SingleValueExpression limit) {
this.reference = checkNotNull(reference, "reference");
this.predicate = checkNotNull(predicate, "predicate");
this.limit = limit;
}

public static class NameRef extends Ref<String> {
public NameRef(final String reference) { this(reference, null); }
public NameRef(final String reference, final ValueExpression limit) { super(reference, value -> value.matches(reference), limit); }
public NameRef(final String reference, final SingleValueExpression limit) { super(reference, value -> value.matches(reference), limit); }
}

public static class DefinitionRef extends Ref<Token> {
public DefinitionRef(final Token reference) { this(reference, null); }
public DefinitionRef(final Token reference, final ValueExpression limit) { super(reference, value -> value.definition.equals(reference), limit); }
public DefinitionRef(final Token reference, final SingleValueExpression limit) { super(reference, value -> value.definition.equals(reference), limit); }
}

@Override
public ImmutableList<Value> eval(final ParseState parseState, final Encoding encoding) {
if (limit == null) {
return evalImpl(parseState, NO_LIMIT);
}
final ImmutableList<Value> evaluatedLimit = limit.eval(parseState, encoding);
if (evaluatedLimit.size != 1) {
throw new IllegalArgumentException("Limit must evaluate to a single non-empty value.");
}
if (evaluatedLimit.head.equals(NOT_A_VALUE)) {
return ImmutableList.create(NOT_A_VALUE);
}
return evalImpl(parseState, evaluatedLimit.head.asNumeric().intValueExact());
return limit.evalSingle(parseState, encoding)
.map(limitValue -> limitValue.equals(NOT_A_VALUE) ? ImmutableList.create(NOT_A_VALUE) : evalImpl(parseState, limitValue.asNumeric().intValueExact()))
.orElseThrow(() -> new IllegalArgumentException("Limit must evaluate to a non-empty value."));
}

private ImmutableList<Value> evalImpl(final ParseState parseState, final int limit) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import static io.parsingdata.metal.Shorthand.con;
import static io.parsingdata.metal.Shorthand.div;
import static io.parsingdata.metal.Shorthand.exp;
import static io.parsingdata.metal.Shorthand.last;
import static io.parsingdata.metal.Shorthand.ref;
import static io.parsingdata.metal.Shorthand.rep;
import static io.parsingdata.metal.expression.value.NotAValue.NOT_A_VALUE;
Expand Down Expand Up @@ -49,23 +50,16 @@ public void before() {
parseState = rep(any("a")).parse(env(stream(1, 2, 3))).get();
}

@Test
public void multiLimit() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Limit must evaluate to a single non-empty value.");
ref("a", exp(con(1), con(3))).eval(parseState, enc());
}

@Test
public void emptyLimit() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Limit must evaluate to a single non-empty value.");
ref("a", ref("b")).eval(parseState, enc());
thrown.expectMessage("Limit must evaluate to a non-empty value.");
ref("a", last(ref("b"))).eval(parseState, enc());
}

@Test
public void nanLimit() {
final ImmutableList<Value> result = ref("a", div(con(1), con(0))).eval(parseState, enc());
final ImmutableList<Value> result = ref("a", last(div(con(1), con(0)))).eval(parseState, enc());
assertEquals(1, result.size);
assertEquals(NOT_A_VALUE, result.head);
}
Expand Down

0 comments on commit a3df037

Please sign in to comment.