Skip to content

Commit

Permalink
Remove the Scope class and make it part of the Ref value expression.
Browse files Browse the repository at this point in the history
The scope only makes sense in combination with ref. It has no function
for other value expressions. When it is included within the ref, we can
also make it more efficient, because we can check the scopeDepth while
traversing the parseGraph for the values in a single run.

Co-authored-by: jvdb <[email protected]>
  • Loading branch information
mvanaken and jvdb committed Feb 9, 2024
1 parent ddf0add commit 63d894c
Show file tree
Hide file tree
Showing 13 changed files with 159 additions and 161 deletions.
10 changes: 8 additions & 2 deletions core/src/main/java/io/parsingdata/metal/Shorthand.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@
import io.parsingdata.metal.expression.value.FoldRight;
import io.parsingdata.metal.expression.value.Join;
import io.parsingdata.metal.expression.value.Reverse;
import io.parsingdata.metal.expression.value.Scope;
import io.parsingdata.metal.expression.value.SingleValueExpression;
import io.parsingdata.metal.expression.value.UnaryValueExpression;
import io.parsingdata.metal.expression.value.Value;
Expand Down Expand Up @@ -349,7 +348,14 @@ private Shorthand() {}
public static BinaryValueExpression mapRight(final BiFunction<ValueExpression, ValueExpression, BinaryValueExpression> func, final SingleValueExpression leftExpand, final ValueExpression right) { return func.apply(exp(leftExpand, count(right)), right); }

/** @see Bytes */ public static ValueExpression bytes(final ValueExpression operand) { return new Bytes(operand); }
/** @see Scope */ public static ValueExpression scope(final ValueExpression scopedValueExpression, final SingleValueExpression scopeSize) { return new Scope(scopedValueExpression, scopeSize); }

/** @deprecated Use {@link #scope(NameRef, SingleValueExpression)} instead. You probably need to switch {@code last} with {@code scope}, e.g. {@code scope(last(x), y)} to {@code last(scope(x, y))}. */
@Deprecated
public static ValueExpression scope(final SingleValueExpression scopedValueExpression, final SingleValueExpression scopeSize) { throw new UnsupportedOperationException("A deprecated shorthand for scope is used. Use one of the other alternatives instead."); }
/** @see Ref */ public static NameRef scope(final NameRef operand, final SingleValueExpression scopeSize) { return operand.withScope(scopeSize); }
/** @see Ref */ public static NameRef scope(final NameRef operand, final SingleValueExpression scopeSize, final SingleValueExpression limit) { return operand.withScope(scopeSize).withLimit(limit); }
/** @see Ref */ public static DefinitionRef scope(final DefinitionRef operand, final SingleValueExpression scopeSize) { return operand.withScope(scopeSize); }
/** @see Ref */ public static DefinitionRef scope(final DefinitionRef operand, SingleValueExpression scopeSize, final SingleValueExpression limit) { return operand.withScope(scopeSize).withLimit(limit); }

