Skip to content

Commit a9d5802

Browse files
committed
Merge branch 'topic/lkql_jit_options' into 'master'
Forward all LKQL engine options through a JSON encoded string Closes #346 See merge request eng/libadalang/langkit-query-language!297
2 parents d42dc54 + fcc49d6 commit a9d5802

File tree

30 files changed

+638
-573
lines changed

30 files changed

+638
-573
lines changed

lkql_jit/cli/pom.xml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
<includes>
4646
<include>org.graalvm.sdk:launcher-common</include>
4747
<include>info.picocli:picocli</include>
48+
<include>com.adacore:options</include>
4849
<include>org.json:json</include>
4950
</includes>
5051
</artifactSet>
@@ -105,9 +106,9 @@
105106
</dependency>
106107

107108
<dependency>
108-
<groupId>org.json</groupId>
109-
<artifactId>json</artifactId>
110-
<version>20240303</version>
109+
<groupId>com.adacore</groupId>
110+
<artifactId>options</artifactId>
111+
<version>0.1.0</version>
111112
</dependency>
112113

113114
<dependency>

lkql_jit/cli/src/main/java/com/adacore/lkql_jit/drivers/GNATCheckWorker.java renamed to lkql_jit/cli/src/main/java/com/adacore/lkql_jit/GNATCheckWorker.java

Lines changed: 50 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -3,22 +3,22 @@
33
// SPDX-License-Identifier: GPL-3.0-or-later
44
//
55

6-
package com.adacore.lkql_jit.drivers;
6+
package com.adacore.lkql_jit;
77

8-
import com.adacore.lkql_jit.options.JsonUtils;
9-
import com.adacore.lkql_jit.options.RuleInstance;
108
import java.io.File;
119
import java.io.IOException;
1210
import java.nio.file.Files;
1311
import java.nio.file.Paths;
1412
import java.util.*;
1513
import java.util.concurrent.Callable;
14+
import java.util.stream.Collectors;
1615
import org.graalvm.launcher.AbstractLanguageLauncher;
1716
import org.graalvm.options.OptionCategory;
1817
import org.graalvm.polyglot.Context;
1918
import org.graalvm.polyglot.Engine;
2019
import org.graalvm.polyglot.Source;
2120
import org.graalvm.polyglot.Value;
21+
import org.json.JSONObject;
2222
import picocli.CommandLine;
2323

2424
/**
@@ -168,106 +168,67 @@ protected void launch(Context.Builder contextBuilder) {
168168
* @return The exit code of the script.
169169
*/
170170
protected int executeScript(Context.Builder contextBuilder) {
171-
// Set the builder common options
172-
contextBuilder.allowIO(true);
173-
contextBuilder.option("lkql.diagnosticOutputMode", "GNATCHECK");
174-
175-
// If no rules are provided, don't do anything
176-
contextBuilder.option("lkql.fallbackToAllRules", "false");
171+
// Create the LKQL options object builder
172+
final var optionsBuilder = new LKQLOptions.Builder();
177173

178-
// Do not stop the worker's execution when a source file is missing
179-
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);
180185

181186
// If a LKQL rule config file has been provided, parse it and display the result
182187
if (this.args.lkqlConfigFile != null) {
183188
System.out.println(
184-
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))));
185195
return 0;
186196
}
187197

188-
// Set the context options
189-
if (this.args.verbose) {
190-
contextBuilder.option("lkql.verbose", "true");
191-
}
192-
193-
// Set the project file
194-
if (this.args.project != null) {
195-
contextBuilder.option("lkql.projectFile", this.args.project);
196-
}
197-
198-
if (this.args.subProject != null) {
199-
contextBuilder.option("lkql.subprojectFile", this.args.subProject);
200-
}
201-
202-
if (this.args.debug) {
203-
contextBuilder.option("lkql.checkerDebug", "true");
204-
}
205-
206-
if (!this.args.scenarioVariables.isEmpty()) {
207-
StringBuilder scenarioVars = new StringBuilder();
208-
Base64.Encoder encoder = Base64.getEncoder();
209-
this.args.scenarioVariables.forEach(
210-
(key, val) -> {
211-
scenarioVars.append(
212-
new String(encoder.encode((key + "=" + val).getBytes())));
213-
scenarioVars.append(";");
214-
});
215-
contextBuilder.option("lkql.scenarioVars", scenarioVars.toString());
216-
}
217-
218-
if (this.args.target != null) {
219-
contextBuilder.option("lkql.target", this.args.target);
220-
}
221-
222-
if (this.args.RTS != null) {
223-
contextBuilder.option("lkql.runtime", this.args.RTS);
224-
}
225-
226-
if (this.args.configFile != null) {
227-
contextBuilder.option("lkql.configFile", this.args.configFile);
228-
}
229-
230-
// 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
231213
if (this.args.filesFrom != null) {
232214
try {
233-
final List<String> lines = Files.readAllLines(Paths.get(this.args.filesFrom));
234-
final String files = String.join(File.pathSeparator, lines);
235-
contextBuilder.option("lkql.files", files);
215+
optionsBuilder.files(Files.readAllLines(Paths.get(this.args.filesFrom)));
236216
} catch (IOException e) {
237217
System.err.println("Could not read file: " + this.args.filesFrom);
238218
}
239219
}
240220

