Skip to content

Commit

Permalink
Add OnReject support to Group
Browse files Browse the repository at this point in the history
Allow `Group` clauses to take rejected groups and handle them in the same way
as `Reject` and `Require`.
  • Loading branch information
apmasell authored and avarsava committed Feb 1, 2024
1 parent ab8f5c1 commit d3c2999
Show file tree
Hide file tree
Showing 9 changed files with 203 additions and 44 deletions.
1 change: 1 addition & 0 deletions changes/add_group_onreject.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* Add `OnReject` support to `Group` clauses
7 changes: 5 additions & 2 deletions language.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,8 +215,8 @@ dropped.

This reshapes the data.

- `Group` `By` _discriminator1_[`,` ...] [`Where` _condition_] _collectionname1_ `=` _collector1_[`,` ...]
- `Group` `By` _discriminator1_[`,` ...] `Using` _grouper_ _param_ `=` _expr1_[`,` ...] [`With` _output_[`,` ...]] [`Where` _condition_] _collectionname1_ `=` _collector1_[`,` ...]
- `Group` `By` _discriminator1_[`,` ...] [`Where` _condition_] `Into` _collectionname1_ `=` _collector1_[`,` ...] [`OnReject` _reject1_[ _reject2_[ ...]] `Resume`]
- `Group` `By` _discriminator1_[`,` ...] `Using` _grouper_ _param_ `=` _expr1_[`,` ...] [`With` _output_[`,` ...]] [`Where` _condition_] `Into` _collectionname1_ `=` _collector1_[`,` ...] [`OnReject` _reject1_[ _reject2_[ ...]] `Resume`]

Performs a grouping of the data. First, rows are collected in subgroups by
their _discriminators_. If `Using` is provided, those subgroups are modified by
Expand Down Expand Up @@ -245,6 +245,9 @@ another section. Each collector can have `Where` filters that limit the
collected data. Optionally, a `Where` filter can be applied to all the
collectors by providing _condition_.

Rows which are rejected are passed to the rejection handlers. These are
`Monitor` or `Dump` clauses or an `Alert` terminal. Rejection handlers can only
access the discriminators.

