diff --git a/action-lang/src/main/java/me/retrodaredevil/action/lang/ActionLangUtil.java b/action-lang/src/main/java/me/retrodaredevil/action/lang/ActionLangUtil.java index ffb7b577..3aea8cef 100644 --- a/action-lang/src/main/java/me/retrodaredevil/action/lang/ActionLangUtil.java +++ b/action-lang/src/main/java/me/retrodaredevil/action/lang/ActionLangUtil.java @@ -41,6 +41,8 @@ public final class ActionLangUtil { // expressions configMap.put("const", builder.copy().args("value").build()); configMap.put("str", builder.copy().linkedNode("expression").build()); + configMap.put("eq", builder.copy().args("lhs", "rhs").build()); + configMap.put("not", builder.copy().linkedNode("expression").build()); configMap.put("ref", builder.copy().args("name").build()); configMap.put("eval", builder.copy().args("name").build()); configMap.put("join", builder.copy().linkedNode("expression").build()); diff --git a/action-node/src/main/java/me/retrodaredevil/action/node/expression/EqualsExpression.java b/action-node/src/main/java/me/retrodaredevil/action/node/expression/EqualsExpression.java new file mode 100644 index 00000000..524e3d87 --- /dev/null +++ b/action-node/src/main/java/me/retrodaredevil/action/node/expression/EqualsExpression.java @@ -0,0 +1,30 @@ +package me.retrodaredevil.action.node.expression; + +import me.retrodaredevil.action.node.expression.result.BooleanExpressionResult; +import me.retrodaredevil.action.node.expression.result.ExpressionResult; + +import java.util.ArrayList; +import java.util.List; + +public class EqualsExpression implements BooleanExpression { + private final Expression lhs; + private final Expression rhs; + + public EqualsExpression(Expression lhs, Expression rhs) { + this.lhs = lhs; + this.rhs = rhs; + } + + @Override + public List evaluate() { + List leftResultList = lhs.evaluate(); + List rightResultList = rhs.evaluate(); + List resultList = new ArrayList<>(); + for (ExpressionResult leftResult : leftResultList) { + for (ExpressionResult rightResult : rightResultList) { + resultList.add(BooleanExpressionResult.get(leftResult.equals(rightResult))); + } + } + return resultList; + } +} diff --git a/action-node/src/main/java/me/retrodaredevil/action/node/expression/ExpressionConvert.java b/action-node/src/main/java/me/retrodaredevil/action/node/expression/ExpressionConvert.java index 9f57316c..9451dea5 100644 --- a/action-node/src/main/java/me/retrodaredevil/action/node/expression/ExpressionConvert.java +++ b/action-node/src/main/java/me/retrodaredevil/action/node/expression/ExpressionConvert.java @@ -17,6 +17,7 @@ public static List convertTo(List evaluate() { + List results = ExpressionConvert.convertTo(expression.evaluate(), BooleanExpressionResult.class); + // TODO use unmodifiable list + return results.stream() + .map(BooleanExpressionResult::not) + .collect(Collectors.toList()); + } +} diff --git a/action-node/src/main/java/me/retrodaredevil/action/node/expression/node/EqualsExpressionNode.java b/action-node/src/main/java/me/retrodaredevil/action/node/expression/node/EqualsExpressionNode.java new file mode 100644 index 00000000..991123ff --- /dev/null +++ b/action-node/src/main/java/me/retrodaredevil/action/node/expression/node/EqualsExpressionNode.java @@ -0,0 +1,32 @@ +package me.retrodaredevil.action.node.expression.node; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeName; +import me.retrodaredevil.action.node.environment.ActionEnvironment; +import me.retrodaredevil.action.node.expression.EqualsExpression; +import me.retrodaredevil.action.node.expression.Expression; + +import static java.util.Objects.requireNonNull; + +@JsonTypeName("eq") +public class EqualsExpressionNode implements ExpressionNode { + private final ExpressionNode lhs; + private final ExpressionNode rhs; + + @JsonCreator + public EqualsExpressionNode( + @JsonProperty(value = "lhs", required = true) ExpressionNode lhs, + @JsonProperty(value = "rhs", required = true) ExpressionNode rhs) { + this.lhs = requireNonNull(lhs); + this.rhs = requireNonNull(rhs); + } + + @Override + public Expression createExpression(ActionEnvironment actionEnvironment) { + return new EqualsExpression( + lhs.createExpression(actionEnvironment), + rhs.createExpression(actionEnvironment) + ); + } +} diff --git a/action-node/src/main/java/me/retrodaredevil/action/node/expression/node/ExpressionNode.java b/action-node/src/main/java/me/retrodaredevil/action/node/expression/node/ExpressionNode.java index 30ab6b22..11aa2746 100644 --- a/action-node/src/main/java/me/retrodaredevil/action/node/expression/node/ExpressionNode.java +++ b/action-node/src/main/java/me/retrodaredevil/action/node/expression/node/ExpressionNode.java @@ -7,6 +7,8 @@ @JsonSubTypes({ @JsonSubTypes.Type(ComparisonExpressionNode.class), + @JsonSubTypes.Type(EqualsExpressionNode.class), + @JsonSubTypes.Type(NotExpressionNode.class), @JsonSubTypes.Type(ConstantExpressionNode.class), @JsonSubTypes.Type(VariableReferenceExpressionNode.class), @JsonSubTypes.Type(ToStringExpressionNode.class), diff --git a/action-node/src/main/java/me/retrodaredevil/action/node/expression/node/NotExpressionNode.java b/action-node/src/main/java/me/retrodaredevil/action/node/expression/node/NotExpressionNode.java new file mode 100644 index 00000000..39c2623b --- /dev/null +++ b/action-node/src/main/java/me/retrodaredevil/action/node/expression/node/NotExpressionNode.java @@ -0,0 +1,26 @@ +package me.retrodaredevil.action.node.expression.node; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonTypeName; +import me.retrodaredevil.action.node.environment.ActionEnvironment; +import me.retrodaredevil.action.node.expression.Expression; +import me.retrodaredevil.action.node.expression.NotExpression; + +import static java.util.Objects.requireNonNull; + +@JsonTypeName("not") +public class NotExpressionNode implements ExpressionNode { + private final ExpressionNode expressionNode; + + @JsonCreator + public NotExpressionNode( + @JsonProperty(value = "expression", required = true) ExpressionNode expressionNode) { + this.expressionNode = requireNonNull(expressionNode); + } + + @Override + public Expression createExpression(ActionEnvironment actionEnvironment) { + return new NotExpression(expressionNode.createExpression(actionEnvironment)); + } +} diff --git a/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/BooleanExpressionResult.java b/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/BooleanExpressionResult.java index f4eda82a..b1d3a7c7 100644 --- a/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/BooleanExpressionResult.java +++ b/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/BooleanExpressionResult.java @@ -14,6 +14,10 @@ public boolean getBoolean() { return value; } + public BooleanExpressionResult not() { + return this == TRUE ? FALSE : TRUE; + } + public static BooleanExpressionResult get(boolean result) { return result ? TRUE : FALSE; } diff --git a/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/ExpressionResult.java b/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/ExpressionResult.java index fa88d106..a601b0f2 100644 --- a/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/ExpressionResult.java +++ b/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/ExpressionResult.java @@ -1,4 +1,6 @@ package me.retrodaredevil.action.node.expression.result; public interface ExpressionResult { + @Override + boolean equals(Object other); } diff --git a/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/NumericExpressionResult.java b/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/NumericExpressionResult.java index b2a00325..704b0bb9 100644 --- a/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/NumericExpressionResult.java +++ b/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/NumericExpressionResult.java @@ -2,11 +2,15 @@ import org.jetbrains.annotations.NotNull; +/** + * A {@link NumericExpressionResult} contains a {@link Number} of any implementation. + * Equality is determined by comparing the equality of the {@link Number#doubleValue()} + */ public interface NumericExpressionResult extends ExpressionResult, Comparable { Number getNumber(); static NumericExpressionResult create(Number number) { - return () -> number; + return new SimpleNumericExpressionResult(number); } @Override diff --git a/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/SimpleNumericExpressionResult.java b/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/SimpleNumericExpressionResult.java new file mode 100644 index 00000000..a8a5d70e --- /dev/null +++ b/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/SimpleNumericExpressionResult.java @@ -0,0 +1,32 @@ +package me.retrodaredevil.action.node.expression.result; + +import java.util.Objects; + +import static java.util.Objects.requireNonNull; + +final class SimpleNumericExpressionResult implements NumericExpressionResult { + private final Number number; + + SimpleNumericExpressionResult(Number number) { + this.number = requireNonNull(number); + } + + @Override + public Number getNumber() { + return number; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof NumericExpressionResult)) return false; + NumericExpressionResult that = (NumericExpressionResult) o; + Number thatNumber = that.getNumber(); + return number.equals(thatNumber) || number.doubleValue() == thatNumber.doubleValue(); + } + + @Override + public int hashCode() { + return Objects.hashCode(number.doubleValue()); + } +} diff --git a/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/StringExpressionResult.java b/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/StringExpressionResult.java index 6e448dab..7b7fb7f0 100644 --- a/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/StringExpressionResult.java +++ b/action-node/src/main/java/me/retrodaredevil/action/node/expression/result/StringExpressionResult.java @@ -1,5 +1,7 @@ package me.retrodaredevil.action.node.expression.result; +import java.util.Objects; + import static java.util.Objects.requireNonNull; public final class StringExpressionResult implements ExpressionResult { @@ -12,4 +14,17 @@ public StringExpressionResult(String value) { public String getString() { return value; } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof StringExpressionResult)) return false; + StringExpressionResult that = (StringExpressionResult) o; + return value.equals(that.value); + } + + @Override + public int hashCode() { + return Objects.hashCode(value); + } } diff --git a/client/src/main/java/me/retrodaredevil/solarthing/actions/rover/RoverBoostVoltageActionNode.java b/client/src/main/java/me/retrodaredevil/solarthing/actions/rover/RoverBoostVoltageActionNode.java index cf4531ec..93aeff45 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/actions/rover/RoverBoostVoltageActionNode.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/actions/rover/RoverBoostVoltageActionNode.java @@ -11,7 +11,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -@Deprecated +@Deprecated(forRemoval = true) @JsonTypeName("roverboostvoltage") public class RoverBoostVoltageActionNode implements ActionNode { private static final Logger LOGGER = LoggerFactory.getLogger(RoverBoostVoltageActionNode.class); diff --git a/client/src/main/java/me/retrodaredevil/solarthing/program/ActionUtil.java b/client/src/main/java/me/retrodaredevil/solarthing/program/ActionUtil.java index 9985a46d..7a78e300 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/program/ActionUtil.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/program/ActionUtil.java @@ -14,7 +14,6 @@ import me.retrodaredevil.solarthing.actions.message.MessageSenderActionNode; import me.retrodaredevil.solarthing.actions.message.SendMessageActionNode; import me.retrodaredevil.solarthing.actions.rover.RoverBoostSetActionNode; -import me.retrodaredevil.solarthing.actions.rover.RoverBoostVoltageActionNode; import me.retrodaredevil.solarthing.actions.rover.RoverLoadActionNode; import me.retrodaredevil.solarthing.actions.rover.modbus.RoverModbusActionNode; import me.retrodaredevil.solarthing.actions.solcast.SolcastActionNode; @@ -51,7 +50,8 @@ public static ObjectMapper registerActionNodes(ObjectMapper objectMapper) { RoverModbusActionNode.class, RoverLoadActionNode.class, RoverBoostSetActionNode.class, - RoverBoostVoltageActionNode.class, + // RoverBoostVoltageActionNode commented out until we confirm that replacing it works as intended +// RoverBoostVoltageActionNode.class, TracerModbusActionNode.class, TracerLoadActionNode.class, diff --git a/client/src/main/java/me/retrodaredevil/solarthing/program/subprogram/analyze/analyzers/generator/entry/GeneratorFXStatistics.java b/client/src/main/java/me/retrodaredevil/solarthing/program/subprogram/analyze/analyzers/generator/entry/GeneratorFXStatistics.java index f2f09a5b..7a36f37b 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/program/subprogram/analyze/analyzers/generator/entry/GeneratorFXStatistics.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/program/subprogram/analyze/analyzers/generator/entry/GeneratorFXStatistics.java @@ -10,9 +10,9 @@ * some properties may not be useful. * Usually many of these properties become more useful for the shorter periods of time that are focused on. * - * @param identifier - * @param averageChargerWattage - * @param averageBuyWattage + * @param identifier TODO + * @param averageChargerWattage TODO + * @param averageBuyWattage TODO * @deprecated Not yet implemented */ @Deprecated diff --git a/client/src/main/java/me/retrodaredevil/solarthing/program/subprogram/run/RequestMain.java b/client/src/main/java/me/retrodaredevil/solarthing/program/subprogram/run/RequestMain.java index 03cc6786..34e61e3e 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/program/subprogram/run/RequestMain.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/program/subprogram/run/RequestMain.java @@ -34,10 +34,10 @@ public class RequestMain { public static int startRequestProgram(RequestProgramOptions options, boolean isValidate) throws Exception { LOGGER.info(SolarThingConstants.SUMMARY_MARKER, "Beginning request program"); AnalyticsManager analyticsManager = new AnalyticsManager(options.isAnalyticsEnabled()); - return startRequestProgram(options, analyticsManager, options.getPeriod(), options.getMinimumWait(), isValidate); + return startRequestProgram(options, isValidate, analyticsManager, options.getPeriod(), options.getMinimumWait()); } - private static int startRequestProgram(RequestProgramOptions options, AnalyticsManager analyticsManager, Duration period, Duration minimumWait, boolean isValidate) throws Exception { + private static int startRequestProgram(RequestProgramOptions options, boolean isValidate, AnalyticsManager analyticsManager, Duration period, Duration minimumWait) throws Exception { // Note this is very similar to code in OutbackMateMain and could eventually be refactored EnvironmentUpdater[] environmentUpdaterReference = new EnvironmentUpdater[1]; PacketHandlerInit.Result handlersResult = PacketHandlerInit.initHandlers( diff --git a/client/src/main/java/me/retrodaredevil/solarthing/program/subprogram/run/couchdb/CustomWmfCouchDbEdit20240318.java b/client/src/main/java/me/retrodaredevil/solarthing/program/subprogram/run/couchdb/CustomWmfCouchDbEdit20240318.java index a36e4a1c..b3908e00 100644 --- a/client/src/main/java/me/retrodaredevil/solarthing/program/subprogram/run/couchdb/CustomWmfCouchDbEdit20240318.java +++ b/client/src/main/java/me/retrodaredevil/solarthing/program/subprogram/run/couchdb/CustomWmfCouchDbEdit20240318.java @@ -41,6 +41,7 @@ public class CustomWmfCouchDbEdit20240318 { ); private final CouchDbInstance instance; private final PrintStream out; + @SuppressWarnings("FieldCanBeLocal") // we suppress this warning because this class should probably be removed at some point private final CouchDbSetupMain.Prompt prompt; public CustomWmfCouchDbEdit20240318(CouchDbInstance instance, PrintStream out, CouchDbSetupMain.Prompt prompt) { diff --git a/config_templates/actions-ns/equality_test.ns b/config_templates/actions-ns/equality_test.ns new file mode 100644 index 00000000..893d6d4c --- /dev/null +++ b/config_templates/actions-ns/equality_test.ns @@ -0,0 +1,21 @@ +queue { + race { + racer(all : eq(const(5), const(5.0))) : print("5 = 5.0!") + racer(pass) : print("This should not happen!") + } + race { + racer(all : eq(const(4), const(5.0))) : print("4 = 5.0! (bad)") + racer(all : not : eq(const(4), const(5.0))) : print("4 != 5.0!") + racer(pass) : print("This should not happen!") + } + + race { + racer(all : eq(const("hello"), const hello)) : print("hello = hello") + racer(pass) : print("This should not happen!") + } + race { + racer(all : eq(const("Hello"), const hello)) : print("Hello = hello (bad)") + racer(all : not : eq(const("Hello"), const hello)) : print("Hello != hello") + racer(pass) : print("This should not happen!") + } +}