241-
// Set the charset
242-
if (this.args.charset != null) {
243-
contextBuilder.option("lkql.charset", this.args.charset);
244-
}
245-
246-
// Set the rule directories
247-
if (!this.args.rulesDirs.isEmpty()) {
248-
contextBuilder.option(
249-
"lkql.rulesDirs", String.join(File.pathSeparator, this.args.rulesDirs));
250-
}
251-
252-
// Set the generic instantiation displaying parameter
253-
if (this.args.showInstantiationChain) {
254-
contextBuilder.option("lkql.showInstantiationChain", "true");
255-
}
256-
257-
// Set the rule instances
221+
// Parse the rule instances provided by the GNATcheck driver
258222
final Map<String, RuleInstance> instances = new HashMap<>();
259223
for (var rulesFrom : this.args.rulesFroms) {
260224
if (!rulesFrom.isEmpty()) {
261225
instances.putAll(parseLKQLRuleFile(rulesFrom));
262226
}
263227
}
264-
contextBuilder.option("lkql.ruleInstances", JsonUtils.serializeInstances(instances));
228+
optionsBuilder.ruleInstances(instances);
265229

266-
contextBuilder.engine(
267-
Engine.newBuilder()
268-
.allowExperimentalOptions(true)
269-
.option("engine.Compilation", "false")
270-
.build());
230+
// Finally, pass the options to the LKQL engine
231+
contextBuilder.option("lkql.options", optionsBuilder.build().toJson().toString());
271232

