Make DSL rule loading work on TeaVM

This commit is contained in:
Riccardo Azzolini 2019-08-09 20:51:31 +02:00
parent e5b64ce218
commit 2b9fb97648
8 changed files with 94 additions and 109 deletions

View File

@ -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 <code>List</code> of paths of files which contain DSL rules.
* Each <code>String</code> in the returned <code>List</code> 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<String> getRuleFilePaths() throws IOException;
void zip(String targetPath, String destinationFilePath, String password);

View File

@ -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<Rule>[] 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());
}
}

View File

@ -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<DslError> errors) {
filesErrors.add(new FileErrors(file, source, errors));
public void addFileErrors(final String filePath, final String source, final List<DslError> errors) {
filesErrors.add(new FileErrors(filePath, source, errors));
}
/**

View File

@ -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<DslError> errors;
/**
* Constructs a <code>FileErrors</code> 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<DslError> errors) {
public FileErrors(final String filePath, final String source, final List<DslError> 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;
}
/**

View File

@ -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<FileErrors> 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<LineMap.Line> 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());

View File

@ -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<String> getRuleFilePaths() throws IOException {
final File dslRulesPath = getStorageUtils().get("rules/dsl/");
List<String> 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

View File

@ -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<String> getRuleFilePaths() throws IOException {
final File dslRulesPath = getStorageUtils().get("rules/dsl/");
List<String> 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

View File

@ -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 <code>/rules.list</code> resource on the server.
* <p>
* The <code>/rules.list</code> 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<String> getRuleFilePaths() throws IOException {
try (final InputStream listStream = getStorageUtils().getResourceStream("/rules.list")) {
return getStorageUtils().readAllLines(listStream);
}
}
@Override