diff --git a/Makefile b/Makefile index 79e94c33e..fade8eb18 100644 --- a/Makefile +++ b/Makefile @@ -64,7 +64,7 @@ lkql_jit: lkql lkql_native_jit: lkql $(MAVEN) -f lkql/build/java/ install - $(MAVEN) -f lkql_jit/ clean install -P native-all + $(MAVEN) -f lkql_jit/ clean install -P native .PHONY: lkql_checker diff --git a/lkql_checker/lalcheck/gnatcheck-compiler.adb b/lkql_checker/lalcheck/gnatcheck-compiler.adb index 2bab4e7fa..8911f50cb 100644 --- a/lkql_checker/lalcheck/gnatcheck-compiler.adb +++ b/lkql_checker/lalcheck/gnatcheck-compiler.adb @@ -1372,11 +1372,11 @@ package body Gnatcheck.Compiler is end if; end Set_Compiler_Checks; - --------------------- - -- Spawn_Gnatcheck -- - --------------------- + ---------------------------- + -- Spawn_Gnatcheck_Worker -- + ---------------------------- - function Spawn_Gnatcheck + function Spawn_Gnatcheck_Worker (Rule_File : String; Msg_File : String; Source_File : String) return Process_Id @@ -1405,9 +1405,6 @@ package body Gnatcheck.Compiler is end if; end loop; - Num_Args := @ + 1; - Args (Num_Args) := new String'("--subprocess"); - if Prj /= "" then Num_Args := @ + 1; Args (Num_Args) := new String'("-P" & Prj); @@ -1428,14 +1425,6 @@ package body Gnatcheck.Compiler is Args (Num_Args) := new String'("-A"); Num_Args := @ + 1; Args (Num_Args) := new String'(Get_Aggregated_Project); - - if XML_Report_ON then - Num_Args := @ + 1; - Args (Num_Args) := new String'("-ox=" & Get_XML_Report_File_Name); - else - Num_Args := @ + 1; - Args (Num_Args) := new String'("-o=" & Get_Report_File_Name); - end if; end if; if RTS_Path.all /= "" then @@ -1458,48 +1447,29 @@ package body Gnatcheck.Compiler is Args (Num_Args) := new String'("-eL"); end if; - if No_Object_Dir then - Num_Args := @ + 1; - Args (Num_Args) := new String'("--no_objects_dir"); - end if; - for Dir of Additional_Rules_Dirs loop Num_Args := @ + 1; Args (Num_Args) := new String'("--rules-dir=" & Dir); end loop; - if U_Option_Set then - Num_Args := @ + 1; - Args (Num_Args) := new String'("-U"); - end if; - - if not Main_Unit.Is_Empty then - for MU of Main_Unit loop - Num_Args := @ + 1; - Args (Num_Args) := new String'(String (MU.Name)); - end loop; - end if; - Num_Args := @ + 1; - Args (Num_Args) := new String'("-files=" & Source_File); + Args (Num_Args) := new String'("--files-from=" & Source_File); Append_Variables (Args, Num_Args); - Num_Args := @ + 1; - Args (Num_Args) := new String'("-rules"); - Num_Args := @ + 1; - Args (Num_Args) := new String'("-from=" & Rule_File); - if LKQL_Rule_File_Name /= null then Num_Args := @ + 1; - Args (Num_Args) := new String'("-from-lkql=" & - LKQL_Rule_File_Name.all); + Args (Num_Args) := + new String'("--rules-from=" & LKQL_Rule_File_Name.all); + else + Num_Args := @ + 1; + Args (Num_Args) := new String'("--rules-from=" & Rule_File); end if; if Debug_Mode then -- For debug purposes, we don't want to put the full path to the -- worker command, if it is a full path. We just want the base name - Put (Base_Name (Worker_Command)); + Put (Base_Name (Worker.all)); for J in 1 .. Num_Args loop Put (" " & Args (J).all); @@ -1518,7 +1488,7 @@ package body Gnatcheck.Compiler is end loop; return Pid; - end Spawn_Gnatcheck; + end Spawn_Gnatcheck_Worker; -------------------- -- Spawn_GPRbuild -- diff --git a/lkql_checker/lalcheck/gnatcheck-compiler.ads b/lkql_checker/lalcheck/gnatcheck-compiler.ads index 0925df798..f890d7785 100644 --- a/lkql_checker/lalcheck/gnatcheck-compiler.ads +++ b/lkql_checker/lalcheck/gnatcheck-compiler.ads @@ -126,14 +126,14 @@ package Gnatcheck.Compiler is -- format of restriction rules and places the output into the specified -- file that is supposed to be an opened out file. - function Spawn_Gnatcheck + function Spawn_Gnatcheck_Worker (Rule_File : String; Msg_File : String; Source_File : String) return Process_Id; - -- Spawn gnatcheck on the main project file with the relevant options - -- on the rules given by Rule_File, redirecting the output to Msg_File. - -- Source_File is the name of a file listing all the source files to - -- analyze. + -- Spawn a gnatcheck worker (LKQL) on the main project file with the + -- relevant options on the rules given by Rule_File, redirecting the + -- output to Msg_File. Source_File is the name of a file listing all the + -- source files to analyze. function Spawn_GPRbuild (Output_File : String) return Process_Id; -- Spawn gprbuild on the main project file with the relevant options, diff --git a/lkql_checker/lalcheck/gnatcheck-options.ads b/lkql_checker/lalcheck/gnatcheck-options.ads index 56ba3f02a..6fd4b6f17 100644 --- a/lkql_checker/lalcheck/gnatcheck-options.ads +++ b/lkql_checker/lalcheck/gnatcheck-options.ads @@ -45,7 +45,7 @@ package Gnatcheck.Options is -- The name of the environment variable used to define a custom worker -- executable. - Default_Worker : constant String := "native_gnatcheck_worker"; + Default_Worker : constant String := "lkql gnatcheck_worker"; -- The name of the worker executable to use. Worker_Name : constant String := diff --git a/lkql_checker/lalcheck/lalcheck.adb b/lkql_checker/lalcheck/lalcheck.adb index a31418862..724638db8 100644 --- a/lkql_checker/lalcheck/lalcheck.adb +++ b/lkql_checker/lalcheck/lalcheck.adb @@ -314,7 +314,7 @@ procedure Lalcheck is -- -rules -from=rules0.txt -files=files?.txt Pids (Job) := - Spawn_Gnatcheck + Spawn_Gnatcheck_Worker (File_Name ("rules", 0), File_Name ("out", Job), File_Name ("files", Job)); diff --git a/lkql_jit/checker/src/main/java/com/adacore/lkql_jit/LKQLChecker.java b/lkql_jit/checker/src/main/java/com/adacore/lkql_jit/LKQLChecker.java deleted file mode 100644 index b0244f58a..000000000 --- a/lkql_jit/checker/src/main/java/com/adacore/lkql_jit/LKQLChecker.java +++ /dev/null @@ -1,470 +0,0 @@ -/*---------------------------------------------------------------------------- --- L K Q L J I T -- --- -- --- Copyright (C) 2022-2023, AdaCore -- --- -- --- This library is free software; you can redistribute it and/or modify it -- --- under terms of the GNU General Public License as published by the Free -- --- Software Foundation; either version 3, or (at your option) any later -- --- version. This library is distributed in the hope that it will be useful, -- --- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- --- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- --- -- --- As a special exception under Section 7 of GPL version 3, you are granted -- --- additional permissions described in the GCC Runtime Library Exception, -- --- version 3.1, as published by the Free Software Foundation. -- --- -- --- You should have received a copy of the GNU General Public License and -- --- a copy of the GCC Runtime Library Exception along with this program; -- --- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- --- -- -----------------------------------------------------------------------------*/ - -package com.adacore.lkql_jit; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import org.graalvm.launcher.AbstractLanguageLauncher; -import org.graalvm.options.OptionCategory; -import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.PolyglotException; -import org.graalvm.polyglot.Source; -import org.graalvm.polyglot.Value; - -/** - * This class represents the LKQL checker entry point with the LKQL JIT backend. This is a TEMPORARY - * driver to perform efficiency tests on LKQL JIT in real life use case. TODO : Support all flags - * and options of the lkql_checker original implementation. - * - * @author Hugo GUERRIER - */ -public class LKQLChecker extends AbstractLanguageLauncher { - - // ----- Macros and enums ----- - - /** Represents the status of an argument. */ - protected enum ArgumentStatus { - Consumed, - Unhandled, - Malformed, - ExpectInt - } - - /** The identifier of the LKQL language. */ - private static final String ID = "lkql"; - - // ----- Launcher options ----- - - /** The charset to decode the LKQL sources. */ - private String charset = null; - - /** The project file to analyse. */ - private String projectFile = null; - - /** Source files to analyse. */ - private final List files = new ArrayList<>(); - - /** If the project analysis should be recursive. */ - private boolean recursive = false; - - /** Number of parallel jobs. */ - private int jobs = 0; - - /** If the verbose mode should be activated. */ - private boolean verbose = false; - - /** Whether to keep the engine running when a required file was not found */ - private boolean keepGoingOnMissingFile = false; - - // ----- Checker options ----- - - /** A directory containing all user added rules. */ - private String rulesDirs = null; - - /** The rules to apply. */ - private String rules = null; - - /** The arguments to pass to the rules. */ - private List rulesArgs = new ArrayList<>(); - - /** The source files to ignore during analysis. */ - private String ignores = null; - - /** The mode of error recovery. */ - private final String errorMode = "continue_and_warn"; - - // ----- Checker methods ----- - - /** - * Display the help message for the LKQL language. - * - * @param maxCategory The option category. - */ - @Override - protected void printHelp(OptionCategory maxCategory) { - System.out.println( - """ - usage : lkql_jit_checker [options ...] files [files ...] - - The LKQL checker using LKQL JIT compiler - - Positional arguments : - files : Files to analyse - - Basic options: - --charset, -C Charset to use for the source decoding - --project, -P Project file to use - --recursive, -U Process all units in the project tree, excluding - externally built projects - --jobs, -j Number of parallel jobs to use. If zero, use the - maximal parallelism : one job per CPU - - --verbose, -v Enable the verbose mode - - --rules-dirs Specify directories where rules will be seek from - --rules, -r Comma separated rules to apply (if not passed - all rules are applied) - --rule-arg, -a Argument to pass to a rule, with the syntax - .= - --property-error-recovery, -pr Which behavior to adopt when there is a - property error inside of a LKQL query. - Possible alternatives: continue_and_warn, - continue_and_log, raise_error. Default: - continue_and_warn - """); - } - - /** - * Simply return the language id. - * - * @return The language id. - */ - @Override - protected String getLanguageId() { - return ID; - } - - /** - * Start the LKQL checker. - * - * @param args The params. - */ - public static void main(String[] args) { - new LKQLChecker().launch(args); - } - - /** - * Start the LQKL checker. - * - * @param contextBuilder The context builder to build LKQL context. - */ - @Override - protected void launch(Context.Builder contextBuilder) { - int exitCode = this.executeScript(contextBuilder); - if (exitCode != 0) { - throw this.abort((String) null, exitCode); - } - } - - /** - * Execute the LKQL checker script and return the exit code. - * - * @param contextBuilder The context builder. - * @return The exit code of the script. - */ - protected int executeScript(Context.Builder contextBuilder) { - // Set the builder common options - contextBuilder.allowIO(true); - - contextBuilder.option("lkql.checkerDebug", "true"); - - // Set the context options - if (this.verbose) { - System.out.println("=== LKQL JIT is in verbose mode ==="); - contextBuilder.option("lkql.verbose", "true"); - } - - if (this.keepGoingOnMissingFile) { - contextBuilder.option("lkql.keepGoingOnMissingFile", "true"); - } - - // Set the project file - if (this.projectFile != null) { - contextBuilder.option("lkql.projectFile", this.projectFile); - } - - // Set the files - if (!this.files.isEmpty()) { - contextBuilder.option("lkql.files", String.join(File.pathSeparator, this.files)); - } - - // Set the charset - if (this.charset != null && !this.charset.isEmpty() && !this.charset.isBlank()) { - contextBuilder.option("lkql.charset", this.charset); - } - - // Set the rule directories - if (this.rulesDirs != null) { - contextBuilder.option("lkql.rulesDirs", this.rulesDirs); - } - - // Set the rule to apply - if (this.rules != null && !this.rules.isEmpty() && !this.rules.isBlank()) { - contextBuilder.option("lkql.rules", this.rules.toLowerCase()); - } - - // Set the rule argument - contextBuilder.option("lkql.rulesArgs", String.join(";", this.rulesArgs)); - - // Set the Ada files to ignore during the analysis - if (this.ignores != null && !this.ignores.isEmpty() && !this.ignores.isBlank()) { - contextBuilder.option("lkql.ignores", this.ignores); - } - - // Create the context and run the script in it - try (Context context = contextBuilder.build()) { - final Source source = Source.newBuilder("lkql", checkerSource, "checker.lkql").build(); - final Value executable = context.parse(source); - executable.executeVoid(true); - return 0; - } catch (Exception e) { - if (e instanceof PolyglotException pe && pe.isExit()) { - return pe.getExitStatus(); - } else if (this.verbose) { - e.printStackTrace(); - } else { - System.err.println(e.getMessage()); - } - return 0; - } - } - - // ----- Argument parsing methods ----- - - /** - * Get the checker specific argument and return the unparsed ones to the default parser. - * - * @param arguments The arguments to parse. - * @param polyglotOptions The polyglot options. - * @return The unrecognized options. - */ - @Override - protected List preprocessArguments( - List arguments, Map polyglotOptions) { - // Prepare the list to return - final List unrecognizedArguments = new ArrayList<>(); - - // Iterate over arguments and parse them - ListIterator iterator = arguments.listIterator(); - while (iterator.hasNext()) { - String curArg = iterator.next(); - - // Test if the arg is a flag - if (curArg.startsWith("-") && curArg.length() >= 2 && !curArg.equals("--")) { - - // Get the flag name - String flag; - if (curArg.startsWith("--")) { - flag = curArg.substring(2); - } else { - flag = this.expandShortFlag(curArg.substring(1)); - } - - // If the flag is not null - if (flag != null) { - - // Test if the flag is a solo one - if (processFlag(flag) == ArgumentStatus.Consumed) { - continue; - } - - // Else try to process it with the value - String value; - if (iterator.hasNext()) { - value = iterator.next(); - } else { - value = null; - } - - // Try to consume the flag - switch (this.processFlag(flag, value)) { - case Consumed -> { - continue; - } - case Malformed -> throw this.abort("Missing value for " + curArg); - case ExpectInt -> throw this.abort("Expected integer value for " + curArg); - } - - // Reset the iterator - if (value != null) { - iterator.previous(); - } - } - - // If all fail, add the argument to the unrecognized arg - unrecognizedArguments.add(curArg); - } - - // Else simply add it to the files - else { - this.files.add(curArg); - } - } - - // Return the unhandled arguments - return unrecognizedArguments; - } - - /** - * Expand a short flag into a long flag. - * - * @param shortFlag The short flag. - * @return The long flag value. - */ - protected String expandShortFlag(String shortFlag) { - return switch (shortFlag) { - case "C" -> "charset"; - case "P" -> "project"; - case "U" -> "recursive"; - case "j" -> "jobs"; - case "v" -> "verbose"; - case "r" -> "rules"; - case "a" -> "rule-arg"; - case "k" -> "keep-going-on-missing-file"; - default -> null; - }; - } - - /** - * Process the flag without argument. - * - * @param flag The flag to process. - * @return The status of the argument parsing. - */ - protected ArgumentStatus processFlag(String flag) { - switch (flag) { - // The recursive flag - case "recursive": - this.recursive = true; - break; - - // The verbose flag - case "verbose": - this.verbose = true; - break; - - case "keep-going-on-missing-file": - this.keepGoingOnMissingFile = true; - break; - - // Default behavior - default: - return ArgumentStatus.Unhandled; - } - return ArgumentStatus.Consumed; - } - - /** - * Process a flag with its argument. - * - * @param flag The flag to process. - * @param value The argument value. - * @return If the flag was consumed, unhandled or wrong. - */ - protected ArgumentStatus processFlag(String flag, String value) { - switch (flag) { - // The charset value - case "charset": - if (value == null) { - return ArgumentStatus.Malformed; - } - this.charset = value; - break; - - // The project value - case "project": - if (value == null) { - return ArgumentStatus.Malformed; - } - this.projectFile = value; - break; - - // The jobs value - case "jobs": - if (value == null) { - return ArgumentStatus.Malformed; - } - try { - this.jobs = Integer.parseInt(value); - } catch (Exception e) { - return ArgumentStatus.ExpectInt; - } - break; - - // The add rule dir - case "rules-dirs": - if (value == null) { - return ArgumentStatus.Malformed; - } - this.rulesDirs = value; - break; - - // The rule precision - case "rules": - if (value == null) { - return ArgumentStatus.Malformed; - } - this.rules = value; - break; - - case "rule-arg": - if (value == null) { - return ArgumentStatus.Malformed; - } - this.rulesArgs.add(value); - break; - - case "ignores": - if (value == null) { - return ArgumentStatus.Malformed; - } - this.ignores = value; - break; - - // The default unhandled flag - default: - return ArgumentStatus.Unhandled; - } - return ArgumentStatus.Consumed; - } - - /** - * Validate the state of the launcher after argument parsing. - * - * @param polyglotOptions The polyglot options. - */ - @Override - protected void validateArguments(Map polyglotOptions) { - // Launch the super validation - super.validateArguments(polyglotOptions); - - // Verify the project file - if (this.files.isEmpty() && (this.projectFile == null || this.projectFile.isEmpty())) { - System.err.println("No source file to process"); - } - } - - // ----- The LKQL checker ----- - - public static final String checkerSource = - """ - val analysis_units = specified_units() - val roots = [unit.root for unit in analysis_units] - - map(roots, (root) => node_checker(root)) - map(analysis_units, (unit) => unit_checker(unit)) - """; -} diff --git a/lkql_jit/component/make.py b/lkql_jit/component/make.py index a153b6d0a..e7ddc05c4 100644 --- a/lkql_jit/component/make.py +++ b/lkql_jit/component/make.py @@ -95,12 +95,7 @@ # Copy the produced JARs to the component for name, source_filename in [ ("language", P.join("..", "language", "target", "lkql_jit.jar")), - ("launcher", P.join("..", "launcher", "target", "lkql_jit_launcher.jar")), - ("checker", P.join("..", "checker", "target", "lkql_jit_checker.jar")), - ( - "gnatcheck_worker", - P.join("..", "gnatcheck_worker", "target", "gnatcheck_worker.jar"), - ), + ("lkql_cli", P.join("..", "lkql_cli", "target", "lkql_cli.jar")), ]: # Ensure the JAR has been produced if not P.isfile(source_filename): diff --git a/lkql_jit/gnatcheck_worker/pom.xml b/lkql_jit/gnatcheck_worker/pom.xml deleted file mode 100644 index 00842ca08..000000000 --- a/lkql_jit/gnatcheck_worker/pom.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - - lkql_jit - com.adacore - 0.1.0 - - - 4.0.0 - - gnatcheck_worker - - - - - - org.apache.maven.plugins - maven-jar-plugin - 3.3.0 - - - - com.adacore.lkql_jit.GNATCheckWorker - - - - - - - - org.apache.maven.plugins - maven-shade-plugin - 3.1.1 - - - package - - shade - - - gnatcheck_worker - - - org.graalvm.sdk:launcher-common - - - - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - META-INF/*.DES - - - - - - - - - - - com.diffplug.spotless - spotless-maven-plugin - 2.40.0 - - true - - - - - - - - org.graalvm.sdk - graal-sdk - ${graalvm.version} - - - - org.graalvm.sdk - launcher-common - ${graalvm.version} - - - - com.adacore - language - ${project.parent.version} - - - - diff --git a/lkql_jit/gnatcheck_worker/src/main/java/com/adacore/lkql_jit/GNATCheckWorker.java b/lkql_jit/gnatcheck_worker/src/main/java/com/adacore/lkql_jit/GNATCheckWorker.java deleted file mode 100644 index 1a9b42684..000000000 --- a/lkql_jit/gnatcheck_worker/src/main/java/com/adacore/lkql_jit/GNATCheckWorker.java +++ /dev/null @@ -1,440 +0,0 @@ -/*---------------------------------------------------------------------------- --- L K Q L J I T -- --- -- --- Copyright (C) 2022-2023, AdaCore -- --- -- --- This library is free software; you can redistribute it and/or modify it -- --- under terms of the GNU General Public License as published by the Free -- --- Software Foundation; either version 3, or (at your option) any later -- --- version. This library is distributed in the hope that it will be useful, -- --- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- --- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- --- -- --- As a special exception under Section 7 of GPL version 3, you are granted -- --- additional permissions described in the GCC Runtime Library Exception, -- --- version 3.1, as published by the Free Software Foundation. -- --- -- --- You should have received a copy of the GNU General Public License and -- --- a copy of the GCC Runtime Library Exception along with this program; -- --- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- --- -- -----------------------------------------------------------------------------*/ - -package com.adacore.lkql_jit; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.*; -import org.graalvm.launcher.AbstractLanguageLauncher; -import org.graalvm.options.OptionCategory; -import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.Source; -import org.graalvm.polyglot.Value; - -/** - * Implement a worker process for the GNATcheck driver. - * - * @author Romain BEGUET - */ -public class GNATCheckWorker extends AbstractLanguageLauncher { - - // ----- Macros and enums ----- - - /** The identifier of the LKQL language. */ - private static final String ID = "lkql"; - - // ----- Launcher options ----- - - /** The charset to decode the LKQL sources. */ - private String charset = null; - - /** If the project analysis should be recursive. */ - private boolean recursive = false; - - /** If the verbose mode should be activated. */ - private boolean verbose = false; - - /** The project file to analyse. */ - private String projectFile = null; - - /** - * The name of the subproject to analyse, if any. This implies that `projectFile` designates an - * aggregate project. - */ - private String subprojectFile = null; - - /** Whether GNATcheck is in debug mode. */ - private boolean debug = false; - - /** The project's scenario variables. */ - private String scenarioVars = null; - - /** Whether the '--simple-project' flag was used. */ - private boolean isSimpleProject = false; - - /** A directory containing all user added rules. */ - private String rulesDirs = null; - - /** The rules to apply. */ - private String rulesFrom = null; - - /** The LKQL file to configure the rules. */ - private String rulesFromLKQL = null; - - /** The file containing the files to analyse. */ - private String filesFrom = null; - - /** The source files to ignore during analysis. */ - private String ignore = null; - - // ----- Checker methods ----- - - /** - * Display the help message for the LKQL language. - * - * @param maxCategory The option category. - */ - @Override - protected void printHelp(OptionCategory maxCategory) { - System.out.println("No help!"); - } - - /** - * Simply return the language id. - * - * @return The language id. - */ - @Override - protected String getLanguageId() { - return ID; - } - - /** - * Start the LKQL checker. - * - * @param args The params. - */ - public static void main(String[] args) { - new GNATCheckWorker().launch(args); - } - - /** - * Start the GNATcheck worker. - * - * @param contextBuilder The context builder to build LKQL context. - */ - @Override - protected void launch(Context.Builder contextBuilder) { - int exitCode = this.executeScript(contextBuilder); - if (exitCode != 0) { - throw this.abort((String) null, exitCode); - } - } - - /** - * Execute the GNATcheck worker script and return the exit code. - * - * @param contextBuilder The context builder. - * @return The exit code of the script. - */ - protected int executeScript(Context.Builder contextBuilder) { - // Set the builder common options - contextBuilder.allowIO(true); - contextBuilder.option("lkql.diagnosticOutputMode", "GNATCHECK"); - - // If no rules are provided, don't do anything - contextBuilder.option("lkql.fallbackToAllRules", "false"); - - // Do not stop the worker's execution when a source file is missing - contextBuilder.option("lkql.keepGoingOnMissingFile", "true"); - - // Set the context options - if (this.verbose) { - contextBuilder.option("lkql.verbose", "true"); - } - - // Set the project file - if (this.projectFile != null) { - contextBuilder.option("lkql.projectFile", this.projectFile); - } - - if (this.subprojectFile != null) { - contextBuilder.option("lkql.subprojectFile", this.subprojectFile); - } - - if (this.debug) { - contextBuilder.option("lkql.checkerDebug", "true"); - } - - if (this.scenarioVars != null) { - contextBuilder.option("lkql.scenarioVars", this.scenarioVars); - } - - if (this.isSimpleProject) { - contextBuilder.option("lkql.useAutoProvider", "true"); - } - - // Set the files - if (!this.filesFrom.isEmpty()) { - try { - final List lines = Files.readAllLines(Paths.get(this.filesFrom)); - final String files = String.join(File.pathSeparator, lines); - contextBuilder.option("lkql.files", files); - } catch (IOException e) { - System.err.println("Could not read file: " + this.filesFrom); - } - } - - // Set the charset - if (this.charset != null && !this.charset.isEmpty() && !this.charset.isBlank()) { - contextBuilder.option("lkql.charset", this.charset); - } - - // Set the rule directories - if (this.rulesDirs != null) { - contextBuilder.option("lkql.rulesDirs", this.rulesDirs); - } - - // Set the rule to apply - if (!this.rulesFrom.isEmpty()) { - final List allRules = new ArrayList<>(); - final List allArgs = new ArrayList<>(); - processRuleSpecificationFile(this.rulesFrom, allRules, allArgs); - contextBuilder.option("lkql.rules", String.join(",", allRules)); - contextBuilder.option("lkql.rulesArgs", String.join(";", allArgs)); - } - - // Set the LKQL rule config file - if (this.rulesFromLKQL != null && !this.rulesFromLKQL.isEmpty()) { - contextBuilder.option("lkql.LKQLRuleFile", this.rulesFromLKQL); - } - - if (this.ignore != null && !this.ignore.isEmpty() && !this.ignore.isBlank()) { - contextBuilder.option("lkql.ignores", this.ignore); - } - - // Create the context and run the script in it - try (Context context = contextBuilder.build()) { - final Source source = Source.newBuilder("lkql", checkerSource, "checker.lkql").build(); - final Value executable = context.parse(source); - executable.executeVoid(true); - return 0; - } catch (Exception e) { - if (this.verbose) { - e.printStackTrace(); - } else { - System.err.println(e.getMessage()); - } - return 0; - } - } - - // ----- Argument parsing methods ----- - - /** - * Get the GNATcheck worker specific argument and return the unparsed ones to the default - * parser. - * - *

