diff options
Diffstat (limited to 'support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Interpreter.kt')
-rw-r--r-- | support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Interpreter.kt | 375 |
1 files changed, 0 insertions, 375 deletions
diff --git a/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Interpreter.kt b/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Interpreter.kt deleted file mode 100644 index 49cf40f1a2..0000000000 --- a/support/arara/source/src/main/kotlin/org/islandoftex/arara/model/Interpreter.kt +++ /dev/null @@ -1,375 +0,0 @@ -// SPDX-License-Identifier: BSD-3-Clause -package org.islandoftex.arara.model - -import java.io.File -import kotlin.time.ExperimentalTime -import org.islandoftex.arara.Arara -import org.islandoftex.arara.configuration.AraraSpec -import org.islandoftex.arara.localization.LanguageController -import org.islandoftex.arara.localization.Messages -import org.islandoftex.arara.ruleset.Argument -import org.islandoftex.arara.ruleset.Command -import org.islandoftex.arara.ruleset.Conditional -import org.islandoftex.arara.ruleset.Directive -import org.islandoftex.arara.ruleset.Rule -import org.islandoftex.arara.ruleset.RuleCommand -import org.islandoftex.arara.ruleset.RuleUtils -import org.islandoftex.arara.utils.CommonUtils -import org.islandoftex.arara.utils.DisplayUtils -import org.islandoftex.arara.utils.InterpreterUtils -import org.islandoftex.arara.utils.Methods -import org.mvel2.templates.TemplateRuntime -import org.slf4j.LoggerFactory - -/** - * Interprets the list of directives. - * - * @author Island of TeX - * @version 5.0 - * @since 4.0 - */ -class Interpreter( - /** - * The list of directives to be interpreted and evaluated. - */ - val directives: List<Directive> -) { - /** - * Exception class to represent that the interpreter should stop for some - * reason - */ - private class HaltExpectedException(msg: String) : Exception(msg) - - /** - * Gets the rule according to the provided directive. - * - * @param directive The provided directive. - * @return The absolute canonical path of the rule, given the provided - * directive. - * @throws AraraException Something wrong happened, to be caught in the - * higher levels. - */ - @Throws(AraraException::class) - private fun getRule(directive: Directive): File { - return InterpreterUtils.buildRulePath(directive.identifier) - ?: throw AraraException( - messages.getMessage( - Messages.ERROR_INTERPRETER_RULE_NOT_FOUND, - directive.identifier, - "(" + CommonUtils.allRulePaths - .joinToString("; ") + ")" - ) - ) - } - - // TODO: in the following, extract the printing into the higher level - // function - /** - * "Run" a boolean return value - * @param value The boolean. - * @param conditional The conditional to print in dry-run mode. - * @param authors The authors of the rule. - * @return Returns [value] - */ - private fun runBoolean( - value: Boolean, - conditional: Conditional, - authors: List<String> - ): Boolean { - logger.info(messages.getMessage(Messages.LOG_INFO_BOOLEAN_MODE, - value.toString())) - - if (Arara.config[AraraSpec.Execution.dryrun]) { - DisplayUtils.printAuthors(authors) - DisplayUtils.wrapText(messages.getMessage(Messages - .INFO_INTERPRETER_DRYRUN_MODE_BOOLEAN_MODE, - value)) - DisplayUtils.printConditional(conditional) - } - - return value - } - - /** - * Run a command - * @param command The command to run. - * @param conditional The conditional applied to the run (only for printing). - * @param authors The rule authors (only for printing). - * @param ruleCommandExitValue The exit value of the rule command. - * @return Success of the execution. - * @throws AraraException Execution failed. - */ - @ExperimentalTime - @Throws(AraraException::class) - @Suppress("TooGenericExceptionCaught") - private fun runCommand( - command: Command, - conditional: Conditional, - authors: List<String>, - ruleCommandExitValue: String? - ): Boolean { - logger.info(messages.getMessage(Messages.LOG_INFO_SYSTEM_COMMAND, - command)) - var success = true - - if (!Arara.config[AraraSpec.Execution.dryrun]) { - val code = InterpreterUtils.run(command) - val check: Any = try { - val context = mapOf<String, Any>("value" to code) - TemplateRuntime.eval( - "@{ " + (ruleCommandExitValue ?: "value == 0") + " }", - context) - } catch (exception: RuntimeException) { - throw AraraException(CommonUtils.ruleErrorHeader + - messages.getMessage(Messages - .ERROR_INTERPRETER_EXIT_RUNTIME_ERROR), - exception) - } - - success = if (check is Boolean) { - check - } else { - throw AraraException( - CommonUtils.ruleErrorHeader + messages.getMessage( - Messages.ERROR_INTERPRETER_WRONG_EXIT_CLOSURE_RETURN - ) - ) - } - } else { - DisplayUtils.printAuthors(authors) - DisplayUtils.wrapText(messages.getMessage( - Messages.INFO_INTERPRETER_DRYRUN_MODE_SYSTEM_COMMAND, - command)) - DisplayUtils.printConditional(conditional) - } - - return success - } - - /** - * Converts the command evaluation result to a flat list. - * @param result The result - * @return A flat list. - */ - private fun resultToList(result: Any) = if (result is List<*>) { - CommonUtils.flatten(result) - } else { - listOf(result) - } - - /** - * Execute a command. - * @param command The command to evaluate. - * @param conditional Under which condition to execute. - * @param rule The rule (only passed for output purposes). - * @param parameters The parameters for evaluation - * @throws AraraException Running the command failed. - */ - @ExperimentalTime - @Throws(AraraException::class) - @Suppress("TooGenericExceptionCaught", "ThrowsCount") - private fun executeCommand( - command: RuleCommand, - conditional: Conditional, - rule: Rule, - parameters: Map<String, Any> - ) { - val result: Any = try { - TemplateRuntime.eval(command.command!!, parameters) - } catch (exception: RuntimeException) { - throw AraraException(CommonUtils.ruleErrorHeader + - messages.getMessage(Messages - .ERROR_INTERPRETER_COMMAND_RUNTIME_ERROR), - exception) - } - - // TODO: check nullability - resultToList(result).filter { it.toString().isNotBlank() } - .forEach { current -> - DisplayUtils.printEntry(rule.name, command.name - ?: messages.getMessage(Messages - .INFO_LABEL_UNNAMED_TASK)) - - val success = when (current) { - is Boolean -> runBoolean(current, conditional, - rule.authors) - is Command -> runCommand(current, conditional, - rule.authors, command.exit) - else -> TODO("error: this should not happen" + - "we are only supporting boolean + command") - } - - DisplayUtils.printEntryResult(success) - - if (Arara.config[AraraSpec.Execution.haltOnErrors] && !success) - // TODO: localize - throw HaltExpectedException("Command failed") - - // TODO: document this key - val haltKey = "arara:${Arara.config[AraraSpec - .Execution.reference].name}:halt" - if (Session.contains(haltKey)) { - Arara.config[AraraSpec.Execution.status] = - Session[haltKey].toString().toInt() - // TODO: localize - throw HaltExpectedException("User requested halt") - } - } - } - - /** - * Executes each directive, throwing an exception if something bad has - * happened. - * - * @throws AraraException Something wrong happened, to be caught in the - * higher levels. - */ - @ExperimentalTime - @Throws(AraraException::class) - @Suppress("NestedBlockDepth") - fun execute() { - for (directive in directives) { - logger.info(messages.getMessage(Messages.LOG_INFO_INTERPRET_RULE, - directive.identifier)) - - Arara.config[AraraSpec.Execution.file] = - directive.parameters.getValue("reference") as File - val file = getRule(directive) - - logger.info(messages.getMessage(Messages.LOG_INFO_RULE_LOCATION, - file.parent)) - - Arara.config[AraraSpec.Execution.InfoSpec.ruleId] = - directive.identifier - Arara.config[AraraSpec.Execution.InfoSpec.rulePath] = - file.parent - Arara.config[AraraSpec.Execution.DirectiveSpec.lines] = - directive.lineNumbers - - // parse the rule identified by the directive - // (may throw an exception) - val rule = RuleUtils.parseRule(file, directive.identifier) - val parameters = parseArguments(rule, directive) - .plus(Methods.getRuleMethods()) - - val evaluator = Evaluator() - - var available = true - if (InterpreterUtils.runPriorEvaluation(directive.conditional)) { - available = evaluator.evaluate(directive.conditional) - } - - // if this directive is conditionally disabled, skip - if (!available) continue - // if not execute the commands associated with the directive - do { - rule.commands.forEach { command -> - try { - executeCommand(command, directive.conditional, rule, parameters) - } catch (_: HaltExpectedException) { - // if the user uses the halt rule to trigger - // a halt, this will be raised - return - } - } - } while (evaluator.evaluate(directive.conditional)) - } - } - - /** - * Parses the rule arguments against the provided directive. - * - * @param rule The rule object. - * @param directive The directive. - * @return A map containing all arguments resolved according to the - * directive parameters. - * @throws AraraException Something wrong happened, to be caught in the - * higher levels. - */ - @Throws(AraraException::class) - private fun parseArguments(rule: Rule, directive: Directive): - Map<String, Any> { - val arguments = rule.arguments - val unknown = CommonUtils.getUnknownKeys(directive.parameters, - arguments).minus("reference") - if (unknown.isNotEmpty()) - throw AraraException(CommonUtils.ruleErrorHeader + - messages.getMessage( - Messages.ERROR_INTERPRETER_UNKNOWN_KEYS, - "(" + unknown.joinToString(", ") + ")")) - - val resolvedArguments = mutableMapOf<String, Any>() - resolvedArguments["reference"] = directive.parameters - .getValue("reference") - - val context = mapOf( - "parameters" to directive.parameters, - "reference" to directive.parameters.getValue("reference") - ).plus(Methods.getRuleMethods()) - - arguments.forEach { argument -> - resolvedArguments[argument.identifier!!] = processArgument(argument, - directive.parameters.containsKey(argument.identifier!!), - context) - } - - return resolvedArguments - } - - /** - * Process a single argument and return the evaluated result. - * @param argument The argument to process. - * @param idInDirectiveParams Whether the argument's identifier is - * contained in the directive's parameters field. - * @param context The context for the evaluation. - * @return The result of the evaluation. - * @throws AraraException The argument could not be processed. - */ - @Throws(AraraException::class) - @Suppress("TooGenericExceptionCaught", "ThrowsCount") - private fun processArgument( - argument: Argument, - idInDirectiveParams: Boolean, - context: Map<String, Any> - ): Any { - if (argument.isRequired && !idInDirectiveParams) - throw AraraException(CommonUtils.ruleErrorHeader + - messages.getMessage( - Messages.ERROR_INTERPRETER_ARGUMENT_IS_REQUIRED, - argument.identifier!!)) - - var ret = argument.default?.let { - try { - TemplateRuntime.eval(it, context) - } catch (exception: RuntimeException) { - throw AraraException(CommonUtils.ruleErrorHeader + - messages.getMessage(Messages - .ERROR_INTERPRETER_DEFAULT_VALUE_RUNTIME_ERROR), - exception) - } - } ?: "" - - if (argument.flag != null && idInDirectiveParams) { - ret = try { - TemplateRuntime.eval(argument.flag!!, context) - } catch (exception: RuntimeException) { - throw AraraException(CommonUtils.ruleErrorHeader + messages - .getMessage(Messages - .ERROR_INTERPRETER_FLAG_RUNTIME_EXCEPTION), - exception) - } - } - - return ret - } - - companion object { - // the application messages obtained from the - // language controller - private val messages = LanguageController - - // the class logger obtained from - // the logger factory - private val logger = LoggerFactory.getLogger(Interpreter::class.java) - } -} |