/** @see And */ public static BinaryLogicalExpression and(final Expression left, final Expression right) { return new And(left, right); }
/** @see Or */ public static BinaryLogicalExpression or(final Expression left, final Expression right) { return new Or(left, right); }
Expand Down
31 changes: 17 additions & 14 deletions core/src/main/java/io/parsingdata/metal/data/ParseState.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,61 +42,63 @@ public class ParseState extends ImmutableObject {
public final Source source;
public final ImmutableList<ImmutablePair<Token, BigInteger>> iterations;
public final ImmutableList<ParseReference> references;
public final int scopeDepth;

public ParseState(final ParseGraph order, final ParseValueCache cache, final Source source, final BigInteger offset, final ImmutableList<ImmutablePair<Token, BigInteger>> iterations, final ImmutableList<ParseReference> references) {
public ParseState(final ParseGraph order, final ParseValueCache cache, final Source source, final BigInteger offset, final ImmutableList<ImmutablePair<Token, BigInteger>> iterations, final ImmutableList<ParseReference> references, final int scopeDepth) {
this.order = checkNotNull(order, "order");
this.cache = checkNotNull(cache, "cache");
this.source = checkNotNull(source, "source");
this.offset = checkNotNegative(offset, "offset");
this.iterations = checkNotNull(iterations, "iterations");
this.references = checkNotNull(references, "references");
this.scopeDepth = scopeDepth;
}

public static ParseState createFromByteStream(final ByteStream input, final BigInteger offset) {
return new ParseState(ParseGraph.EMPTY, new ParseValueCache(), new ByteStreamSource(input), offset, new ImmutableList<>(), new ImmutableList<>());
return new ParseState(ParseGraph.EMPTY, new ParseValueCache(), new ByteStreamSource(input), offset, new ImmutableList<>(), new ImmutableList<>(), 0);
}

public static ParseState createFromByteStream(final ByteStream input) {
return createFromByteStream(input, ZERO);
}

public ParseState addBranch(final Token token) {
return new ParseState(order.addBranch(token), cache, source, offset, token.isIterable() ? iterations.add(new ImmutablePair<>(token, ZERO)) : iterations, references);
return new ParseState(order.addBranch(token), cache, source, offset, token.isIterable() ? iterations.add(new ImmutablePair<>(token, ZERO)) : iterations, references, token.isScopeDelimiter() ? scopeDepth + 1 : scopeDepth);
}

public ParseState closeBranch(final Token token) {
if (token.isIterable() && !iterations.head.left.equals(token)) {
throw new IllegalStateException(format("Cannot close branch for iterable token %s. Current iteration state is for token %s.", token.name, iterations.head.left.name));
}
return new ParseState(order.closeBranch(), cache, source, offset, token.isIterable() ? iterations.tail : iterations, references);
return new ParseState(order.closeBranch(), cache, source, offset, token.isIterable() ? iterations.tail : iterations, references, token.isScopeDelimiter() ? scopeDepth - 1 : scopeDepth);
}

public ParseState add(final ParseReference parseReference) {
return new ParseState(order, cache, source, offset, iterations, references.add(parseReference));
return new ParseState(order, cache, source, offset, iterations, references.add(parseReference), scopeDepth);
}

public ParseState add(final ParseValue parseValue) {
return new ParseState(order.add(parseValue), cache.add(parseValue), source, offset, iterations, references);
return new ParseState(order.add(parseValue), cache.add(parseValue), source, offset, iterations, references, scopeDepth);
}

public ParseState createCycle(final ParseReference parseReference) {
return new ParseState(order.add(parseReference), cache, source, offset, iterations, references);
return new ParseState(order.add(parseReference), cache, source, offset, iterations, references, scopeDepth);
}

public ParseState iterate() {
return new ParseState(order, cache, source, offset, iterations.tail.add(new ImmutablePair<>(iterations.head.left, iterations.head.right.add(ONE))), references);
return new ParseState(order, cache, source, offset, iterations.tail.add(new ImmutablePair<>(iterations.head.left, iterations.head.right.add(ONE))), references, scopeDepth);
}

public Optional<ParseState> seek(final BigInteger newOffset) {
return newOffset.compareTo(ZERO) >= 0 ? Optional.of(new ParseState(order, cache, source, newOffset, iterations, references)) : Optional.empty();
return newOffset.compareTo(ZERO) >= 0 ? Optional.of(new ParseState(order, cache, source, newOffset, iterations, references, scopeDepth)) : Optional.empty();
}

public ParseState withOrder(final ParseGraph order) {
return new ParseState(order, NO_CACHE, source, offset, iterations, references);
return new ParseState(order, NO_CACHE, source, offset, iterations, references, scopeDepth);
}

public ParseState withSource(final Source source) {
return new ParseState(order, cache, source, ZERO, iterations, references);
return new ParseState(order, cache, source, ZERO, iterations, references, scopeDepth);
}

public Optional<Slice> slice(final BigInteger length) {
Expand All @@ -107,7 +109,7 @@ public Optional<Slice> slice(final BigInteger length) {
public String toString() {
final String iterationsString = iterations.isEmpty() ? "" : ";iterations:" + iterations;
final String referencesString = references.isEmpty() ? "" : ";references:" + references;
return getClass().getSimpleName() + "(source:" + source + ";offset:" + offset + ";order:" + order + iterationsString + referencesString + ";" + cache + ")";
return getClass().getSimpleName() + "(source:" + source + ";offset:" + offset + ";order:" + order + iterationsString + referencesString + ";scopeDepth:" + scopeDepth + ";" + cache + ")";
}

@Override
Expand All @@ -118,12 +120,13 @@ public boolean equals(final Object obj) {
&& Objects.equals(offset, ((ParseState)obj).offset)
&& Objects.equals(source, ((ParseState)obj).source)
&& Objects.equals(iterations, ((ParseState)obj).iterations)
&& Objects.equals(references, ((ParseState)obj).references);
&& Objects.equals(references, ((ParseState)obj).references)
&& Objects.equals(scopeDepth, ((ParseState)obj).scopeDepth);
}

@Override
public int immutableHashCode() {
return Objects.hash(getClass(), order, cache, offset, source, iterations, references);
return Objects.hash(getClass(), order, cache, offset, source, iterations, references, scopeDepth);
}

}
14 changes: 14 additions & 0 deletions core/src/main/java/io/parsingdata/metal/data/Selection.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,20 @@ public static ImmutableList<ParseValue> getAllValues(final ParseGraph graph, fin
return getAllValues(graph, predicate, NO_LIMIT);
}

public static ImmutableList<ParseValue> getAllValues(final ParseGraph graph, final Predicate<ParseValue> predicate, final int limit, final int requestedScope, final int currentScope) {
return getAllScopedValues(graph, predicate, limit, requestedScope, currentScope).computeResult();
}

private static Trampoline<ImmutableList<ParseValue>> getAllScopedValues(final ParseGraph graph, final Predicate<ParseValue> predicate, final int limit, final int requestedScope, final int currentScope) {
if (graph.isEmpty() || limit == 0) {
return complete(ImmutableList::new);
}
if (requestedScope >= currentScope) {
return complete(() -> getAllValues(graph, predicate, limit));
}
return intermediate(() -> getAllScopedValues(graph.head.asGraph(), predicate, limit, requestedScope, graph.head.getDefinition().isScopeDelimiter() ? currentScope - 1 : currentScope));
}

private static Trampoline<ImmutableList<ParseValue>> getAllValues(final ImmutableList<ParseGraph> graphList, final ImmutableList<ParseValue> valueList, final Predicate<ParseValue> predicate, final int limit) {
if (graphList.isEmpty() || valueList.size == limit) {
return complete(() -> valueList);
Expand Down
107 changes: 0 additions & 107 deletions core/src/main/java/io/parsingdata/metal/expression/value/Scope.java

This file was deleted.

Loading

0 comments on commit 63d894c

Please sign in to comment.