This reshapes the data.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,11 +216,11 @@ public static void renderSigner(
new Method("dynamicSignature", A_OBJECT_TYPE, new Type[] {A_STRING_TYPE, A_OBJECT_TYPE});
protected static final Method METHOD_SIGNATURE_ACCESSOR__STATIC_SIGNATURE =
new Method("staticSignature", A_OBJECT_TYPE, new Type[] {A_STRING_TYPE});
private static final Method METHOD_STREAM__FILTER =
static final Method METHOD_STREAM__FILTER =
new Method("filter", A_STREAM_TYPE, new Type[] {A_PREDICATE_TYPE});
private static final Method METHOD_STREAM__MAP =
new Method("map", A_STREAM_TYPE, new Type[] {A_FUNCTION_TYPE});
private static final Method METHOD_STREAM__ON_CLOSE =
static final Method METHOD_STREAM__ON_CLOSE =
new Method("onClose", A_BASE_STREAM_TYPE, new Type[] {A_RUNNABLE_TYPE});
private static final Method METHOD_STREAM__PEEK =
new Method("peek", A_STREAM_TYPE, new Type[] {A_CONSUMER_TYPE});
Expand Down Expand Up @@ -248,7 +248,7 @@ public BaseOliveBuilder(RootBuilder owner, InputFormatDefinition initialFormat)
*/
public final void call(
CallableDefinitionRenderer defineOlive, Stream<Consumer<Renderer>> arguments) {
final var arglist = arguments.collect(Collectors.toList());
final var arglist = arguments.toList();
if (arglist.size() != defineOlive.parameters()) {
throw new IllegalArgumentException(
String.format(
Expand Down Expand Up @@ -803,7 +803,7 @@ public Renderer pick(
}

public final RegroupVariablesBuilder regroup(
int line, int column, LoadableValue... capturedVariables) {
int line, int column, FilterBuilder filterBuilder, LoadableValue... capturedVariables) {
final var className =
String.format("%s/Group_%d_%d", BaseHotloadingCompiler.PACKAGE_INTERNAL, line, column);

Expand All @@ -830,11 +830,7 @@ public final RegroupVariablesBuilder regroup(
collectLambda.push(renderer);
renderer.methodGen().invokeStatic(A_RUNTIME_SUPPORT_TYPE, METHOD_REGROUP);

LambdaBuilder.pushVirtual(
renderer,
RegroupVariablesBuilder.METHOD_IS_OK.getName(),
LambdaBuilder.predicate(newType));
renderer.methodGen().invokeInterface(A_STREAM_TYPE, METHOD_STREAM__FILTER);
filterBuilder.pushFilterMethod(line, column, renderer, newType);
});

final var newRenderer = newLambda.renderer(oldType, this::emitSigner);
Expand Down Expand Up @@ -868,6 +864,7 @@ public final RegroupVariablesBuilder regroupWithGrouper(
LambdaBuilder.LambdaType collectorBuilderType,
LoadableValue[] grouperCaptures,
List<Pair<String, Type>> grouperVariables,
FilterBuilder filterBuilder,
LoadableValue... capturedVariables) {
final var className =
String.format(
Expand Down Expand Up @@ -960,11 +957,7 @@ public Type type() {
newLambda.push(renderer);
renderer.methodGen().invokeStatic(A_RUNTIME_SUPPORT_TYPE, METHOD_REGROUP_WITH_GROUPER);

LambdaBuilder.pushVirtual(
renderer,
RegroupVariablesBuilder.METHOD_IS_OK.getName(),
LambdaBuilder.predicate(newType));
renderer.methodGen().invokeInterface(A_STREAM_TYPE, METHOD_STREAM__FILTER);
filterBuilder.pushFilterMethod(line, column, renderer, newType);
});

final var newRenderer = newLambda.renderer(oldType, this::emitSigner);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package ca.on.oicr.gsi.shesmu.compiler;

import static ca.on.oicr.gsi.shesmu.compiler.BaseOliveBuilder.A_STREAM_TYPE;
import static ca.on.oicr.gsi.shesmu.compiler.BaseOliveBuilder.METHOD_STREAM__FILTER;
import static ca.on.oicr.gsi.shesmu.compiler.BaseOliveBuilder.METHOD_STREAM__ON_CLOSE;

import java.util.List;
import java.util.TreeSet;
import java.util.stream.Stream;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;

public interface FilterBuilder {
FilterBuilder SIMPLE =
(line, column, renderer, streamType) -> {
LambdaBuilder.pushVirtual(
renderer,
RegroupVariablesBuilder.METHOD_IS_OK.getName(),
LambdaBuilder.predicate(streamType));
renderer.methodGen().invokeInterface(A_STREAM_TYPE, METHOD_STREAM__FILTER);
};

static FilterBuilder of(List<RejectNode> rejectHandlers) {
if (rejectHandlers.isEmpty()) {
return SIMPLE;
}
final var freeVariables = new TreeSet<String>();
for (final var handler : rejectHandlers) {
handler.collectFreeVariables(freeVariables);
}
return (line, column, renderer, streamType) -> {
final var captures =
rejectHandlers.stream()
.flatMap(handler -> handler.requiredCaptures(renderer.root()))
.toArray(LoadableValue[]::new);
final var filterBuilder =
new LambdaBuilder(
renderer.root(),
String.format("Okay? %d:%d 🔍", line, column),
LambdaBuilder.predicate(streamType),
Stream.concat(
Stream.of(captures),
renderer.allValues().filter(v -> freeVariables.contains(v.name())))
.toArray(LoadableValue[]::new));

final var filterRenderer = filterBuilder.renderer(streamType, null);
filterRenderer.methodGen().visitCode();
filterRenderer.loadStream();
filterRenderer.methodGen().invokeVirtual(streamType, RegroupVariablesBuilder.METHOD_IS_OK);
final var failPath = filterRenderer.methodGen().newLabel();
filterRenderer.methodGen().ifZCmp(GeneratorAdapter.EQ, failPath);
filterRenderer.methodGen().push(true);
filterRenderer.methodGen().returnValue();
filterRenderer.methodGen().mark(failPath);
rejectHandlers.forEach(handler -> handler.render(renderer.root(), filterRenderer));
filterRenderer.methodGen().push(false);
filterRenderer.methodGen().returnValue();
filterRenderer.methodGen().endMethod();

filterBuilder.push(renderer);
renderer.methodGen().invokeInterface(A_STREAM_TYPE, METHOD_STREAM__FILTER);

final var closeBuilder =
new LambdaBuilder(
renderer.root(),
String.format("Okay? %d:%d 🗑️", line, column),
LambdaBuilder.RUNNABLE,
captures);
final var closeRenderer = closeBuilder.renderer();
closeRenderer.methodGen().visitCode();
rejectHandlers.forEach(handler -> handler.renderOnClose(closeRenderer));
closeRenderer.methodGen().visitInsn(Opcodes.RETURN);
closeRenderer.methodGen().visitMaxs(0, 0);
closeRenderer.methodGen().visitEnd();

closeBuilder.push(renderer);
renderer.methodGen().invokeInterface(A_STREAM_TYPE, METHOD_STREAM__ON_CLOSE);
renderer.methodGen().checkCast(A_STREAM_TYPE);
};
}

void pushFilterMethod(int line, int column, Renderer renderer, Type streamType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ private interface NodeConstructor<T> {
final var inputs = new AtomicReference<List<Pair<String, ExpressionNode>>>();
final var outputs = new AtomicReference<List<String>>();
final var where = new AtomicReference<Optional<ExpressionNode>>();
final var handlers = new AtomicReference<List<RejectNode>>(List.of());

var result =
parser
Expand Down Expand Up @@ -139,6 +140,17 @@ private interface NodeConstructor<T> {
ip.whitespace()
.listEmpty(collectors::set, GroupNode::parse, ',')
.whitespace());
final var rejectResult = result.keyword("OnReject");
if (rejectResult.isGood()) {
result =
rejectResult
.whitespace()
.list(handlers::set, (rp, ro) -> rp.whitespace().dispatch(REJECT_CLAUSES, ro))
.whitespace()
.keyword("Resume")
.whitespace();
}

if (result.isGood()) {
if (name.get() == null) {
output.accept(
Expand All @@ -149,7 +161,8 @@ private interface NodeConstructor<T> {
parser.column(),
collectors.get(),
discriminators.get(),
where.get()));
where.get(),
handlers.get()));
} else {
output.accept(
label ->
Expand All @@ -162,7 +175,8 @@ private interface NodeConstructor<T> {
outputs.get(),
collectors.get(),
discriminators.get(),
where.get()));
where.get(),
handlers.get()));
}
}
return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,10 +62,11 @@ public static Optional<List<Target>> checkDiscriminators(
}

private final List<GroupNode> children;
protected final int column;
private final int column;
private final List<DiscriminatorNode> discriminators;
private final Optional<String> label;
protected final int line;
private final int line;
private final List<RejectNode> rejectHandlers;
private final Optional<ExpressionNode> where;

public OliveClauseNodeGroup(
Expand All @@ -74,13 +75,15 @@ public OliveClauseNodeGroup(
int column,
List<GroupNode> children,
List<DiscriminatorNode> discriminators,
Optional<ExpressionNode> where) {
Optional<ExpressionNode> where,
List<RejectNode> rejectHandlers) {
this.label = label;
this.line = line;
this.column = column;
this.children = children;
this.discriminators = discriminators;
this.where = where;
this.rejectHandlers = rejectHandlers;
}

@Override
Expand All @@ -103,6 +106,7 @@ public void collectPlugins(Set<Path> pluginFileNames) {
discriminators.forEach(discriminator -> discriminator.collectPlugins(pluginFileNames));
children.forEach(child -> child.collectPlugins(pluginFileNames));
where.ifPresent(w -> w.collectPlugins(pluginFileNames));
rejectHandlers.forEach(r -> r.collectPlugins(pluginFileNames));
}

@Override
Expand Down Expand Up @@ -134,7 +138,7 @@ public Stream<OliveClauseRow> dashboard() {
}

@Override
public final ClauseStreamOrder ensureRoot(
public ClauseStreamOrder ensureRoot(
ClauseStreamOrder state,
Set<String> signableNames,
Consumer<SignableVariableCheck> addSignableCheck,
Expand Down Expand Up @@ -169,6 +173,7 @@ public void render(
oliveBuilder.regroup(
line,
column,
FilterBuilder.of(rejectHandlers),
oliveBuilder
.loadableValues()
.filter(value -> freeVariables.contains(value.name()))
Expand All @@ -183,17 +188,27 @@ public void render(
}

@Override
public final NameDefinitions resolve(
public NameDefinitions resolve(
OliveCompilerServices oliveCompilerServices,
NameDefinitions defs,
Consumer<String> errorHandler) {
final var rejectDefs =
defs.replaceStream(discriminators.stream().flatMap(DiscriminatorNode::targets), true);
var ok =
children.stream().filter(child -> child.resolve(defs, defs, errorHandler)).count()
== children.size()
& discriminators.stream()
.filter(discriminator -> discriminator.resolve(defs, errorHandler))
.count()
== discriminators.size();
== discriminators.size()
& rejectHandlers.stream()
.filter(
handler ->
handler
.resolve(oliveCompilerServices, rejectDefs, errorHandler)
.isGood())
.count()
== rejectHandlers.size();

ok =
ok
Expand Down Expand Up @@ -246,7 +261,7 @@ public final NameDefinitions resolve(
}

@Override
public final boolean resolveDefinitions(
public boolean resolveDefinitions(
OliveCompilerServices oliveCompilerServices, Consumer<String> errorHandler) {

return children.stream()
Expand All @@ -257,11 +272,17 @@ public final boolean resolveDefinitions(
.filter(group -> group.resolveDefinitions(oliveCompilerServices, errorHandler))
.count()
== discriminators.size()
& where.map(w -> w.resolveDefinitions(oliveCompilerServices, errorHandler)).orElse(true);
& where.map(w -> w.resolveDefinitions(oliveCompilerServices, errorHandler)).orElse(true)
& rejectHandlers.stream()
.filter(
rejectHandler ->
rejectHandler.resolveDefinitions(oliveCompilerServices, errorHandler))
.count()
== rejectHandlers.size();
}

@Override
public final boolean typeCheck(Consumer<String> errorHandler) {
public boolean typeCheck(Consumer<String> errorHandler) {
return children.stream().filter(group -> group.typeCheck(errorHandler)).count()
== children.size()
&& discriminators.stream()
Expand All @@ -280,6 +301,10 @@ public final boolean typeCheck(Consumer<String> errorHandler) {
}
return whereOk;
})
.orElse(true);
.orElse(true)
& rejectHandlers.stream()
.filter(rejectHandler -> rejectHandler.typeCheck(errorHandler))
.count()
== rejectHandlers.size();
}
}
Loading

0 comments on commit d3c2999

Please sign in to comment.