diff options
author | Kristóf Marussy <kristof@marussy.com> | 2023-12-24 19:42:21 +0100 |
---|---|---|
committer | Kristóf Marussy <kristof@marussy.com> | 2023-12-25 00:04:37 +0100 |
commit | 1f9b4652b1f85fc9f2cefcd46b34431ecea5c381 (patch) | |
tree | 84aba7f8ce90ff5aea38c912b3999ec7810f6f44 /subprojects/generator-cli | |
parent | feat: command line model generator (diff) | |
download | refinery-1f9b4652b1f85fc9f2cefcd46b34431ecea5c381.tar.gz refinery-1f9b4652b1f85fc9f2cefcd46b34431ecea5c381.tar.zst refinery-1f9b4652b1f85fc9f2cefcd46b34431ecea5c381.zip |
refactor(generator): scope overrides
Diffstat (limited to 'subprojects/generator-cli')
-rw-r--r-- | subprojects/generator-cli/src/main/java/tools/refinery/generator/cli/commands/GenerateCommand.java | 72 |
1 files changed, 9 insertions, 63 deletions
diff --git a/subprojects/generator-cli/src/main/java/tools/refinery/generator/cli/commands/GenerateCommand.java b/subprojects/generator-cli/src/main/java/tools/refinery/generator/cli/commands/GenerateCommand.java index 6c1d105d..b33fce23 100644 --- a/subprojects/generator-cli/src/main/java/tools/refinery/generator/cli/commands/GenerateCommand.java +++ b/subprojects/generator-cli/src/main/java/tools/refinery/generator/cli/commands/GenerateCommand.java | |||
@@ -11,16 +11,10 @@ import com.google.inject.Inject; | |||
11 | import org.eclipse.emf.ecore.resource.Resource; | 11 | import org.eclipse.emf.ecore.resource.Resource; |
12 | import tools.refinery.generator.ModelGeneratorFactory; | 12 | import tools.refinery.generator.ModelGeneratorFactory; |
13 | import tools.refinery.generator.ProblemLoader; | 13 | import tools.refinery.generator.ProblemLoader; |
14 | import tools.refinery.language.model.problem.Problem; | ||
15 | import tools.refinery.language.model.problem.Relation; | ||
16 | import tools.refinery.language.model.problem.ScopeDeclaration; | ||
17 | 14 | ||
18 | import java.io.ByteArrayOutputStream; | ||
19 | import java.io.FileOutputStream; | 15 | import java.io.FileOutputStream; |
20 | import java.io.IOException; | 16 | import java.io.IOException; |
21 | import java.nio.charset.StandardCharsets; | ||
22 | import java.util.ArrayList; | 17 | import java.util.ArrayList; |
23 | import java.util.HashSet; | ||
24 | import java.util.List; | 18 | import java.util.List; |
25 | import java.util.Map; | 19 | import java.util.Map; |
26 | 20 | ||
@@ -32,15 +26,15 @@ public class GenerateCommand { | |||
32 | @Inject | 26 | @Inject |
33 | private ModelGeneratorFactory generatorFactory; | 27 | private ModelGeneratorFactory generatorFactory; |
34 | 28 | ||
35 | private String problemPath; | 29 | private String inputPath; |
36 | private String outputPath = "-"; | 30 | private String outputPath = "-"; |
37 | private List<String> scopes = new ArrayList<>(); | 31 | private List<String> scopes = new ArrayList<>(); |
38 | private List<String> overrideScopes = new ArrayList<>(); | 32 | private List<String> overrideScopes = new ArrayList<>(); |
39 | private long randomSeed = 1; | 33 | private long randomSeed = 1; |
40 | 34 | ||
41 | @Parameter(description = "Input path", required = true) | 35 | @Parameter(description = "input path", required = true) |
42 | public void setProblemPath(String problemPath) { | 36 | public void setInputPath(String inputPath) { |
43 | this.problemPath = problemPath; | 37 | this.inputPath = inputPath; |
44 | } | 38 | } |
45 | 39 | ||
46 | @Parameter(names = {"-output", "-o"}, description = "Output path") | 40 | @Parameter(names = {"-output", "-o"}, description = "Output path") |
@@ -64,14 +58,15 @@ public class GenerateCommand { | |||
64 | } | 58 | } |
65 | 59 | ||
66 | public void run() throws IOException { | 60 | public void run() throws IOException { |
67 | var problem = addScopeConstraints(loader.loadFile(problemPath)); | 61 | var problem = isStandardStream(inputPath) ? loader.loadStream(System.in) : loader.loadFile(inputPath); |
62 | problem = loader.loadScopeConstraints(problem, scopes, overrideScopes); | ||
68 | var generator = generatorFactory.createGenerator(problem); | 63 | var generator = generatorFactory.createGenerator(problem); |
69 | generator.setRandomSeed(randomSeed); | 64 | generator.setRandomSeed(randomSeed); |
70 | generator.generate(); | 65 | generator.generate(); |
71 | var solution = generator.serializeSolution(); | 66 | var solution = generator.serializeSolution(); |
72 | var solutionResource = solution.eResource(); | 67 | var solutionResource = solution.eResource(); |
73 | var saveOptions = Map.of(); | 68 | var saveOptions = Map.of(); |
74 | if (outputPath == null || outputPath.equals("-")) { | 69 | if (isStandardStream(outputPath)) { |
75 | printSolution(solutionResource, saveOptions); | 70 | printSolution(solutionResource, saveOptions); |
76 | } else { | 71 | } else { |
77 | try (var outputStream = new FileOutputStream(outputPath)) { | 72 | try (var outputStream = new FileOutputStream(outputPath)) { |
@@ -80,57 +75,8 @@ public class GenerateCommand { | |||
80 | } | 75 | } |
81 | } | 76 | } |
82 | 77 | ||
83 | private Problem addScopeConstraints(Problem problem) throws IOException { | 78 | private boolean isStandardStream(String path) { |
84 | var allScopes = new ArrayList<>(scopes); | 79 | return path == null || path.equals("-"); |
85 | allScopes.addAll(overrideScopes); | ||
86 | if (allScopes.isEmpty()) { | ||
87 | return problem; | ||
88 | } | ||
89 | int originalStatementCount = problem.getStatements().size(); | ||
90 | var builder = new StringBuilder(); | ||
91 | var problemResource = problem.eResource(); | ||
92 | try (var outputStream = new ByteArrayOutputStream()) { | ||
93 | problemResource.save(outputStream, Map.of()); | ||
94 | builder.append(outputStream.toString(StandardCharsets.UTF_8)); | ||
95 | } | ||
96 | builder.append('\n'); | ||
97 | for (var scope : allScopes) { | ||
98 | builder.append("scope ").append(scope).append(".\n"); | ||
99 | } | ||
100 | var modifiedProblem = loader.loadString(builder.toString(), problemResource.getURI()); | ||
101 | var modifiedStatements = modifiedProblem.getStatements(); | ||
102 | int modifiedStatementCount = modifiedStatements.size(); | ||
103 | if (modifiedStatementCount != originalStatementCount + allScopes.size()) { | ||
104 | throw new IllegalStateException("Failed to parse scope constraints"); | ||
105 | } | ||
106 | // Override scopes remove any scope constraint from the original problem with the same target type. | ||
107 | var overriddenScopes = new HashSet<Relation>(); | ||
108 | for (int i = modifiedStatementCount - overrideScopes.size(); i < modifiedStatementCount; i++) { | ||
109 | var statement = modifiedStatements.get(i); | ||
110 | if (!(statement instanceof ScopeDeclaration scopeDeclaration)) { | ||
111 | throw new IllegalStateException("Invalid scope constraint: " + statement); | ||
112 | } | ||
113 | for (var typeScope : scopeDeclaration.getTypeScopes()) { | ||
114 | overriddenScopes.add(typeScope.getTargetType()); | ||
115 | } | ||
116 | } | ||
117 | int statementIndex = 0; | ||
118 | var iterator = modifiedStatements.iterator(); | ||
119 | // Scope overrides only affect type scopes from the original problem and leave type scopes added on the | ||
120 | // command line intact. | ||
121 | while (statementIndex < originalStatementCount && iterator.hasNext()) { | ||
122 | var statement = iterator.next(); | ||
123 | if (statement instanceof ScopeDeclaration scopeDeclaration) { | ||
124 | var typeScopes = scopeDeclaration.getTypeScopes(); | ||
125 | typeScopes.removeIf(typeScope -> overriddenScopes.contains(typeScope.getTargetType())); | ||
126 | // Scope declarations with no type scopes are invalid, so we have to remove them. | ||
127 | if (typeScopes.isEmpty()) { | ||
128 | iterator.remove(); | ||
129 | } | ||
130 | } | ||
131 | statementIndex++; | ||
132 | } | ||
133 | return modifiedProblem; | ||
134 | } | 80 | } |
135 | 81 | ||
136 | // We deliberately write to the standard output if no output path is specified. | 82 | // We deliberately write to the standard output if no output path is specified. |