From 8095f0a74b08369d0ed4a82ae732a889cd5cdead Mon Sep 17 00:00:00 2001 From: Andre Masella Date: Thu, 16 Nov 2023 16:59:04 -0500 Subject: [PATCH] Generate `.actnow` in guided meditations This creates a new `Run` terminal in `RepeatFor` that allows generating `.actnow` files in a guided meditations. --- changes/add_medidate_now.md | 1 + guided-meditations.md | 5 + .../compiler/ExpressionCompilerServices.java | 3 + .../compiler/ExpressionNodeOptionalOf.java | 6 + .../gsi/shesmu/compiler/InformationNode.java | 38 +++- .../compiler/InformationNodeActNow.java | 196 ++++++++++++++++++ .../compiler/InformationNodeBaseRepeat.java | 4 +- .../compiler/InformationNodeRepeat.java | 3 +- .../shesmu/compiler/InformationNodeTable.java | 3 +- .../shesmu/compiler/OliveArgumentNode.java | 45 +++- .../compiler/OliveArgumentNodeOptional.java | 20 +- .../compiler/OliveArgumentNodeProvided.java | 9 +- .../compiler/OliveCompilerServices.java | 3 - .../gsi/shesmu/compiler/VariableTagNode.java | 6 + .../compiler/VariableTagNodeMultiple.java | 5 + .../compiler/VariableTagNodeSingle.java | 5 + .../gsi/shesmu/server/GuidedMeditation.java | 8 + .../server/plugins/BaseHumanTypeParser.java | 7 + 18 files changed, 350 insertions(+), 17 deletions(-) create mode 100644 changes/add_medidate_now.md create mode 100644 shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeActNow.java diff --git a/changes/add_medidate_now.md b/changes/add_medidate_now.md new file mode 100644 index 000000000..61e231f0f --- /dev/null +++ b/changes/add_medidate_now.md @@ -0,0 +1 @@ +* Add `Run` to `RepeatFor` in guided meditations to generate `.actnow` files. diff --git a/guided-meditations.md b/guided-meditations.md index e4b634ba5..635359b24 100644 --- a/guided-meditations.md +++ b/guided-meditations.md @@ -135,6 +135,11 @@ as if they had been written out repeatedly. The items will be placed in rows in a table. Each column starts with a string _header_ and then the text display information to fill that cell in _value_. +- ... `Run` _action_ [ `Tag` _tag_ ] `With` _parameter_`,` ... `As` _filename_ + +The items will be converted to an `.actnow` file that can be downloaded. This +works with the same syntax as the normal `Run` in an olive. The file will be +downloaded as _filename_`.actnow`. ### Simulations diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/ExpressionCompilerServices.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/ExpressionCompilerServices.java index 00ede0e95..35dcabbc6 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/ExpressionCompilerServices.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/ExpressionCompilerServices.java @@ -1,5 +1,6 @@ package ca.on.oicr.gsi.shesmu.compiler; +import ca.on.oicr.gsi.shesmu.compiler.definitions.ActionDefinition; import ca.on.oicr.gsi.shesmu.compiler.definitions.FunctionDefinition; import ca.on.oicr.gsi.shesmu.compiler.definitions.InputFormatDefinition; import ca.on.oicr.gsi.shesmu.plugin.types.Imyhat; @@ -7,6 +8,8 @@ import java.util.function.Consumer; public interface ExpressionCompilerServices { + ActionDefinition action(String name); + default Optional captureOptional( ExpressionNode expression, int line, int column, Consumer errorHandler) { errorHandler.accept( diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/ExpressionNodeOptionalOf.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/ExpressionNodeOptionalOf.java index 094a27988..db36073cf 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/ExpressionNodeOptionalOf.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/ExpressionNodeOptionalOf.java @@ -3,6 +3,7 @@ import static ca.on.oicr.gsi.shesmu.compiler.TypeUtils.TO_ASM; import ca.on.oicr.gsi.shesmu.compiler.Target.Flavour; +import ca.on.oicr.gsi.shesmu.compiler.definitions.ActionDefinition; import ca.on.oicr.gsi.shesmu.compiler.definitions.FunctionDefinition; import ca.on.oicr.gsi.shesmu.compiler.definitions.InputFormatDefinition; import ca.on.oicr.gsi.shesmu.plugin.types.Imyhat; @@ -49,6 +50,11 @@ public OptionalCaptureCompilerServices( this.layer = layer; } + @Override + public ActionDefinition action(String name) { + return expressionCompilerServices.action(name); + } + @Override public Optional captureOptional( ExpressionNode expression, int line, int column, Consumer errorHandler) { diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNode.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNode.java index a701a4678..a5e2ca9cf 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNode.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNode.java @@ -122,7 +122,43 @@ private interface SimulationConstructor { new InformationNodeRepeat(name, source, transforms, collectors.get())); return result; }); - + REPEAT_COLLECTOR.addKeyword( + "Run", + (input, output) -> { + final var actionName = new AtomicReference(); + final var variableTags = new AtomicReference>(); + final var arguments = new AtomicReference>(); + final var fileName = new AtomicReference(); + final var result = + input + .whitespace() + .qualifiedIdentifier(actionName::set) + .whitespace() + .list(variableTags::set, VariableTagNode::parse) + .whitespace() + .keyword("With") + .whitespace() + .list(arguments::set, OliveArgumentNode::parse, ',') + .whitespace() + .keyword("As") + .whitespace() + .then(ExpressionNode::parse, fileName::set); + if (result.isGood()) { + output.accept( + (name, source, transforms) -> + new InformationNodeActNow( + input.line(), + input.column(), + name, + source, + transforms, + actionName.get(), + variableTags.get(), + arguments.get(), + fileName.get())); + } + return result; + }); DISPATCH.addKeyword( "Alerts", (p, o) -> { diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeActNow.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeActNow.java new file mode 100644 index 000000000..9fce7567b --- /dev/null +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeActNow.java @@ -0,0 +1,196 @@ +package ca.on.oicr.gsi.shesmu.compiler; + +import ca.on.oicr.gsi.shesmu.compiler.definitions.ActionDefinition; +import ca.on.oicr.gsi.shesmu.compiler.definitions.ActionParameterDefinition; +import ca.on.oicr.gsi.shesmu.compiler.definitions.DefinitionRepository; +import ca.on.oicr.gsi.shesmu.plugin.types.Imyhat; +import ca.on.oicr.gsi.shesmu.runtime.RuntimeSupport; +import com.fasterxml.jackson.core.JsonProcessingException; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class InformationNodeActNow extends InformationNodeBaseRepeat { + private final int line; + private final int column; + private final List arguments; + private final List variableTags; + private ActionDefinition definition; + private final ExpressionNode fileName; + private final String actionName; + + public InformationNodeActNow( + int line, + int column, + DestructuredArgumentNode name, + SourceNode source, + List transforms, + String actionName, + List variableTags, + List arguments, + ExpressionNode fileName) { + super(name, source, transforms); + this.line = line; + this.column = column; + this.arguments = arguments; + this.variableTags = variableTags; + this.fileName = fileName; + this.actionName = actionName; + } + + @Override + protected String renderBlock(EcmaScriptRenderer renderer, String data) { + return String.format( + "{type: \"download\", isJson: true, mimetype: \"application/json\", contents: %s, file: (%s) + \".actnow\"}", + data, fileName.renderEcma(renderer)); + } + + @Override + public String renderRow(EcmaScriptRenderer renderer) { + try { + return String.format( + "{name: %s, parameters: {%s}, tags: [%s]}", + RuntimeSupport.MAPPER.writeValueAsString(definition.name()), + arguments.stream() + .map(argument -> argument.renderEcma(renderer)) + .collect(Collectors.joining(", ")), + variableTags.stream() + .map(tag -> tag.renderEcma(renderer)) + .collect(Collectors.joining(", "))); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + + @Override + protected boolean resolveTerminal( + NameDefinitions parentName, NameDefinitions collectorName, Consumer errorHandler) { + var ok = + arguments.stream() + .filter(collector -> collector.resolve(collectorName, errorHandler)) + .count() + == arguments.size(); + if (ok) { + + final var argumentNames = + arguments.stream() + .flatMap(OliveArgumentNode::targets) + .collect(Collectors.groupingBy(Target::name, Collectors.counting())); + for (final var entry : argumentNames.entrySet()) { + if (entry.getValue() > 1) { + errorHandler.accept( + String.format( + "%d:%d: Duplicate argument ā€œ%sā€ to action.", line, column, entry.getKey())); + ok = false; + } + } + + final var definedArgumentNames = + definition.parameters().map(ActionParameterDefinition::name).collect(Collectors.toSet()); + final var requiredArgumentNames = + definition + .parameters() + .filter(ActionParameterDefinition::required) + .map(ActionParameterDefinition::name) + .collect(Collectors.toSet()); + if (!definedArgumentNames.containsAll(argumentNames.keySet())) { + ok = false; + final Set badTerms = new HashSet<>(argumentNames.keySet()); + badTerms.removeAll(definedArgumentNames); + errorHandler.accept( + String.format( + "%d:%d: Extra arguments for action %s: %s", + line, column, actionName, String.join(", ", badTerms))); + } + switch (arguments.stream() + .map(argument -> argument.checkWildcard(errorHandler)) + .reduce(WildcardCheck.NONE, WildcardCheck::combine)) { + case NONE: + if (!argumentNames.keySet().containsAll(requiredArgumentNames)) { + ok = false; + final Set badTerms = new HashSet<>(requiredArgumentNames); + badTerms.removeAll(argumentNames.keySet()); + errorHandler.accept( + String.format( + "%d:%d: Missing arguments for action %s: %s", + line, column, actionName, String.join(", ", badTerms))); + } + break; + case HAS_WILDCARD: + final var provider = + arguments.stream() + .map(x -> (UndefinedVariableProvider) x) + .reduce(UndefinedVariableProvider.NONE, UndefinedVariableProvider::combine); + for (final var requiredName : requiredArgumentNames) { + if (!definedArgumentNames.contains(requiredName)) { + provider.handleUndefinedVariable(requiredName); + } + } + break; + case BAD: + ok = false; + break; + } + } + return ok + & variableTags.stream().filter(tag -> tag.resolve(collectorName, errorHandler)).count() + == variableTags.size() + & fileName.resolve(parentName, errorHandler); + } + + @Override + protected boolean resolveTerminalDefinitions( + ExpressionCompilerServices expressionCompilerServices, + DefinitionRepository nativeDefinitions, + Consumer errorHandler) { + definition = expressionCompilerServices.action(actionName); + if (definition == null) { + errorHandler.accept( + String.format("%d:%d: Unknown action for ā€œ%sā€.", line, column, actionName)); + } + return definition != null + & arguments.stream() + .filter(arg -> arg.resolveFunctions(expressionCompilerServices, errorHandler)) + .count() + == arguments.size() + & variableTags.stream() + .filter(tag -> tag.resolveDefinitions(expressionCompilerServices, errorHandler)) + .count() + == variableTags.size() + & fileName.resolveDefinitions(expressionCompilerServices, errorHandler); + } + + @Override + protected boolean typeCheckTerminal(Consumer errorHandler) { + var ok = fileName.typeCheck(errorHandler); + if (ok && !fileName.type().isSame(Imyhat.STRING)) { + fileName.typeError(Imyhat.STRING, fileName.type(), errorHandler); + ok = false; + } + for (final var tag : variableTags) { + if (!tag.typeCheck(errorHandler)) { + ok = false; + } + } + if (arguments.stream() + .filter( + argument -> argument.typeCheck(errorHandler) && argument.checkName(errorHandler)) + .count() + == arguments.size()) { + final var parameterInfo = + definition + .parameters() + .collect(Collectors.toMap(ActionParameterDefinition::name, Function.identity())); + return arguments.stream() + .filter(argument -> argument.checkArguments(parameterInfo::get, errorHandler)) + .count() + == arguments.size() + & ok; + } else { + return false; + } + } +} diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeBaseRepeat.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeBaseRepeat.java index 91d2f8bdf..0a91ce62e 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeBaseRepeat.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeBaseRepeat.java @@ -57,7 +57,7 @@ public final boolean resolve(NameDefinitions defs, Consumer errorHandler .map( name -> { final var collectorName = defs.replaceStream(name.targets(), true); - return resolveTerminal(collectorName, errorHandler); + return resolveTerminal(defs, collectorName, errorHandler); }) .orElse(false); return ok; @@ -79,7 +79,7 @@ & resolveTerminalDefinitions(expressionCompilerServices, nativeDefinitions, erro } protected abstract boolean resolveTerminal( - NameDefinitions collectorName, Consumer errorHandler); + NameDefinitions parentName, NameDefinitions collectorName, Consumer errorHandler); protected abstract boolean resolveTerminalDefinitions( ExpressionCompilerServices expressionCompilerServices, diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeRepeat.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeRepeat.java index f39b650c3..7fdcc3c77 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeRepeat.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeRepeat.java @@ -31,7 +31,8 @@ public String renderRow(EcmaScriptRenderer renderer) { } @Override - protected boolean resolveTerminal(NameDefinitions collectorName, Consumer errorHandler) { + protected boolean resolveTerminal( + NameDefinitions parentName, NameDefinitions collectorName, Consumer errorHandler) { return collectors.stream() .filter(collector -> collector.resolve(collectorName, errorHandler)) .count() diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeTable.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeTable.java index 66b76bb4b..5b3b798ea 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeTable.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/InformationNodeTable.java @@ -80,7 +80,8 @@ public String renderRow(EcmaScriptRenderer renderer) { } @Override - protected boolean resolveTerminal(NameDefinitions collectorName, Consumer errorHandler) { + protected boolean resolveTerminal( + NameDefinitions parentName, NameDefinitions collectorName, Consumer errorHandler) { return columns.stream() .filter(collector -> collector.resolve(collectorName, errorHandler)) .count() diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveArgumentNode.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveArgumentNode.java index 6315710c5..3825da6f4 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveArgumentNode.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveArgumentNode.java @@ -6,12 +6,15 @@ import ca.on.oicr.gsi.shesmu.compiler.definitions.ActionParameterDefinition; import ca.on.oicr.gsi.shesmu.plugin.Parser; import ca.on.oicr.gsi.shesmu.plugin.types.Imyhat; +import ca.on.oicr.gsi.shesmu.runtime.RuntimeSupport; +import com.fasterxml.jackson.core.JsonProcessingException; import java.nio.file.Path; import java.util.*; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Predicate; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.objectweb.asm.Type; import org.objectweb.asm.commons.GeneratorAdapter; @@ -22,6 +25,8 @@ public abstract class OliveArgumentNode implements UndefinedVariableProvider { private interface ArgumentStorer { void store(Renderer renderer, int action, LoadableValue value); + + String store(EcmaScriptRenderer renderer, EcmaLoadableValue value); } private static class OptionalProvided implements ArgumentStorer { @@ -60,6 +65,20 @@ public Type type() { }); renderer.methodGen().mark(end); } + + @Override + public String store(EcmaScriptRenderer renderer, EcmaLoadableValue value) { + try { + final var loadedValue = value.get(); + return String.format( + "...(%s === null ? {} : {%s: %s})", + loadedValue, + RuntimeSupport.MAPPER.writeValueAsString(parameterDefinition.name()), + loadedValue); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } } private static class Unmodified implements ArgumentStorer { @@ -73,6 +92,17 @@ private Unmodified(ActionParameterDefinition parameterDefinition) { public void store(Renderer renderer, int action, LoadableValue value) { parameterDefinition.store(renderer, action, value); } + + @Override + public String store(EcmaScriptRenderer renderer, EcmaLoadableValue value) { + try { + return String.format( + "%s: %s", + RuntimeSupport.MAPPER.writeValueAsString(parameterDefinition.name()), value.get()); + } catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } } private static final Type A_OPTIONAL_TYPE = Type.getType(Optional.class); @@ -181,17 +211,19 @@ public Optional handleUndefinedVariable(String name) { /** Generate bytecode for this argument's value */ public abstract void render(Renderer renderer, int action); + public abstract String renderEcma(EcmaScriptRenderer renderer); + /** Resolve variables in the expression of this argument */ public abstract boolean resolve(NameDefinitions defs, Consumer errorHandler); public abstract boolean resolveExtraFunctions( - OliveCompilerServices oliveCompilerServices, Consumer errorHandler); + ExpressionCompilerServices expressionCompilerServices, Consumer errorHandler); /** Resolve functions in this argument */ public final boolean resolveFunctions( - OliveCompilerServices oliveCompilerServices, Consumer errorHandler) { - return name.resolve(oliveCompilerServices, errorHandler) - & resolveExtraFunctions(oliveCompilerServices, errorHandler); + ExpressionCompilerServices expressionCompilerServices, Consumer errorHandler) { + return name.resolve(expressionCompilerServices, errorHandler) + & resolveExtraFunctions(expressionCompilerServices, errorHandler); } protected void storeAll(Renderer renderer, int action, Consumer loadValue) { @@ -202,6 +234,11 @@ protected void storeAll(Renderer renderer, int action, Consumer loadVa .forEach(value -> definitions.get(value.name()).store(renderer, action, value)); } + protected final String storeAll(EcmaScriptRenderer renderer, String input) { + return name.renderEcma(renderer.newConst(input)) + .map(value -> definitions.get(value.name()).store(renderer, value)) + .collect(Collectors.joining(", ")); + } /** The argument name */ public final Stream targets() { return name.targets(); diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveArgumentNodeOptional.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveArgumentNodeOptional.java index fcc7a0f18..aa5becb40 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveArgumentNodeOptional.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveArgumentNodeOptional.java @@ -53,6 +53,20 @@ public void render(Renderer renderer, int action) { renderer.methodGen().mark(end); } + @Override + public String renderEcma(EcmaScriptRenderer renderer) { + final var result = renderer.newLet("{}"); + renderer.conditional( + condition.renderEcma(renderer), + ecmaScriptRenderer -> + ecmaScriptRenderer.statement( + String.format( + "%s = { %s }", + result, + storeAll(ecmaScriptRenderer, expression.renderEcma(ecmaScriptRenderer))))); + return String.format("...%s", result); + } + /** Resolve variables in the expression of this argument */ @Override public boolean resolve(NameDefinitions defs, Consumer errorHandler) { @@ -62,9 +76,9 @@ public boolean resolve(NameDefinitions defs, Consumer errorHandler) { /** Resolve functions in this argument */ @Override public boolean resolveExtraFunctions( - OliveCompilerServices oliveCompilerServices, Consumer errorHandler) { - return expression.resolveDefinitions(oliveCompilerServices, errorHandler) - & condition.resolveDefinitions(oliveCompilerServices, errorHandler); + ExpressionCompilerServices expressionCompilerServices, Consumer errorHandler) { + return expression.resolveDefinitions(expressionCompilerServices, errorHandler) + & condition.resolveDefinitions(expressionCompilerServices, errorHandler); } @Override diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveArgumentNodeProvided.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveArgumentNodeProvided.java index 2d3fc46d4..2e8abff3a 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveArgumentNodeProvided.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveArgumentNodeProvided.java @@ -40,6 +40,11 @@ public void render(Renderer renderer, int action) { storeAll(renderer, action, expression::render); } + @Override + public String renderEcma(EcmaScriptRenderer renderer) { + return storeAll(renderer, expression.renderEcma(renderer)); + } + /** Resolve variables in the expression of this argument */ @Override public boolean resolve(NameDefinitions defs, Consumer errorHandler) { @@ -49,8 +54,8 @@ public boolean resolve(NameDefinitions defs, Consumer errorHandler) { /** Resolve functions in this argument */ @Override public boolean resolveExtraFunctions( - OliveCompilerServices oliveCompilerServices, Consumer errorHandler) { - return expression.resolveDefinitions(oliveCompilerServices, errorHandler); + ExpressionCompilerServices expressionCompilerServices, Consumer errorHandler) { + return expression.resolveDefinitions(expressionCompilerServices, errorHandler); } @Override diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveCompilerServices.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveCompilerServices.java index bb771668b..b720ea782 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveCompilerServices.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/OliveCompilerServices.java @@ -1,13 +1,10 @@ package ca.on.oicr.gsi.shesmu.compiler; -import ca.on.oicr.gsi.shesmu.compiler.definitions.ActionDefinition; import ca.on.oicr.gsi.shesmu.compiler.definitions.InputFormatDefinition; import ca.on.oicr.gsi.shesmu.compiler.definitions.SignatureDefinition; import java.util.stream.Stream; public interface OliveCompilerServices extends ExpressionCompilerServices, ConstantRetriever { - ActionDefinition action(String name); - boolean addMetric(String metricName); InputFormatDefinition inputFormat(String format); diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/VariableTagNode.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/VariableTagNode.java index e75b04241..cf220d57f 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/VariableTagNode.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/VariableTagNode.java @@ -59,12 +59,18 @@ public final void collectPlugins(Set pluginFileNames) { expression.collectPlugins(pluginFileNames); } + protected abstract String decorateEcma(String data); + protected final void render(Renderer renderer) { expression.render(renderer); } public abstract Optional renderDynamicSize(Renderer renderer); + public final String renderEcma(EcmaScriptRenderer renderer) { + return decorateEcma(expression.renderEcma(renderer)); + } + public abstract int renderStaticTag(Renderer renderer, int tagIndex); protected abstract Imyhat requiredType(); diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/VariableTagNodeMultiple.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/VariableTagNodeMultiple.java index 0516dbd31..459d990b1 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/VariableTagNodeMultiple.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/VariableTagNodeMultiple.java @@ -24,6 +24,11 @@ protected VariableTagNodeMultiple(ExpressionNode expression) { super(expression); } + @Override + protected String decorateEcma(String data) { + return "..." + data; + } + @Override public Optional renderDynamicSize(Renderer renderer) { render(renderer); diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/VariableTagNodeSingle.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/VariableTagNodeSingle.java index 7ce108255..b32986d5d 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/VariableTagNodeSingle.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/compiler/VariableTagNodeSingle.java @@ -18,6 +18,11 @@ public Optional renderDynamicSize(Renderer renderer) { return Optional.empty(); } + @Override + protected String decorateEcma(String data) { + return data; + } + @Override public int renderStaticTag(Renderer renderer, int tagIndex) { renderer.methodGen().dup(); diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/server/GuidedMeditation.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/server/GuidedMeditation.java index 86c66acee..fecb6fe09 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/server/GuidedMeditation.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/server/GuidedMeditation.java @@ -5,6 +5,7 @@ import ca.on.oicr.gsi.shesmu.compiler.NameDefinitions; import ca.on.oicr.gsi.shesmu.compiler.WizardDefineNode; import ca.on.oicr.gsi.shesmu.compiler.WizardNode; +import ca.on.oicr.gsi.shesmu.compiler.definitions.ActionDefinition; import ca.on.oicr.gsi.shesmu.compiler.definitions.DefinitionRepository; import ca.on.oicr.gsi.shesmu.compiler.definitions.FunctionDefinition; import ca.on.oicr.gsi.shesmu.compiler.definitions.InputFormatDefinition; @@ -75,12 +76,19 @@ public static boolean compile( final Map crossReferences = new TreeMap<>(); final var expressionCompilerServices = new ExpressionCompilerServices() { + private final NameLoader actions = + new NameLoader<>(definitionRepository.actions(), ActionDefinition::name); private final NameLoader formats = new NameLoader<>( AnnotatedInputFormatDefinition.formats(), InputFormatDefinition::name); private final NameLoader functions = new NameLoader<>(new StandardDefinitions().functions(), FunctionDefinition::name); + @Override + public ActionDefinition action(String name) { + return actions.get(name); + } + @Override public FunctionDefinition function(String name) { return functions.get(name); diff --git a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/server/plugins/BaseHumanTypeParser.java b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/server/plugins/BaseHumanTypeParser.java index 571fc6422..5db22857e 100644 --- a/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/server/plugins/BaseHumanTypeParser.java +++ b/shesmu-server/src/main/java/ca/on/oicr/gsi/shesmu/server/plugins/BaseHumanTypeParser.java @@ -33,9 +33,16 @@ public final Imyhat parse(String input) { return node.get() .render( new ExpressionCompilerServices() { + private final NameLoader actions = + new NameLoader<>(definitionRepository.actions(), ActionDefinition::name); private final NameLoader functions = new NameLoader<>(definitionRepository.functions(), FunctionDefinition::name); + @Override + public ActionDefinition action(String name) { + return actions.get(name); + } + @Override public FunctionDefinition function(String name) { return functions.get(name);