The expected format for command-line arguments is as follows (the order should be - * respected): - * - *

    - *
  • `--subprocess` No-op here. Originally used by GNATcheck to discriminate between a - * driver run and a worker run, since they were implemented by the same application. - *
  • `[-P{project} [--ignore-project-switches]]` The project file to use, and whether to - * ignore GNATcheck- related options that are specified in it. - *
  • `[--simple-project]` - *
  • `[-A]` The aggregated project to consider, used when the main project file is an - * aggregate project. - *
  • `[--RTS {runtime}]` The runtime to use - *
  • `[--target {target}]` The target to use - *
  • `[-d]` Whether to output debug information - *
  • `[-eL]` - *
  • `[--no_objects_dir]` Whether to output data in the objects directory. TODO: Not sure if - * relevant for workers - *
  • `[--rules-dir {rule_dir}]*` Additional custom directories in which to search for the - * specified rules - *
  • `[-U]` Whether to consider project sources recursively. Not relevant for worker, as - * files to consider are explicitly given by the driver. - *
  • `-files {path}` A path to a temporary file generated by the driver, which contains the - * list of unit names that this worker should be processing during its run. - *
  • `[-Xvar=val]*` The GPR scenario variables to use when loading the project file - *
  • `-rules` No-op. - *
  • `-from {path}` A path to a temporary file generated by the driver, which contains the - * list of rule specifications (to be parsed) that this worker should use during its run - *
  • `-from-lkql {path}` A path to an LKQL file which contains the list of rule - * specifications (to be parsed) that this worker should use during its run - *
