From 2b9fb976482d85f06532eb0dd2ac5003c8342885 Mon Sep 17 00:00:00 2001 From: Riccardo Azzolini Date: Fri, 9 Aug 2019 20:51:31 +0200 Subject: [PATCH] Make DSL rule loading work on TeaVM --- .../java/it/cavallium/warppi/Platform.java | 10 ++- .../warppi/math/rules/RulesManager.java | 57 +++++++--------- .../dsl/errorutils/DslFilesException.java | 11 ++-- .../math/rules/dsl/errorutils/FileErrors.java | 17 +++-- .../dsl/errorutils/FilesErrorsFormatter.java | 9 ++- .../warppi/desktop/DesktopPlatform.java | 16 ++++- .../warppi/hardware/HardwarePlatform.java | 17 ++++- .../cavallium/warppi/teavm/TeaVMPlatform.java | 66 +++++-------------- 8 files changed, 94 insertions(+), 109 deletions(-) diff --git a/core/src/main/java/it/cavallium/warppi/Platform.java b/core/src/main/java/it/cavallium/warppi/Platform.java index 33e0ac8c..0644b554 100644 --- a/core/src/main/java/it/cavallium/warppi/Platform.java +++ b/core/src/main/java/it/cavallium/warppi/Platform.java @@ -60,7 +60,15 @@ public interface Platform { String[] stacktraceToString(Error e); - void loadPlatformRules(); + /** + * Determines the list of files containing DSL rules to load. + * + * @return a List of paths of files which contain DSL rules. + * Each String in the returned List can be passed as an argument to + * {@link StorageUtils#getResourceStream(String)} to access the corresponding file's contents. + * @throws IOException if an IO error occurs while getting the list of rule file paths. + */ + List getRuleFilePaths() throws IOException; void zip(String targetPath, String destinationFilePath, String password); diff --git a/core/src/main/java/it/cavallium/warppi/math/rules/RulesManager.java b/core/src/main/java/it/cavallium/warppi/math/rules/RulesManager.java index ab8ce069..a444b7de 100644 --- a/core/src/main/java/it/cavallium/warppi/math/rules/RulesManager.java +++ b/core/src/main/java/it/cavallium/warppi/math/rules/RulesManager.java @@ -1,13 +1,8 @@ package it.cavallium.warppi.math.rules; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.util.stream.Stream; - import it.cavallium.warppi.Engine; +import it.cavallium.warppi.Platform; import it.cavallium.warppi.Platform.ConsoleUtils; -import it.cavallium.warppi.Platform.StorageUtils; import it.cavallium.warppi.math.Function; import it.cavallium.warppi.math.MathContext; import it.cavallium.warppi.math.functions.Expression; @@ -21,6 +16,10 @@ import it.cavallium.warppi.math.solver.MathSolver; import it.cavallium.warppi.util.Error; import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import java.io.IOException; +import java.io.InputStream; +import java.util.stream.Stream; + public class RulesManager { public static ObjectArrayList[] rules; @@ -37,18 +36,14 @@ public class RulesManager { loadBuiltinRules(); - if (Engine.getPlatform().isJavascript()) { - Engine.getPlatform().loadPlatformRules(); - } else { - try { - loadDslRules(); - } catch (IOException | DslFilesException e) { - e.printStackTrace(); - if (e instanceof DslFilesException) { - System.err.print(((DslFilesException) e).format()); - } - Engine.getPlatform().exit(1); + try { + loadDslRules(); + } catch (IOException | DslFilesException e) { + e.printStackTrace(); + if (e instanceof DslFilesException) { + System.err.print(((DslFilesException) e).format()); } + Engine.getPlatform().exit(1); } } @@ -71,33 +66,29 @@ public class RulesManager { } private static void loadDslRules() throws IOException, DslFilesException { - final StorageUtils storageUtils = Engine.getPlatform().getStorageUtils(); - final File dslRulesPath = storageUtils.get("rules/dsl/"); - if (!dslRulesPath.exists()) { - return; - } + final Platform platform = Engine.getPlatform(); final DslFilesException fileErrors = new DslFilesException(); - for (final File file : storageUtils.walk(dslRulesPath)) { - if (!file.toString().endsWith(".rules")) { - continue; - } - - Engine.getPlatform().getConsoleUtils().out().println( + for (final String path : platform.getRuleFilePaths()) { + platform.getConsoleUtils().out().println( ConsoleUtils.OUTPUTLEVEL_NODEBUG, "RulesManager", - "Found DSL rules file: " + file.getAbsolutePath() + "Found DSL rules file: " + path ); final String source; - try (final InputStream resource = storageUtils.getResourceStream(file.toString())) { - source = storageUtils.read(resource); + try (final InputStream resource = platform.getStorageUtils().getResourceStream(path)) { + source = platform.getStorageUtils().read(resource); } try { - RulesDsl.makeRules(source).forEach(RulesManager::addRule); + // This loop used to be written as RulesDsl.makeRules(source).forEach(RulesManager::addRule), + // but the forEach method hangs on TeaVM. + for (Rule rule : RulesDsl.makeRules(source)) { + addRule(rule); + } } catch (DslAggregateException e) { - fileErrors.addFileErrors(file, source, e.getErrors()); + fileErrors.addFileErrors(path, source, e.getErrors()); } } diff --git a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/errorutils/DslFilesException.java b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/errorutils/DslFilesException.java index d0325281..ef5329fc 100644 --- a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/errorutils/DslFilesException.java +++ b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/errorutils/DslFilesException.java @@ -2,7 +2,6 @@ package it.cavallium.warppi.math.rules.dsl.errorutils; import it.cavallium.warppi.math.rules.dsl.DslError; -import java.io.File; import java.util.ArrayList; import java.util.List; @@ -15,13 +14,13 @@ public class DslFilesException extends Exception { /** * Registers errors which have been found in the specified DSL source file. * - * @param file The path of the DSL source file in which the errors occurred. - * @param source The entire contents of the DSL source file in which the errors occurred. - * @param errors The (non-empty) list of errors found in the DSL source file. + * @param filePath The path of the DSL source file in which the errors occurred. + * @param source The entire contents of the DSL source file in which the errors occurred. + * @param errors The (non-empty) list of errors found in the DSL source file. * @throws IllegalArgumentException If the list of errors is empty. */ - public void addFileErrors(final File file, final String source, final List errors) { - filesErrors.add(new FileErrors(file, source, errors)); + public void addFileErrors(final String filePath, final String source, final List errors) { + filesErrors.add(new FileErrors(filePath, source, errors)); } /** diff --git a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/errorutils/FileErrors.java b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/errorutils/FileErrors.java index f06a5e13..3b6a07fe 100644 --- a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/errorutils/FileErrors.java +++ b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/errorutils/FileErrors.java @@ -2,7 +2,6 @@ package it.cavallium.warppi.math.rules.dsl.errorutils; import it.cavallium.warppi.math.rules.dsl.DslError; -import java.io.File; import java.util.List; /** @@ -11,23 +10,23 @@ import java.util.List; * Also stores the file's path and contents (for error reporting). */ public class FileErrors { - private final File file; + private final String filePath; private final String source; private final List errors; /** * Constructs a FileErrors instance with the given file and error data. * - * @param file The path of the DSL source file in which the errors occurred. - * @param source The entire contents of the DSL source file in which the errors occurred. - * @param errors The (non-empty) list of errors found in the DSL source file. + * @param filePath The path of the DSL source file in which the errors occurred. + * @param source The entire contents of the DSL source file in which the errors occurred. + * @param errors The (non-empty) list of errors found in the DSL source file. * @throws IllegalArgumentException If the list of errors is empty. */ - public FileErrors(final File file, final String source, final List errors) { + public FileErrors(final String filePath, final String source, final List errors) { if (errors.isEmpty()) { throw new IllegalArgumentException("The list of errors can't be empty"); } - this.file = file; + this.filePath = filePath; this.source = source; this.errors = errors; } @@ -35,8 +34,8 @@ public class FileErrors { /** * @return The path of the DSL source file in which the errors occurred. */ - public File getFile() { - return file; + public String getFilePath() { + return filePath; } /** diff --git a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/errorutils/FilesErrorsFormatter.java b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/errorutils/FilesErrorsFormatter.java index 74bf46f9..129d6fd8 100644 --- a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/errorutils/FilesErrorsFormatter.java +++ b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/errorutils/FilesErrorsFormatter.java @@ -3,7 +3,6 @@ package it.cavallium.warppi.math.rules.dsl.errorutils; import it.cavallium.warppi.math.rules.dsl.DslError; import org.apache.commons.lang3.StringUtils; -import java.io.File; import java.util.Comparator; import java.util.List; import java.util.stream.Collectors; @@ -26,7 +25,7 @@ public class FilesErrorsFormatter { */ public String format(final List filesErrors) { return filesErrors.stream() - .sorted(Comparator.comparing(FileErrors::getFile)) + .sorted(Comparator.comparing(FileErrors::getFilePath)) .flatMap(this::formatFileErrors) .collect(Collectors.joining(System.lineSeparator())); } @@ -35,17 +34,17 @@ public class FilesErrorsFormatter { final LineMap lines = new LineMap(fileErrors.getSource()); return fileErrors.getErrors().stream() .sorted(Comparator.comparing(DslError::getPosition).thenComparing(DslError::getLength)) - .map(error -> formatError(fileErrors.getFile(), lines, error)); + .map(error -> formatError(fileErrors.getFilePath(), lines, error)); } - private String formatError(final File file, final LineMap lines, final DslError error) { + private String formatError(final String filePath, final LineMap lines, final DslError error) { final StringBuilder builder = new StringBuilder(); final List spannedLines = lines.getSpannedLines(error.getPosition(), error.getLength()); final LineMap.Line firstLine = spannedLines.get(0); final int column = error.getPosition() - firstLine.getStartPosition() + 1; - builder.append(file.toString()).append(":") + builder.append(filePath).append(":") .append(firstLine.getNumber()).append(":") .append(column).append(":") .append(System.lineSeparator()); diff --git a/desktop/src/main/java/it/cavallium/warppi/desktop/DesktopPlatform.java b/desktop/src/main/java/it/cavallium/warppi/desktop/DesktopPlatform.java index d0046fcd..94639c68 100644 --- a/desktop/src/main/java/it/cavallium/warppi/desktop/DesktopPlatform.java +++ b/desktop/src/main/java/it/cavallium/warppi/desktop/DesktopPlatform.java @@ -5,7 +5,9 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.net.URL; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.apache.commons.io.FileUtils; @@ -157,8 +159,18 @@ public class DesktopPlatform implements Platform { } @Override - public void loadPlatformRules() { - + public List getRuleFilePaths() throws IOException { + final File dslRulesPath = getStorageUtils().get("rules/dsl/"); + List paths = new ArrayList<>(); + if (dslRulesPath.exists()) { + for (final File file : getStorageUtils().walk(dslRulesPath)) { + final String path = file.toString(); + if (path.endsWith(".rules")) { + paths.add(path); + } + } + } + return paths; } @Override diff --git a/hardware/src/main/java/it/cavallium/warppi/hardware/HardwarePlatform.java b/hardware/src/main/java/it/cavallium/warppi/hardware/HardwarePlatform.java index 275d65e4..c2b5c470 100644 --- a/hardware/src/main/java/it/cavallium/warppi/hardware/HardwarePlatform.java +++ b/hardware/src/main/java/it/cavallium/warppi/hardware/HardwarePlatform.java @@ -1,10 +1,13 @@ package it.cavallium.warppi.hardware; import java.io.File; +import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.net.URL; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import it.cavallium.warppi.Platform; @@ -146,8 +149,18 @@ public class HardwarePlatform implements Platform { } @Override - public void loadPlatformRules() { - + public List getRuleFilePaths() throws IOException { + final File dslRulesPath = getStorageUtils().get("rules/dsl/"); + List paths = new ArrayList<>(); + if (dslRulesPath.exists()) { + for (final File file : getStorageUtils().walk(dslRulesPath)) { + final String path = file.toString(); + if (path.endsWith(".rules")) { + paths.add(path); + } + } + } + return paths; } @Override diff --git a/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMPlatform.java b/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMPlatform.java index cee0ecc9..2b28dbff 100644 --- a/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMPlatform.java +++ b/teavm/src/main/java/it/cavallium/warppi/teavm/TeaVMPlatform.java @@ -1,7 +1,10 @@ package it.cavallium.warppi.teavm; +import java.io.IOException; +import java.io.InputStream; import java.net.URL; import java.util.HashMap; +import java.util.List; import java.util.Map; import org.teavm.jso.browser.Window; @@ -10,7 +13,6 @@ import org.teavm.jso.dom.html.HTMLDocument; import it.cavallium.warppi.Platform; import it.cavallium.warppi.gui.graphicengine.GraphicEngine; import it.cavallium.warppi.gui.graphicengine.html.HtmlEngine; -import it.cavallium.warppi.math.rules.RulesManager; import it.cavallium.warppi.util.Error; public class TeaVMPlatform implements Platform { @@ -140,57 +142,19 @@ public class TeaVMPlatform implements Platform { return e.getMessage().toUpperCase().replace("\r", "").split("\n"); } + /** + * Fetches the list of resource files containing DSL rules to load from the /rules.list resource on the server. + *

+ * The /rules.list resource must exist and be a text file with zero or more lines. + * Each line specifies the name of another resource containing DSL source code. + * Blank lines aren't allowed, and resource names are interpreted exactly as written (without stripping + * leading/trailing spaces, etc.) + */ @Override - public void loadPlatformRules() { - RulesManager.addRule(new rules.functions.DivisionRule()); - RulesManager.addRule(new rules.functions.EmptyNumberRule()); - RulesManager.addRule(new rules.functions.ExpressionRule()); - RulesManager.addRule(new rules.functions.JokeRule()); - RulesManager.addRule(new rules.functions.MultiplicationRule()); - RulesManager.addRule(new rules.functions.NegativeRule()); - RulesManager.addRule(new rules.functions.NumberRule()); - RulesManager.addRule(new rules.functions.PowerRule()); - RulesManager.addRule(new rules.functions.RootRule()); - RulesManager.addRule(new rules.functions.SubtractionRule()); - RulesManager.addRule(new rules.functions.SumRule()); - RulesManager.addRule(new rules.functions.SumSubtractionRule()); - RulesManager.addRule(new rules.functions.VariableRule()); - RulesManager.addRule(new rules.ExpandRule1()); - RulesManager.addRule(new rules.ExpandRule2()); - RulesManager.addRule(new rules.ExpandRule5()); - RulesManager.addRule(new rules.ExponentRule1()); - RulesManager.addRule(new rules.ExponentRule2()); - RulesManager.addRule(new rules.ExponentRule3()); - RulesManager.addRule(new rules.ExponentRule4()); - RulesManager.addRule(new rules.ExponentRule8()); - RulesManager.addRule(new rules.ExponentRule9()); - RulesManager.addRule(new rules.ExponentRule15()); - RulesManager.addRule(new rules.ExponentRule16()); - RulesManager.addRule(new rules.ExponentRule17()); - RulesManager.addRule(new rules.FractionsRule1()); - RulesManager.addRule(new rules.FractionsRule2()); - RulesManager.addRule(new rules.FractionsRule3()); - RulesManager.addRule(new rules.FractionsRule4()); - RulesManager.addRule(new rules.FractionsRule5()); - RulesManager.addRule(new rules.FractionsRule6()); - RulesManager.addRule(new rules.FractionsRule7()); - RulesManager.addRule(new rules.FractionsRule8()); - RulesManager.addRule(new rules.FractionsRule9()); - RulesManager.addRule(new rules.FractionsRule10()); - RulesManager.addRule(new rules.FractionsRule11()); - RulesManager.addRule(new rules.FractionsRule12()); - RulesManager.addRule(new rules.FractionsRule14()); - RulesManager.addRule(new rules.NumberRule1()); - RulesManager.addRule(new rules.NumberRule2()); - RulesManager.addRule(new rules.NumberRule3()); - RulesManager.addRule(new rules.NumberRule4()); - RulesManager.addRule(new rules.NumberRule5()); - RulesManager.addRule(new rules.NumberRule7()); - RulesManager.addRule(new rules.UndefinedRule1()); - RulesManager.addRule(new rules.UndefinedRule2()); - RulesManager.addRule(new rules.VariableRule1()); - RulesManager.addRule(new rules.VariableRule2()); - RulesManager.addRule(new rules.VariableRule3()); + public List getRuleFilePaths() throws IOException { + try (final InputStream listStream = getStorageUtils().getResourceStream("/rules.list")) { + return getStorageUtils().readAllLines(listStream); + } } @Override