272233
// Create the context and run the script in it
273234
try (Context context = contextBuilder.build()) {
@@ -307,7 +268,14 @@ private static Map<String, RuleInstance> parseLKQLRuleFile(final String lkqlRule
307268
final Map<String, RuleInstance> res = new HashMap<>();
308269
try (Context context =
309270
Context.newBuilder()
310-
.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())
311279
.allowIO(true)
312280
.build()) {
313281
// Parse the LKQL rule configuration file with a polyglot context

lkql_jit/cli/src/main/java/com/adacore/lkql_jit/drivers/LKQLChecker.java renamed to lkql_jit/cli/src/main/java/com/adacore/lkql_jit/LKQLChecker.java

Lines changed: 31 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,8 @@
33
// SPDX-License-Identifier: GPL-3.0-or-later
44
//
55

6-
package com.adacore.lkql_jit.drivers;
6+
package com.adacore.lkql_jit;
77

8-
import com.adacore.lkql_jit.options.JsonUtils;
9-
import com.adacore.lkql_jit.options.RuleInstance;
10-
import java.io.File;
118
import java.util.*;
129
import java.util.concurrent.Callable;
1310
import org.graalvm.launcher.AbstractLanguageLauncher;
@@ -103,7 +100,7 @@ enum PropertyErrorRecoveryMode {
103100
@CommandLine.Option(
104101
names = {"-I", "--ignores"},
105102
description = "Ada files to ignore during analysis")
106-
public String ignores = null;
103+
public List<String> ignores = new ArrayList<>();
107104

108105
@CommandLine.Option(
109106
names = "--keep-going-on-missing-file",
@@ -176,70 +173,35 @@ protected void launch(Context.Builder contextBuilder) {
176173
* @return The exit code of the script.
177174
*/
178175
protected int executeScript(Context.Builder contextBuilder) {
179-
// Set the builder common options
180-
contextBuilder.allowIO(true);
181-
182-
contextBuilder.option("lkql.checkerDebug", "true");
183-
184-
// Set the context options
185-
if (this.args.verbose) {
186-
System.out.println("=== LKQL JIT is in verbose mode ===");
187-
contextBuilder.option("lkql.verbose", "true");
188-
}
189-
190-
if (this.args.keepGoingOnMissingFile) {
191-
contextBuilder.option("lkql.keepGoingOnMissingFile", "true");
192-
}
193-
194-
// Set the project file
195-
if (this.args.project != null) {
196-
contextBuilder.option("lkql.projectFile", this.args.project);
197-
}
198-
199-
// Set the files
200-
if (!this.args.files.isEmpty()) {
201-
contextBuilder.option("lkql.files", String.join(File.pathSeparator, this.args.files));
202-
}
203-
204-
// Set the charset
205-
if (this.args.charset != null
206-
&& !this.args.charset.isEmpty()
207-
&& !this.args.charset.isBlank()) {
208-
contextBuilder.option("lkql.charset", this.args.charset);
209-
}
210-
211-
if (this.args.RTS != null) {
212-
contextBuilder.option("lkql.runtime", this.args.RTS);
213-
}
214-
215-
if (this.args.target != null) {
216-
contextBuilder.option("lkql.target", this.args.target);
217-
}
218-
219-
// Set the rule directories
220-
if (!this.args.rulesDirs.isEmpty()) {
221-
contextBuilder.option(
222-
"lkql.rulesDirs", String.join(File.pathSeparator, this.args.rulesDirs));
223-
}
224-
225-
// Pass the rule instances to the LKQL engine
226-
try {
227-
contextBuilder.option(
228-
"lkql.ruleInstances", JsonUtils.serializeInstances(this.getRuleInstances()));
229-
} catch (Exception e) {
230-
System.err.println(e.getMessage());
231-
}
232-
233-
// Set the Ada files to ignore during the analysis
234-
if (this.args.ignores != null) {
235-
contextBuilder.option("lkql.ignores", this.args.ignores);
236-
}
237-
238-
// This is needed to make sure that calls to `exitContext` done from within an isolate
239-
// thread (e.g. executing a Java callback from Ada code) directly stop the program instead
240-
// of going it the normal way by raising a special exception, as such exceptions won't be
241-
// handled by the caller when thrown from inside the isolate thread.
242-
contextBuilder.useSystemExit(true);
176+
// Create the LKQL options object builder
177+
final var optionsBuilder = new LKQLOptions.Builder();
178+
179+
// Set the common configurations
180+
contextBuilder
181+
.allowIO(true)
182+
// This is needed to make sure that calls to `exitContext` done from within an
183+
// isolate thread (e.g. executing a Java callback from Ada code) directly stop
184+
// the program instead of going it the normal way by raising a special exception,
185+
// as such exceptions won't be handled by the caller when thrown from inside the
186+
// isolate thread.
187+
.useSystemExit(true);
188+
optionsBuilder.checkerDebug(true);
189+
190+
// Forward the command line options to the options object builder
191+
optionsBuilder
192+
.verbose(this.args.verbose)
193+
.keepGoingOnMissingFile(this.args.keepGoingOnMissingFile)
194+
.projectFile(this.args.project)
195+
.files(this.args.files)
196+
.ignores(this.args.ignores)
197+
.charset(this.args.charset)
198+
.target(this.args.target)
199+
.runtime(this.args.RTS)
200+
.rulesDir(this.args.rulesDirs)
201+
.ruleInstances(this.getRuleInstances());
202+
203+
// Finally, pass the options to the LKQL engine
204+
contextBuilder.option("lkql.options", optionsBuilder.build().toJson().toString());
243205

244206
// Create the context and run the script in it
245207
try (Context context = contextBuilder.build()) {

lkql_jit/cli/src/main/java/com/adacore/lkql_jit/drivers/LKQLDoc.java renamed to lkql_jit/cli/src/main/java/com/adacore/lkql_jit/LKQLDoc.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
// SPDX-License-Identifier: GPL-3.0-or-later
44
//
55

6-
package com.adacore.lkql_jit.drivers;
6+
package com.adacore.lkql_jit;
77

88
import java.io.BufferedWriter;
99
import java.io.IOException;
@@ -32,7 +32,14 @@ public class LKQLDoc implements Callable<Integer> {
3232

3333
@Override
3434
public Integer call() {
35-
Context context = Context.newBuilder("lkql").allowAllAccess(true).build();
35+
Context context =
36+
Context.newBuilder("lkql")
37+
.allowAllAccess(true)
38+
// Set default LKQL options
39+
.option(
40+
"lkql.options",
41+
new LKQLOptions.Builder().build().toJson().toString())
42+
.build();
3643
try {
3744
Files.createDirectories(FileSystems.getDefault().getPath(outputDir));
3845
} catch (IOException e) {

0 commit comments

Comments
 (0)