- * - * @param arguments The arguments to parse. - * @param polyglotOptions The polyglot options. - * @return The unrecognized options. - */ - @Override - protected List preprocessArguments( - List arguments, Map polyglotOptions) { - // Iterate over arguments and parse them - ListIterator iterator = arguments.listIterator(); - String currentArg = iterator.next(); - - // First argument should be "--subprocess" - - assert currentArg.equals("--subprocess"); - currentArg = iterator.next(); - - // Optional argument: project file - if (currentArg.startsWith("-P")) { - this.projectFile = currentArg.substring(2); - currentArg = iterator.next(); - - if (currentArg.equals("--ignore-project-switches")) { - currentArg = iterator.next(); - } - } - - // TODO: handle "--simple-project" - - if (currentArg.equals("--simple-project")) { - currentArg = iterator.next(); - this.projectFile = null; - this.isSimpleProject = true; - } - - if (currentArg.equals("-A")) { - // Use the specified aggregated project (`projectFile` holds the aggregate project) - this.subprojectFile = iterator.next(); - - // TODO: handle "-o=..." and "-ox=..." - iterator.next(); - - currentArg = iterator.next(); - } - - // TODO: handle "--RTS" - - // TODO: handle "--target" - - if (currentArg.equals("-d")) { - this.debug = true; - currentArg = iterator.next(); - } - - // TODO: handle "-eL" - - // TODO: handle "--no_objects_dir" - - StringBuilder rulesDirs = new StringBuilder(); - while (currentArg.startsWith("--rules-dir=")) { - rulesDirs.append(currentArg.substring(12)); - rulesDirs.append(File.pathSeparator); - currentArg = iterator.next(); - } - this.rulesDirs = rulesDirs.toString(); - - if (currentArg.equals("-U")) { - this.recursive = true; - currentArg = iterator.next(); - } - - while (!currentArg.startsWith("-files=")) { - // ignore all files specified after -U: they are already specified by "-files=" - currentArg = iterator.next(); - } - - assert currentArg.startsWith("-files="); - this.filesFrom = currentArg.substring(7); - currentArg = iterator.next(); - - // Encode scenario variables specifications (key=value) in Base64 in order to escape `value` - // which can - // contain arbitrary characters. Join them with the semicolon character (which cannot appear - // in - // a Base64-encoded - // string). - StringBuilder scenarioVars = new StringBuilder(); - Base64.Encoder encoder = Base64.getEncoder(); - while (currentArg.startsWith("-X")) { - String binding = currentArg.substring(2); - scenarioVars.append(new String(encoder.encode(binding.getBytes()))); - scenarioVars.append(";"); - currentArg = iterator.next(); - } - this.scenarioVars = scenarioVars.toString(); - - // Parse the rules configuration options - assert currentArg.equals("-rules"); - - while (iterator.hasNext()) { - currentArg = iterator.next(); - if (currentArg.startsWith("-from=")) { - this.rulesFrom = currentArg.substring(6); - } else if (currentArg.startsWith("-from-lkql=")) { - this.rulesFromLKQL = currentArg.substring(11); - } - } - - final List unrecognizedArgs = new ArrayList<>(); - unrecognizedArgs.add("--experimental-options"); - unrecognizedArgs.add("--engine.Compilation=false"); - while (iterator.hasNext()) { - unrecognizedArgs.add(iterator.next()); - } - return unrecognizedArgs; - } - - /** - * Parse the given GNATcheck rule specification file and fill in the list of rules and rule - * arguments accordingly. - * - *

The file is expected to have one rule specification per line. - * - * @param filename The filename containing the rule specifications for this run. - * @param allRules The list in which to add all parsed rules. - * @param allArgs The list in which to add all parsed rule arguments. - */ - private static void processRuleSpecificationFile( - String filename, List allRules, List allArgs) { - try { - for (String ruleSpec : Files.readAllLines(Paths.get(filename))) { - processRuleSpecification(ruleSpec, allRules, allArgs); - } - } catch (IOException e) { - System.err.println("Could not read file: " + filename); - } - } - - /** - * Parse the given GNATcheck rule specification and add it to the list of rules to run. - * - *

A GNATcheck rule specification can also specify arguments for that rule, so these are - * parsed as well and added to the list of rule arguments. - * - * @param ruleSpec The rule specification to parse. - * @param allRules The list of all currently parsed rules, in which we'll add this one. - * @param allArgs The list of all currently specified rule arguments, which might be expanded - * here. - */ - private static void processRuleSpecification( - String ruleSpec, List allRules, List allArgs) { - if (ruleSpec.startsWith("-")) { - String ruleName = allRules.get(allRules.size() - 1); - String arg = ruleSpec.substring(1); - allArgs.add(ruleName + "." + arg); - } else { - allRules.add(ruleSpec); - } - } - - // ----- The LKQL checker ----- - - public static final String checkerSource = - """ - val analysis_units = specified_units() - val roots = [unit.root for unit in analysis_units] - - map(roots, (root) => node_checker(root)) - map(analysis_units, (unit) => unit_checker(unit)) - """; -} diff --git a/lkql_jit/launcher/pom.xml b/lkql_jit/launcher/pom.xml deleted file mode 100644 index a6d3d92d0..000000000 --- a/lkql_jit/launcher/pom.xml +++ /dev/null @@ -1,97 +0,0 @@ - - - 4.0.0 - - - lkql_jit - com.adacore - 0.1.0 - - - launcher - - - - - - org.apache.maven.plugins - maven-jar-plugin - 3.3.0 - - - - com.adacore.lkql_jit.LKQLLauncher - - - - - - - - org.apache.maven.plugins - maven-shade-plugin - 3.1.1 - - - package - - shade - - - lkql_jit_launcher - - - org.graalvm.sdk:launcher-common - - - - - *:* - - META-INF/*.SF - META-INF/*.DSA - META-INF/*.RSA - META-INF/*.DES - - - - - - - - - - - com.diffplug.spotless - spotless-maven-plugin - 2.40.0 - - true - - - - - - - - org.graalvm.sdk - graal-sdk - ${graalvm.version} - - - - org.graalvm.sdk - launcher-common - ${graalvm.version} - - - - com.adacore - language - ${project.parent.version} - - - - \ No newline at end of file diff --git a/lkql_jit/launcher/src/main/java/com/adacore/lkql_jit/LKQLLauncher.java b/lkql_jit/launcher/src/main/java/com/adacore/lkql_jit/LKQLLauncher.java deleted file mode 100644 index 2fa3b86ad..000000000 --- a/lkql_jit/launcher/src/main/java/com/adacore/lkql_jit/LKQLLauncher.java +++ /dev/null @@ -1,389 +0,0 @@ -/*---------------------------------------------------------------------------- --- L K Q L J I T -- --- -- --- Copyright (C) 2022-2023, AdaCore -- --- -- --- This library is free software; you can redistribute it and/or modify it -- --- under terms of the GNU General Public License as published by the Free -- --- Software Foundation; either version 3, or (at your option) any later -- --- version. This library is distributed in the hope that it will be useful, -- --- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- --- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- --- -- --- As a special exception under Section 7 of GPL version 3, you are granted -- --- additional permissions described in the GCC Runtime Library Exception, -- --- version 3.1, as published by the Free Software Foundation. -- --- -- --- You should have received a copy of the GNU General Public License and -- --- a copy of the GCC Runtime Library Exception along with this program; -- --- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- --- -- -----------------------------------------------------------------------------*/ - -package com.adacore.lkql_jit; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import org.graalvm.launcher.AbstractLanguageLauncher; -import org.graalvm.options.OptionCategory; -import org.graalvm.polyglot.Context; -import org.graalvm.polyglot.Source; -import org.graalvm.polyglot.Value; - -/** - * This class is the LKQL launcher, this will handle all execution request coming from the command - * line. - * - * @author Hugo GUERRIER - *

TODO : Support all features of the original LKQL Ada implementation - */ -public class LKQLLauncher extends AbstractLanguageLauncher { - - // ----- Macros and enums ----- - - /** Represents the status of an argument. */ - protected enum ArgumentStatus { - Consumed, - Unhandled, - Malformed, - ExpectInt - } - - /** The identifier of the LKQL language. */ - private static final String ID = "lkql"; - - // ----- Launcher options ----- - - /** The charset to decode the LKQL sources. */ - private String charset = null; - - /** The project file to analyse. */ - private String projectFile = null; - - /** Source files to analyse. */ - private final List files = new ArrayList<>(); - - /** If the project analysis should be recursive. */ - private boolean recursive = false; - - /** Number of parallel jobs. */ - private int jobs = 0; - - /** The LKQL script to evaluate. */ - private String script = null; - - // ----- JIT options ----- - - /** If the verbose mode should be activated. */ - private boolean verbose = false; - - // ----- Launcher methods ----- - - /** - * Display the help message for the LKQL language. - * - * @param maxCategory The option category. - */ - @Override - protected void printHelp(OptionCategory maxCategory) { - System.out.println( - """ - usage : lkql_jit [options ...] files [files ...] [--script|-S SCRIPT_PATH] - - The LKQL JIT compiler - - Positional arguments : - files : Files to analyse - - Basic options: - --charset, -C Charset to use for the source decoding - --project, -P Project file to use - --recursive, -U Process all units in the project tree, excluding - externally built projects - --jobs, -j Number of parallel jobs to use. If zero, use the - maximal parallelism : one job per CPU - --script-path, -S Path of the LKQL script to evaluate - - --verbose, -v Enable the verbose mode - """); - } - - /** - * Simply return the language id. - * - * @return The language id. - */ - @Override - protected String getLanguageId() { - return ID; - } - - /** - * Start the LKQL launcher. - * - * @param args The program args. - */ - public static void main(String[] args) { - new LKQLLauncher().launch(args); - } - - /** - * The entry point of the launcher with the context builder. - * - * @param contextBuilder The context builder. - */ - @Override - protected void launch(Context.Builder contextBuilder) { - int exitCode = this.executeScript(contextBuilder); - if (exitCode != 0) { - throw this.abort((String) null, exitCode); - } - } - - /** - * Execute the LKQL script and return the exit code. - * - * @param contextBuilder The context builder. - * @return The exit code of the script. - */ - protected int executeScript(Context.Builder contextBuilder) { - // Set the builder common options - contextBuilder.allowIO(true); - - // Set the context options - if (this.verbose) { - System.out.println("=== LKQL JIT is in verbose mode ==="); - contextBuilder.option("lkql.verbose", "true"); - } - - // Set the project file - if (this.projectFile != null) { - contextBuilder.option("lkql.projectFile", this.projectFile); - } - - // Set the files - if (!this.files.isEmpty()) { - contextBuilder.option("lkql.files", String.join(",", this.files)); - } - - // Set the charset - if (this.charset != null && !this.charset.isEmpty() && !this.charset.isBlank()) { - contextBuilder.option("lkql.charset", this.charset); - } - - // Create the context and run the script in it - try (Context context = contextBuilder.build()) { - final Source source = Source.newBuilder("lkql", new File(this.script)).build(); - final Value executable = context.parse(source); - executable.executeVoid(false); - return 0; - } catch (IOException e) { - System.err.println("File not found : " + this.script); - return 2; - } catch (Exception e) { - if (this.verbose) { - e.printStackTrace(); - } else { - System.err.println(e.getMessage()); - } - return 0; - } - } - - // ----- Argument parsing methods ----- - - /** - * Parse the command line arguments and return the unrecognized options to parse it with the - * default parser. - * - * @param arguments The arguments to parse. - * @param polyglotOptions The polyglot options. - * @return The unrecognized options. - */ - @Override - protected List preprocessArguments( - List arguments, Map polyglotOptions) { - // Prepare the list to return - final List unrecognizedArguments = new ArrayList<>(); - - // Iterate over arguments and parse them - ListIterator iterator = arguments.listIterator(); - while (iterator.hasNext()) { - String curArg = iterator.next(); - - // Test if the arg is a flag - if (curArg.startsWith("-") && curArg.length() >= 2 && !curArg.equals("--")) { - - // Get the flag name - String flag; - if (curArg.startsWith("--")) { - flag = curArg.substring(2); - } else { - flag = this.expandShortFlag(curArg.substring(1)); - } - - // If the flag is not null - if (flag != null) { - - // Test if the flag is a solo one - if (processFlag(flag) == ArgumentStatus.Consumed) { - continue; - } - - // Else try to process it with the value - String value; - if (iterator.hasNext()) { - value = iterator.next(); - } else { - value = null; - } - - // Try to consume the flag - switch (this.processFlag(flag, value)) { - case Consumed -> { - continue; - } - case Malformed -> throw this.abort("Missing value for " + curArg); - case ExpectInt -> throw this.abort("Expected integer value for " + curArg); - } - - // Reset the iterator - if (value != null) { - iterator.previous(); - } - } - - // If all fail, add the argument to the unrecognized arg - unrecognizedArguments.add(curArg); - } - - // Else simply add it to the files - else { - this.files.add(curArg); - } - } - - // Return the list of unrecognized arguments - return unrecognizedArguments; - } - - /** - * Expand a short flag into a long flag. - * - * @param shortFlag The short flag. - * @return The long flag value. - */ - protected String expandShortFlag(String shortFlag) { - return switch (shortFlag) { - case "C" -> "charset"; - case "P" -> "project"; - case "U" -> "recursive"; - case "j" -> "jobs"; - case "S" -> "script-path"; - case "v" -> "verbose"; - default -> null; - }; - } - - /** - * Process the flag without argument. - * - * @param flag The flag to process. - * @return The status of the argument parsing. - */ - protected ArgumentStatus processFlag(String flag) { - switch (flag) { - // The recursive flag - case "recursive": - this.recursive = true; - break; - - // The verbose flag - case "verbose": - this.verbose = true; - break; - - // Default behavior - default: - return ArgumentStatus.Unhandled; - } - return ArgumentStatus.Consumed; - } - - /** - * Process a flag with its argument. - * - * @param flag The flag to process. - * @param value The argument value. - * @return If the flag was consumed, unhandled or wrong. - */ - protected ArgumentStatus processFlag(String flag, String value) { - switch (flag) { - // The charset value - case "charset": - if (value == null) { - return ArgumentStatus.Malformed; - } - this.charset = value; - break; - - // The project value - case "project": - if (value == null) { - return ArgumentStatus.Malformed; - } - this.projectFile = value; - break; - - // The jobs value - case "jobs": - if (value == null) { - return ArgumentStatus.Malformed; - } - try { - this.jobs = Integer.parseInt(value); - } catch (Exception e) { - return ArgumentStatus.ExpectInt; - } - break; - - // The script flag - case "script-path": - if (value == null) { - return ArgumentStatus.Malformed; - } - this.script = value; - break; - - // The default unhandled flag - default: - return ArgumentStatus.Unhandled; - } - return ArgumentStatus.Consumed; - } - - /** - * Validate the state of the launcher after argument parsing. - * - * @param polyglotOptions The polyglot options. - */ - @Override - protected void validateArguments(Map polyglotOptions) { - // Launch the super validation - super.validateArguments(polyglotOptions); - - // Verify the project file - if (files.isEmpty() && (this.projectFile == null || this.projectFile.isEmpty())) { - throw this.abort("Please provide files or a project file to analyze"); - } - - // Verify the script file - if (this.script == null || this.script.isEmpty()) { - throw this.abort("Please provide a script file to evaluate"); - } - } -} diff --git a/lkql_jit/checker/pom.xml b/lkql_jit/lkql_cli/pom.xml similarity index 73% rename from lkql_jit/checker/pom.xml rename to lkql_jit/lkql_cli/pom.xml index 096e6d190..675be7489 100644 --- a/lkql_jit/checker/pom.xml +++ b/lkql_jit/lkql_cli/pom.xml @@ -10,7 +10,7 @@ 0.1.0 - checker + lkql_cli @@ -22,7 +22,7 @@ - com.adacore.lkql_jit.LKQLChecker + com.adacore.lkql_jit.LKQLMain @@ -40,10 +40,11 @@ shade - lkql_jit_checker + lkql_cli org.graalvm.sdk:launcher-common + info.picocli:picocli @@ -62,6 +63,7 @@ + com.diffplug.spotless @@ -71,10 +73,36 @@ true + + + org.apache.maven.plugins + maven-compiler-plugin + + 3.5 + + + + info.picocli + picocli-codegen + 4.7.5 + + + + -Aproject=${project.groupId}/${project.artifactId} + + + + + + info.picocli + picocli + 4.7.5 + + org.graalvm.sdk graal-sdk @@ -94,4 +122,4 @@ - \ No newline at end of file + diff --git a/lkql_jit/lkql_cli/src/main/java/com/adacore/lkql_jit/GNATCheckWorker.java b/lkql_jit/lkql_cli/src/main/java/com/adacore/lkql_jit/GNATCheckWorker.java new file mode 100644 index 000000000..79473099b --- /dev/null +++ b/lkql_jit/lkql_cli/src/main/java/com/adacore/lkql_jit/GNATCheckWorker.java @@ -0,0 +1,336 @@ +/*---------------------------------------------------------------------------- +-- L K Q L J I T -- +-- -- +-- Copyright (C) 2022-2023, AdaCore -- +-- -- +-- This library is free software; you can redistribute it and/or modify it -- +-- under terms of the GNU General Public License as published by the Free -- +-- Software Foundation; either version 3, or (at your option) any later -- +-- version. This library is distributed in the hope that it will be useful, -- +-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- +-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- -- +----------------------------------------------------------------------------*/ + +package com.adacore.lkql_jit; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.*; +import java.util.concurrent.Callable; +import org.graalvm.launcher.AbstractLanguageLauncher; +import org.graalvm.options.OptionCategory; +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Source; +import org.graalvm.polyglot.Value; +import picocli.CommandLine; + +/** + * Implement a worker process for the GNATcheck driver. + * + * @author Romain BEGUET + */ +public class GNATCheckWorker extends AbstractLanguageLauncher { + + Args args = null; + + @CommandLine.Command( + name = "gnatcheck_worker", + description = "Internal driver meant to be called by GNATcheck. Not for public use") + public static class Args implements Callable { + @CommandLine.Unmatched public List unmatched; + + @CommandLine.Option( + names = {"-C", "--charset"}, + description = "Charset to use for the source decoding") + public String charset = null; + + @CommandLine.Option(names = "--RTS", description = "Runtime to use (not handled yet)") + public String RTS = null; + + @CommandLine.Option(names = "--target", description = "Runtime to use (not handled yet)") + public String target = null; + + @CommandLine.Option( + names = {"-v", "--verbose"}, + description = "Enable the verbose mode") + public boolean verbose; + + @CommandLine.Option( + names = {"-P", "--project"}, + description = "Project file to use") + public String project = null; + + @CommandLine.Option( + names = "-A", + description = + "The name of the subproject to analyse, if any. This implies that" + + " `projectFile` designates an aggregate project.") + public String subProject = null; + + @CommandLine.Option(names = "-d", description = "Enable the debug mode") + public boolean debug; + + @CommandLine.Option(names = "-X", description = "Scenario variable") + public Map scenarioVariables = new HashMap<>(); + + @CommandLine.Option(names = "--simple-project", description = "Enable simple project mode") + public boolean isSimpleProject; + + @CommandLine.Option( + names = "--rules-dir", + description = "Additional directory in which to check for rules") + public List rulesDirs = new ArrayList<>(); + + @CommandLine.Option(names = "--rules-from", description = "The file containing the rules") + public String rulesFrom = null; + + @CommandLine.Option(names = "--files-from", description = "The file containing the files") + public String filesFrom = null; + + @CommandLine.Option(names = "--out-file", description = "The output report file") + public String outputFile = null; + + @CommandLine.Option( + names = "--ignore-project-switches", + description = + "Process all units in the project tree, excluding externally built" + + " projects") + public boolean ignore_project_switches; + + @Override + public Integer call() { + String[] unmatchedArgs; + if (this.unmatched == null) { + unmatchedArgs = new String[0]; + } else { + unmatchedArgs = this.unmatched.toArray(new String[0]); + } + new GNATCheckWorker(this).launch(unmatchedArgs); + return 0; + } + } + + public GNATCheckWorker(GNATCheckWorker.Args args) { + this.args = args; + } + + // ----- Macros and enums ----- + + /** The identifier of the LKQL language. */ + private static final String ID = "lkql"; + + // ----- Checker methods ----- + + /** + * Display the help message for the LKQL language. + * + * @param maxCategory The option category. + */ + @Override + protected void printHelp(OptionCategory maxCategory) { + System.out.println("No help!"); + } + + /** + * Simply return the language id. + * + * @return The language id. + */ + @Override + protected String getLanguageId() { + return ID; + } + + /** + * Start the GNATcheck worker. + * + * @param contextBuilder The context builder to build LKQL context. + */ + @Override + protected void launch(Context.Builder contextBuilder) { + int exitCode = this.executeScript(contextBuilder); + if (exitCode != 0) { + throw this.abort((String) null, exitCode); + } + } + + /** + * Execute the GNATcheck worker script and return the exit code. + * + * @param contextBuilder The context builder. + * @return The exit code of the script. + */ + protected int executeScript(Context.Builder contextBuilder) { + // Set the builder common options + contextBuilder.allowIO(true); + contextBuilder.option("lkql.diagnosticOutputMode", "GNATCHECK"); + + // If no rules are provided, don't do anything + contextBuilder.option("lkql.fallbackToAllRules", "false"); + + // Do not stop the worker's execution when a source file is missing + contextBuilder.option("lkql.keepGoingOnMissingFile", "true"); + + // Set the context options + if (this.args.verbose) { + contextBuilder.option("lkql.verbose", "true"); + } + + // Set the project file + if (this.args.isSimpleProject) { + contextBuilder.option("lkql.useAutoProvider", "true"); + // TODO: Add warning message since auto provider and project file are apparently + // mutually exclusive + } else { + if (this.args.project != null) { + contextBuilder.option("lkql.projectFile", this.args.project); + } + + if (this.args.subProject != null) { + contextBuilder.option("lkql.subprojectFile", this.args.subProject); + } + } + + if (this.args.debug) { + contextBuilder.option("lkql.checkerDebug", "true"); + } + + if (!this.args.scenarioVariables.isEmpty()) { + StringBuilder scenarioVars = new StringBuilder(); + Base64.Encoder encoder = Base64.getEncoder(); + this.args.scenarioVariables.forEach( + (key, val) -> { + scenarioVars.append( + new String(encoder.encode((key + "=" + val).getBytes()))); + scenarioVars.append(";"); + }); + contextBuilder.option("lkql.scenarioVars", scenarioVars.toString()); + } + + // Set the files + if (this.args.filesFrom != null) { + try { + final List lines = Files.readAllLines(Paths.get(this.args.filesFrom)); + final String files = String.join(File.pathSeparator, lines); + contextBuilder.option("lkql.files", files); + } catch (IOException e) { + System.err.println("Could not read file: " + this.args.filesFrom); + } + } + + // Set the charset + if (this.args.charset != null + && !this.args.charset.isEmpty() + && !this.args.charset.isBlank()) { + contextBuilder.option("lkql.charset", this.args.charset); + } + + // Set the rule directories + if (!this.args.rulesDirs.isEmpty()) { + contextBuilder.option( + "lkql.rulesDirs", String.join(File.pathSeparator, this.args.rulesDirs)); + } + + // Set the rule to apply + if (!this.args.rulesFrom.isEmpty()) { + if (this.args.rulesFrom.endsWith(".lkql")) { + contextBuilder.option("lkql.LKQLRuleFile", this.args.rulesFrom); + } else { + final List allRules = new ArrayList<>(); + final List allArgs = new ArrayList<>(); + processRuleSpecificationFile(this.args.rulesFrom, allRules, allArgs); + contextBuilder.option("lkql.rules", String.join(",", allRules)); + contextBuilder.option("lkql.rulesArgs", String.join(";", allArgs)); + } + } + + // Create the context and run the script in it + try (Context context = contextBuilder.build()) { + final Source source = Source.newBuilder("lkql", checkerSource, "checker.lkql").build(); + final Value executable = context.parse(source); + executable.executeVoid(true); + return 0; + } catch (Exception e) { + if (this.args.verbose) { + e.printStackTrace(); + } else { + System.err.println(e.getMessage()); + } + return 0; + } + } + + /** + * Parse the given GNATcheck rule specification file and fill in the list of rules and rule + * arguments accordingly. + * + *

The file is expected to have one rule specification per line. + * + * @param filename The filename containing the rule specifications for this run. + * @param allRules The list in which to add all parsed rules. + * @param allArgs The list in which to add all parsed rule arguments. + */ + private static void processRuleSpecificationFile( + String filename, List allRules, List allArgs) { + try { + for (String ruleSpec : Files.readAllLines(Paths.get(filename))) { + processRuleSpecification(ruleSpec, allRules, allArgs); + } + } catch (IOException e) { + System.err.println("Could not read file: " + filename); + } + } + + /** + * Parse the given GNATcheck rule specification and add it to the list of rules to run. + * + *

A GNATcheck rule specification can also specify arguments for that rule, so these are + * parsed as well and added to the list of rule arguments. + * + * @param ruleSpec The rule specification to parse. + * @param allRules The list of all currently parsed rules, in which we'll add this one. + * @param allArgs The list of all currently specified rule arguments, which might be expanded + * here. + */ + private static void processRuleSpecification( + String ruleSpec, List allRules, List allArgs) { + if (ruleSpec.startsWith("-")) { + String ruleName = allRules.get(allRules.size() - 1); + String arg = ruleSpec.substring(1); + allArgs.add(ruleName + "." + arg); + } else { + allRules.add(ruleSpec); + } + } + + protected List preprocessArguments( + List arguments, Map polyglotOptions) { + if (this.args.unmatched != null) { + return this.args.unmatched; + } else { + return new ArrayList(); + } + } + + // ----- The LKQL checker ----- + + public static final String checkerSource = + """ + val analysis_units = specified_units() + val roots = [unit.root for unit in analysis_units] + + map(roots, (root) => node_checker(root)) + map(analysis_units, (unit) => unit_checker(unit)) + """; +} diff --git a/lkql_jit/lkql_cli/src/main/java/com/adacore/lkql_jit/LKQLChecker.java b/lkql_jit/lkql_cli/src/main/java/com/adacore/lkql_jit/LKQLChecker.java new file mode 100644 index 000000000..b94fe292a --- /dev/null +++ b/lkql_jit/lkql_cli/src/main/java/com/adacore/lkql_jit/LKQLChecker.java @@ -0,0 +1,277 @@ +/*---------------------------------------------------------------------------- +-- L K Q L J I T -- +-- -- +-- Copyright (C) 2022-2023, AdaCore -- +-- -- +-- This library is free software; you can redistribute it and/or modify it -- +-- under terms of the GNU General Public License as published by the Free -- +-- Software Foundation; either version 3, or (at your option) any later -- +-- version. This library is distributed in the hope that it will be useful, -- +-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- +-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- -- +----------------------------------------------------------------------------*/ + +package com.adacore.lkql_jit; + +import java.io.File; +import java.util.*; +import java.util.concurrent.Callable; +import org.graalvm.launcher.AbstractLanguageLauncher; +import org.graalvm.options.OptionCategory; +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.PolyglotException; +import org.graalvm.polyglot.Source; +import org.graalvm.polyglot.Value; +import picocli.CommandLine; + +/** + * This class represents the LKQL checker entry point with the LKQL JIT backend. This is a TEMPORARY + * driver to perform efficiency tests on LKQL JIT in real life use case. TODO : Support all flags + * and options of the lkql_checker original implementation. + * + * @author Hugo GUERRIER + */ +public class LKQLChecker extends AbstractLanguageLauncher { + + // ----- Macros and enums ----- + + @CommandLine.Command( + name = "check", + description = + "Alternative checker driver. Like GNATcheck but with less options " + + "& a more modern command line interface") + public static class Args implements Callable { + + @CommandLine.Spec public picocli.CommandLine.Model.CommandSpec spec; + + @CommandLine.Parameters(description = "Files to analyze") + public List files = new ArrayList(); + + @CommandLine.Option( + names = {"-C", "--charset"}, + description = "Charset to use for the source decoding") + public String charset = null; + + @CommandLine.Option( + names = {"-P", "--project"}, + description = "Project file to use") + public String project = null; + + @CommandLine.Option( + names = {"-U", "--recursive"}, + description = + "Process all units in the project tree, excluding externally built" + + " projects") + public boolean recursive; + + @CommandLine.Option( + names = {"-j", "--jobs"}, + description = "Numbers of jobs to use. If zero, one job per CPU") + public int jobs = 1; + + @CommandLine.Option( + names = {"-v", "--verbose"}, + description = "Enable the verbose mode") + public boolean verbose; + + @CommandLine.Option( + names = "--rules-dir", + description = "Additional directories where rules will be sought") + public List rulesDirs = new ArrayList(); + + @CommandLine.Option( + names = {"-r", "--rule"}, + description = "Additional directories where rules will be sought") + public List rules = new ArrayList(); + + @CommandLine.Option( + names = {"-a", "--rule-arg"}, + description = + "Argument to pass to a rule, with the syntax" + + " .=") + public List rulesArgs = new ArrayList(); + + enum PropertyErrorRecoveryMode { + continueAndWarn, + continueAndLog, + raiseError + } + + @CommandLine.Option(names = "--property-error-recovery") + PropertyErrorRecoveryMode propertyErrorRecovery = PropertyErrorRecoveryMode.continueAndWarn; + + @CommandLine.Option( + names = {"-I", "--ignores"}, + description = "Ada files to ignore during analysis") + public String ignores = null; + + @CommandLine.Option( + names = "--keep-going-on-missing-file", + description = "Keep going on missing file") + public Boolean keepGoingOnMissingFile = false; + + @CommandLine.Unmatched public List unmatched; + + @Override + public Integer call() { + String[] unmatchedArgs; + if (this.unmatched == null) { + unmatchedArgs = new String[0]; + } else { + unmatchedArgs = this.unmatched.toArray(new String[0]); + } + new LKQLChecker(this).launch(unmatchedArgs); + return 0; + } + } + + public LKQLChecker(LKQLChecker.Args args) { + this.args = args; + } + + private LKQLChecker.Args args = null; + + /** The identifier of the LKQL language. */ + private static final String ID = "lkql"; + + // ----- Checker methods ----- + + /** + * Display the help message for the LKQL language. + * + * @param maxCategory The option category. + */ + @Override + protected void printHelp(OptionCategory maxCategory) { + this.args.spec.commandLine().usage(this.args.spec.commandLine().getOut()); + } + + /** + * Simply return the language id. + * + * @return The language id. + */ + @Override + protected String getLanguageId() { + return ID; + } + + /** + * Start the LQKL checker. + * + * @param contextBuilder The context builder to build LKQL context. + */ + @Override + protected void launch(Context.Builder contextBuilder) { + int exitCode = this.executeScript(contextBuilder); + if (exitCode != 0) { + throw this.abort((String) null, exitCode); + } + } + + /** + * Execute the LKQL checker script and return the exit code. + * + * @param contextBuilder The context builder. + * @return The exit code of the script. + */ + protected int executeScript(Context.Builder contextBuilder) { + // Set the builder common options + contextBuilder.allowIO(true); + + contextBuilder.option("lkql.checkerDebug", "true"); + + // Set the context options + if (this.args.verbose) { + System.out.println("=== LKQL JIT is in verbose mode ==="); + contextBuilder.option("lkql.verbose", "true"); + } + + if (this.args.keepGoingOnMissingFile) { + contextBuilder.option("lkql.keepGoingOnMissingFile", "true"); + } + + // Set the project file + if (this.args.project != null) { + contextBuilder.option("lkql.projectFile", this.args.project); + } + + // Set the files + if (!this.args.files.isEmpty()) { + contextBuilder.option("lkql.files", String.join(File.pathSeparator, this.args.files)); + } + + // Set the charset + if (this.args.charset != null + && !this.args.charset.isEmpty() + && !this.args.charset.isBlank()) { + contextBuilder.option("lkql.charset", this.args.charset); + } + + // Set the rule directories + if (!this.args.rulesDirs.isEmpty()) { + contextBuilder.option( + "lkql.rulesDirs", String.join(File.pathSeparator, this.args.rulesDirs)); + } + + // Set the rule to apply + if (!this.args.rules.isEmpty()) { + contextBuilder.option("lkql.rules", String.join(",", this.args.rules).toLowerCase()); + } + + // Set the rule argument + contextBuilder.option("lkql.rulesArgs", String.join(";", this.args.rulesArgs)); + + // Set the Ada files to ignore during the analysis + if (this.args.ignores != null) { + contextBuilder.option("lkql.ignores", this.args.ignores); + } + + // Create the context and run the script in it + try (Context context = contextBuilder.build()) { + final Source source = Source.newBuilder("lkql", checkerSource, "checker.lkql").build(); + final Value executable = context.parse(source); + executable.executeVoid(true); + return 0; + } catch (Exception e) { + if (e instanceof PolyglotException pe && pe.isExit()) { + return pe.getExitStatus(); + } else if (this.args.verbose) { + e.printStackTrace(); + } else { + System.err.println(e.getMessage()); + } + return 0; + } + } + + @Override + protected List preprocessArguments( + List arguments, Map polyglotOptions) { + if (this.args.unmatched != null) { + return this.args.unmatched; + } else { + return new ArrayList(); + } + } + + // ----- The LKQL checker ----- + + public static final String checkerSource = + """ + val analysis_units = specified_units() + val roots = [unit.root for unit in analysis_units] + + map(roots, (root) => node_checker(root)) + map(analysis_units, (unit) => unit_checker(unit)) + """; +} diff --git a/lkql_jit/lkql_cli/src/main/java/com/adacore/lkql_jit/LKQLLauncher.java b/lkql_jit/lkql_cli/src/main/java/com/adacore/lkql_jit/LKQLLauncher.java new file mode 100644 index 000000000..23e481438 --- /dev/null +++ b/lkql_jit/lkql_cli/src/main/java/com/adacore/lkql_jit/LKQLLauncher.java @@ -0,0 +1,228 @@ +/*---------------------------------------------------------------------------- +-- L K Q L J I T -- +-- -- +-- Copyright (C) 2022-2023, AdaCore -- +-- -- +-- This library is free software; you can redistribute it and/or modify it -- +-- under terms of the GNU General Public License as published by the Free -- +-- Software Foundation; either version 3, or (at your option) any later -- +-- version. This library is distributed in the hope that it will be useful, -- +-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- +-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- -- +----------------------------------------------------------------------------*/ + +package com.adacore.lkql_jit; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import org.graalvm.launcher.AbstractLanguageLauncher; +import org.graalvm.options.OptionCategory; +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Source; +import org.graalvm.polyglot.Value; +import picocli.CommandLine; + +/** + * This class is the LKQL launcher, this will handle all execution request coming from the command + * line. + * + * @author Hugo GUERRIER + *

TODO : Support all features of the original LKQL Ada implementation + */ +public class LKQLLauncher extends AbstractLanguageLauncher { + + @CommandLine.Command(name = "run", description = "Run the LKQL interpreter on a given script") + public static class LKQLRun implements Callable { + + @CommandLine.Spec public CommandLine.Model.CommandSpec spec; + + @CommandLine.Parameters(description = "Files to analyze") + public List files; + + @CommandLine.Option( + names = {"-C", "--charset"}, + description = "Charset to use for the source decoding") + public String charset = null; + + @CommandLine.Option( + names = {"-P", "--project"}, + description = "Project file to use") + public String project = null; + + @CommandLine.Option( + names = {"-U", "--recursive"}, + description = + "Process all units in the project tree, excluding externally built" + + " projects") + public boolean recursive; + + @CommandLine.Option( + names = {"-j", "--jobs"}, + description = "Numbers of jobs to use. If zero, one job per CPU") + public int jobs = 1; + + @CommandLine.Option( + names = {"-v", "--verbose"}, + description = "Enable the verbose mode") + public boolean verbose; + + @CommandLine.Unmatched public List unmatched; + + @CommandLine.Option( + names = {"-S", "--script-path"}, + description = "The LKQL script to execute") + public String script; + + @CommandLine.Option( + names = "--keep-going-on-missing-file", + description = "Keep going on missing file") + public Boolean keepGoingOnMissingFile = false; + + @Override + public Integer call() { + String[] unmatchedArgs; + if (this.unmatched == null) { + unmatchedArgs = new String[0]; + } else { + unmatchedArgs = this.unmatched.toArray(new String[0]); + } + new LKQLLauncher(this).launch(unmatchedArgs); + return 0; + } + } + + public LKQLLauncher(LKQLRun args) { + this.args = args; + } + + private LKQLRun args = null; + + // ----- Macros and enums ----- + + /** The identifier of the LKQL language. */ + private static final String ID = "lkql"; + + // ----- Launcher methods ----- + + /** + * Display the help message for the LKQL language. + * + * @param maxCategory The option category. + */ + @Override + protected void printHelp(OptionCategory maxCategory) { + this.args.spec.commandLine().usage(this.args.spec.commandLine().getOut()); + } + + /** + * Simply return the language id. + * + * @return The language id. + */ + @Override + protected String getLanguageId() { + return ID; + } + + /** + * The entry point of the launcher with the context builder. + * + * @param contextBuilder The context builder. + */ + @Override + protected void launch(Context.Builder contextBuilder) { + int exitCode = this.executeScript(contextBuilder); + if (exitCode != 0) { + throw this.abort((String) null, exitCode); + } + } + + /** + * Execute the LKQL script and return the exit code. + * + * @param contextBuilder The context builder. + * @return The exit code of the script. + */ + protected int executeScript(Context.Builder contextBuilder) { + // Set the builder common options + contextBuilder.allowIO(true); + + // Set the context options + if (this.args.verbose) { + System.out.println("=== LKQL JIT is in verbose mode ==="); + contextBuilder.option("lkql.verbose", "true"); + } + + // Set the project file + if (this.args.project != null) { + contextBuilder.option("lkql.projectFile", this.args.project); + } + + if (this.args.keepGoingOnMissingFile) { + contextBuilder.option("lkql.keepGoingOnMissingFile", "true"); + } + + // Set the files + if (this.args.files != null) { + contextBuilder.option("lkql.files", String.join(",", this.args.files)); + } + + // Set the charset + if (this.args.charset != null + && !this.args.charset.isEmpty() + && !this.args.charset.isBlank()) { + contextBuilder.option("lkql.charset", this.args.charset); + } + + // Create the context and run the script in it + try (Context context = contextBuilder.build()) { + final Source source = Source.newBuilder("lkql", new File(this.args.script)).build(); + final Value executable = context.parse(source); + executable.executeVoid(false); + return 0; + } catch (IOException e) { + System.err.println("File not found : " + this.args.script); + return 2; + } catch (Exception e) { + if (this.args.verbose) { + e.printStackTrace(); + } else { + System.err.println(e.getMessage()); + } + return 0; + } + } + + // ----- Argument parsing methods ----- + + /** + * Parse the command line arguments and return the unrecognized options to parse it with the + * default parser. + * + * @param arguments The arguments to parse. + * @param polyglotOptions The polyglot options. + * @return The unrecognized options. + */ + @Override + protected List preprocessArguments( + List arguments, Map polyglotOptions) { + if (this.args.unmatched != null) { + return this.args.unmatched; + } else { + return new ArrayList(); + } + } +} diff --git a/lkql_jit/lkql_cli/src/main/java/com/adacore/lkql_jit/LKQLMain.java b/lkql_jit/lkql_cli/src/main/java/com/adacore/lkql_jit/LKQLMain.java new file mode 100644 index 000000000..4674ec676 --- /dev/null +++ b/lkql_jit/lkql_cli/src/main/java/com/adacore/lkql_jit/LKQLMain.java @@ -0,0 +1,54 @@ +/*---------------------------------------------------------------------------- +-- L K Q L J I T -- +-- -- +-- Copyright (C) 2022-2023, AdaCore -- +-- -- +-- This library is free software; you can redistribute it and/or modify it -- +-- under terms of the GNU General Public License as published by the Free -- +-- Software Foundation; either version 3, or (at your option) any later -- +-- version. This library is distributed in the hope that it will be useful, -- +-- but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHAN- -- +-- TABILITY or FITNESS FOR A PARTICULAR PURPOSE. -- +-- -- +-- As a special exception under Section 7 of GPL version 3, you are granted -- +-- additional permissions described in the GCC Runtime Library Exception, -- +-- version 3.1, as published by the Free Software Foundation. -- +-- -- +-- You should have received a copy of the GNU General Public License and -- +-- a copy of the GCC Runtime Library Exception along with this program; -- +-- see the files COPYING3 and COPYING.RUNTIME respectively. If not, see -- +-- -- +----------------------------------------------------------------------------*/ + +package com.adacore.lkql_jit; + +import java.util.concurrent.Callable; +import picocli.CommandLine; +import picocli.CommandLine.Command; + +@Command( + mixinStandardHelpOptions = true, + name = "lkql", + synopsisSubcommandLabel = "COMMAND", + subcommands = { + LKQLLauncher.LKQLRun.class, + LKQLChecker.Args.class, + GNATCheckWorker.Args.class + }, + description = + "Unified driver for LKQL (Langkit query language). Allows you to run LKQL " + + "scripts or apply specific checks on a given Ada codebase") +public class LKQLMain implements Callable { + + @CommandLine.Spec CommandLine.Model.CommandSpec spec; + + @Override + public Integer call() throws Exception { + throw new CommandLine.ParameterException(spec.commandLine(), "Missing required subcommand"); + } + + public static void main(String[] args) { + int rc = new CommandLine(new LKQLMain()).execute(args); + System.exit(rc); + } +} diff --git a/lkql_jit/native/make.py b/lkql_jit/native/make.py index ab252334d..45f3e4e79 100644 --- a/lkql_jit/native/make.py +++ b/lkql_jit/native/make.py @@ -57,9 +57,9 @@ args = parse_args() # Get the components to build - build_launcher = "launcher" in args.native_components build_checker = "checker" in args.native_components build_worker = "gnatcheck_worker" in args.native_components + build_lkql = "lkql_cli" in args.native_components # Create the common command cmd = [ @@ -74,6 +74,8 @@ if args.build_mode in ("dev", "debug"): cmd.extend( [ + "-g", + "-O0", "-H:-DeleteLocalSymbols", "-H:+SourceLevelDebug", "-H:+PreserveFramePointer", @@ -90,18 +92,11 @@ for name, do_native_build, jar_filename, exe_name, class_name in [ ( - "launcher", - build_launcher, - P.join("..", "launcher", "target", "lkql_jit_launcher.jar"), - "native_lkql_jit", - "LKQLLauncher", - ), - ( - "checker", - build_checker, - P.join("..", "checker", "target", "lkql_jit_checker.jar"), - "native_lkql_jit_checker", - "LKQLChecker", + "checker", + build_checker, + P.join("..", "checker", "target", "lkql_jit_checker.jar"), + "native_lkql_jit_checker", + "LKQLChecker" ), ( "gnatcheck_worker", @@ -110,6 +105,13 @@ "native_gnatcheck_worker", "GNATCheckWorker", ), + ( + "lkql_cli", + build_lkql, + P.join("..", "lkql_cli", "target", "lkql_cli.jar"), + "lkql", + "LKQLMain" + ), ]: if do_native_build: if not P.isfile(jar_filename): diff --git a/lkql_jit/pom.xml b/lkql_jit/pom.xml index 278840161..4398a8b46 100644 --- a/lkql_jit/pom.xml +++ b/lkql_jit/pom.xml @@ -10,9 +10,7 @@ 0.1.0 language - launcher - checker - gnatcheck_worker + lkql_cli native component @@ -46,30 +44,9 @@ - native-checker + native - checker - - - - - native-launcher - - launcher - - - - - native-gnatcheck_worker - - gnatcheck_worker - - - - - native-all - - launcher checker gnatcheck_worker + lkql_cli @@ -143,10 +120,8 @@ - checker/src/main/java/**/*.java - gnatcheck_worker/src/main/java/**/*.java language/src/main/java/**/*.java - launcher/src/main/java/**/*.java + lkql_cli/src/main/java/**/*.java diff --git a/testsuite/drivers/base_driver.py b/testsuite/drivers/base_driver.py index 5a5dd819a..c95e5ad2c 100644 --- a/testsuite/drivers/base_driver.py +++ b/testsuite/drivers/base_driver.py @@ -431,12 +431,12 @@ def _define_lkql_executables(self) -> None: if self.env.options.mode == "jit": python_wrapper = P.join(self.env.support_dir, "lkql_jit.py") command_base = [sys.executable, python_wrapper] - self.lkql_exe = [*command_base, "launcher"] - self.lkql_checker_exe = [*command_base, "checker"] - self.gnatcheck_worker_exe = [*command_base, "gnatcheck_worker"] + self.lkql_exe = [*command_base, "lkql", "run"] + self.lkql_checker_exe = [*command_base, "lkql", "check"] + self.gnatcheck_worker_exe = [*command_base, "lkql", "gnatcheck_worker"] # If the mode is native JIT elif self.env.options.mode == "native_jit": - self.lkql_exe = ["native_lkql_jit"] - self.lkql_checker_exe = ["native_lkql_jit_checker"] - self.gnatcheck_worker_exe = ["native_gnatcheck_worker"] + self.lkql_exe = ["lkql", "run"] + self.lkql_checker_exe = ["lkql", "check"] + self.gnatcheck_worker_exe = ["lkql", "gnatcheck_worker"] diff --git a/testsuite/drivers/checker_driver.py b/testsuite/drivers/checker_driver.py index 7ff4a43dd..36682292a 100644 --- a/testsuite/drivers/checker_driver.py +++ b/testsuite/drivers/checker_driver.py @@ -40,7 +40,7 @@ def run(self) -> None: args += ['--rule-arg', '{}={}'.format(k, v)] args += ['-r', self.test_env['rule_name']] - args += ['--rules-dirs', self.test_env['test_dir']] + args += ['--rules-dir', self.test_env['test_dir']] args += ['--keep-going-on-missing-file'] # Run the checker diff --git a/testsuite/python_support/lkql_jit.py b/testsuite/python_support/lkql_jit.py index 986120c0b..20f45ed0e 100644 --- a/testsuite/python_support/lkql_jit.py +++ b/testsuite/python_support/lkql_jit.py @@ -9,16 +9,12 @@ # Jar for each LKQL JIT entry point jars = { - "launcher": "lkql_jit_launcher.jar", - "checker": "lkql_jit_checker.jar", - "gnatcheck_worker": "gnatcheck_worker.jar" + "lkql": "lkql_cli.jar" } # Main class for each LKQL JIT entry point main_classes = { - "launcher": "LKQLLauncher", - "checker": "LKQLChecker", - "gnatcheck_worker": "GNATCheckWorker" + "lkql": "LKQLMain" } def get_java_command(entry_point: str) -> list[str]: @@ -68,9 +64,7 @@ def get_java_command(entry_point: str) -> list[str]: description=__doc__) subparsers = parser.add_subparsers(help="LKQL JIT entry point", required=True) for subcommand, help in [ - ("launcher", "Use LKQL JIT in normal mode."), - ("checker", "Use the LKQL JIT checker driver."), - ("gnatcheck_worker", "Use the LKQL JIT GNATcheck worker (this should be only used by GNATcheck).") + ("lkql", "Main entry point for LKQL") ]: subp = subparsers.add_parser(subcommand, help=help) subp.set_defaults(subc=subcommand) diff --git a/testsuite/tests/miscellaneous/wildcard_matching/test.out b/testsuite/tests/miscellaneous/wildcard_matching/test.out index 66d428170..133174e42 100644 --- a/testsuite/tests/miscellaneous/wildcard_matching/test.out +++ b/testsuite/tests/miscellaneous/wildcard_matching/test.out @@ -1,4 +1,3 @@ -No source file to process foo matches foo foo does not match *fo foo matches *foo diff --git a/utils/lkql.vim b/utils/lkql.vim index fe68d1500..5c1ab4541 100644 --- a/utils/lkql.vim +++ b/utils/lkql.vim @@ -48,3 +48,6 @@ hi def link lkqlGrammarRule Define hi def link lkqlLiteral Number hi def link lkqlComment Comment hi def link lkqlBlockString String + +set comments=b:#,b:\|\" " lkql block strings treated like comments for formatting +set formatoptions += crno " Automatically wrap, and insert comment lead on newline