|
11 | 11 | import java.nio.file.Paths; |
12 | 12 | import java.util.*; |
13 | 13 | import java.util.concurrent.Callable; |
| 14 | +import java.util.stream.Collectors; |
14 | 15 | import org.graalvm.launcher.AbstractLanguageLauncher; |
15 | 16 | import org.graalvm.options.OptionCategory; |
16 | 17 | import org.graalvm.polyglot.Context; |
17 | 18 | import org.graalvm.polyglot.Engine; |
18 | 19 | import org.graalvm.polyglot.Source; |
19 | 20 | import org.graalvm.polyglot.Value; |
| 21 | +import org.json.JSONObject; |
20 | 22 | import picocli.CommandLine; |
21 | 23 |
|
22 | 24 | /** |
@@ -166,106 +168,67 @@ protected void launch(Context.Builder contextBuilder) { |
166 | 168 | * @return The exit code of the script. |
167 | 169 | */ |
168 | 170 | protected int executeScript(Context.Builder contextBuilder) { |
169 | | - // Set the builder common options |
170 | | - contextBuilder.allowIO(true); |
171 | | - contextBuilder.option("lkql.diagnosticOutputMode", "GNATCHECK"); |
172 | | - |
173 | | - // If no rules are provided, don't do anything |
174 | | - contextBuilder.option("lkql.fallbackToAllRules", "false"); |
| 171 | + // Create the LKQL options object builder |
| 172 | + final var optionsBuilder = new LKQLOptions.Builder(); |
175 | 173 |
|
176 | | - // Do not stop the worker's execution when a source file is missing |
177 | | - contextBuilder.option("lkql.keepGoingOnMissingFile", "true"); |
| 174 | + // Set the common configuration |
| 175 | + contextBuilder.allowIO(true); |
| 176 | + contextBuilder.engine( |
| 177 | + Engine.newBuilder() |
| 178 | + .allowExperimentalOptions(true) |
| 179 | + .option("engine.Compilation", "false") |
| 180 | + .build()); |
| 181 | + optionsBuilder |
| 182 | + .diagnosticOutputMode(LKQLOptions.DiagnosticOutputMode.GNATCHECK) |
| 183 | + .fallbackToAllRules(false) |
| 184 | + .keepGoingOnMissingFile(true); |
178 | 185 |
|
179 | 186 | // If a LKQL rule config file has been provided, parse it and display the result |
180 | 187 | if (this.args.lkqlConfigFile != null) { |
181 | 188 | System.out.println( |
182 | | - JSONUtils.serializeInstances(parseLKQLRuleFile(this.args.lkqlConfigFile))); |
| 189 | + new JSONObject( |
| 190 | + parseLKQLRuleFile(this.args.lkqlConfigFile).entrySet().stream() |
| 191 | + .map(e -> Map.entry(e.getKey(), e.getValue().toJson())) |
| 192 | + .collect( |
| 193 | + Collectors.toMap( |
| 194 | + Map.Entry::getKey, Map.Entry::getValue)))); |
183 | 195 | return 0; |
184 | 196 | } |
185 | 197 |
|
186 | | - // Set the context options |
187 | | - if (this.args.verbose) { |
188 | | - contextBuilder.option("lkql.verbose", "true"); |
189 | | - } |
190 | | - |
191 | | - // Set the project file |
192 | | - if (this.args.project != null) { |
193 | | - contextBuilder.option("lkql.projectFile", this.args.project); |
194 | | - } |
195 | | - |
196 | | - if (this.args.subProject != null) { |
197 | | - contextBuilder.option("lkql.subprojectFile", this.args.subProject); |
198 | | - } |
199 | | - |
200 | | - if (this.args.debug) { |
201 | | - contextBuilder.option("lkql.checkerDebug", "true"); |
202 | | - } |
203 | | - |
204 | | - if (!this.args.scenarioVariables.isEmpty()) { |
205 | | - StringBuilder scenarioVars = new StringBuilder(); |
206 | | - Base64.Encoder encoder = Base64.getEncoder(); |
207 | | - this.args.scenarioVariables.forEach( |
208 | | - (key, val) -> { |
209 | | - scenarioVars.append( |
210 | | - new String(encoder.encode((key + "=" + val).getBytes()))); |
211 | | - scenarioVars.append(";"); |
212 | | - }); |
213 | | - contextBuilder.option("lkql.scenarioVars", scenarioVars.toString()); |
214 | | - } |
215 | | - |
216 | | - if (this.args.target != null) { |
217 | | - contextBuilder.option("lkql.target", this.args.target); |
218 | | - } |
219 | | - |
220 | | - if (this.args.RTS != null) { |
221 | | - contextBuilder.option("lkql.runtime", this.args.RTS); |
222 | | - } |
223 | | - |
224 | | - if (this.args.configFile != null) { |
225 | | - contextBuilder.option("lkql.configFile", this.args.configFile); |
226 | | - } |
227 | | - |
228 | | - // Set the files |
| 198 | + // Forward the command line options to the options object builder |
| 199 | + optionsBuilder |
| 200 | + .verbose(this.args.verbose) |
| 201 | + .projectFile(this.args.project) |
| 202 | + .subprojectFile(this.args.subProject) |
| 203 | + .scenarioVariables(this.args.scenarioVariables) |
| 204 | + .target(this.args.target) |
| 205 | + .runtime(this.args.RTS) |
| 206 | + .configFile(this.args.configFile) |
| 207 | + .charset(this.args.charset) |
| 208 | + .rulesDir(this.args.rulesDirs) |
| 209 | + .showInstantiationChain(this.args.showInstantiationChain) |
| 210 | + .checkerDebug(this.args.debug); |
| 211 | + |
| 212 | + // Read the list of sources to analyze provided by GNATcheck driver |
229 | 213 | if (this.args.filesFrom != null) { |
230 | 214 | try { |
231 | | - final List<String> lines = Files.readAllLines(Paths.get(this.args.filesFrom)); |
232 | | - final String files = String.join(File.pathSeparator, lines); |
233 | | - contextBuilder.option("lkql.files", files); |
| 215 | + optionsBuilder.files(Files.readAllLines(Paths.get(this.args.filesFrom))); |
234 | 216 | } catch (IOException e) { |
235 | 217 | System.err.println("Could not read file: " + this.args.filesFrom); |
236 | 218 | } |
237 | 219 | } |
238 | 220 |
|
239 | | - // Set the charset |
240 | | - if (this.args.charset != null) { |
241 | | - contextBuilder.option("lkql.charset", this.args.charset); |
242 | | - } |
243 | | - |
244 | | - // Set the rule directories |
245 | | - if (!this.args.rulesDirs.isEmpty()) { |
246 | | - contextBuilder.option( |
247 | | - "lkql.rulesDirs", String.join(File.pathSeparator, this.args.rulesDirs)); |
248 | | - } |
249 | | - |
250 | | - // Set the generic instantiation displaying parameter |
251 | | - if (this.args.showInstantiationChain) { |
252 | | - contextBuilder.option("lkql.showInstantiationChain", "true"); |
253 | | - } |
254 | | - |
255 | | - // Set the rule instances |
| 221 | + // Parse the rule instances provided by the GNATcheck driver |
256 | 222 | final Map<String, RuleInstance> instances = new HashMap<>(); |
257 | 223 | for (var rulesFrom : this.args.rulesFroms) { |
258 | 224 | if (!rulesFrom.isEmpty()) { |
259 | 225 | instances.putAll(parseLKQLRuleFile(rulesFrom)); |
260 | 226 | } |
261 | 227 | } |
262 | | - contextBuilder.option("lkql.ruleInstances", JSONUtils.serializeInstances(instances)); |
| 228 | + optionsBuilder.ruleInstances(instances); |
263 | 229 |
|
264 | | - contextBuilder.engine( |
265 | | - Engine.newBuilder() |
266 | | - .allowExperimentalOptions(true) |
267 | | - .option("engine.Compilation", "false") |
268 | | - .build()); |
| 230 | + // Finally, pass the options to the LKQL engine |
| 231 | + contextBuilder.option("lkql.options", optionsBuilder.build().toJson().toString()); |
269 | 232 |
|
270 | 233 | // Create the context and run the script in it |
271 | 234 | try (Context context = contextBuilder.build()) { |
@@ -305,7 +268,14 @@ private static Map<String, RuleInstance> parseLKQLRuleFile(final String lkqlRule |
305 | 268 | final Map<String, RuleInstance> res = new HashMap<>(); |
306 | 269 | try (Context context = |
307 | 270 | Context.newBuilder() |
308 | | - .option("lkql.diagnosticOutputMode", "GNATCHECK") |
| 271 | + .option( |
| 272 | + "lkql.options", |
| 273 | + new LKQLOptions.Builder() |
| 274 | + .diagnosticOutputMode( |
| 275 | + LKQLOptions.DiagnosticOutputMode.GNATCHECK) |
| 276 | + .build() |
| 277 | + .toJson() |
| 278 | + .toString()) |
309 | 279 | .allowIO(true) |
310 | 280 | .build()) { |
311 | 281 | // Parse the LKQL rule configuration file with a polyglot context |
|
0 commit comments