All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax0.jamal.engine.ScriptMacro Maven / Gradle / Ivy

package javax0.jamal.engine;

import javax0.jamal.api.BadSyntax;
import javax0.jamal.api.BadSyntaxAt;
import javax0.jamal.tools.OptionsStore;
import javax0.jamal.tools.ScriptingTools;

import static javax0.jamal.tools.ScriptingTools.getEngine;
import static javax0.jamal.tools.ScriptingTools.populate;
import static javax0.jamal.tools.ScriptingTools.resultToString;

/**
 * Stores the information about a user defined macro and can also evaluate it using actual parameter string values.
 */
public class ScriptMacro implements javax0.jamal.api.ScriptMacro {
    final private String id;
    final private Processor processor;
    final private OptionsStore optionsStore;
    final private String content;
    final private String scriptType;
    final ArgumentHandler argumentHandler;
    final private boolean isJShell;

    /**
     * Creates a new user defined macro.
     *
     * @param processor  is the context of the evaluation. Through this object a macro can access the evaluation
     *                   environment.
     * @param id         the identifier of the macro. This is the string that stands after the {@code define} keyword
     *                   when the user defined macro is defined. This is a unique identified in the context where the
     *                   macro is reachable and usable.
     * @param scriptType the type of the script. The scripting engine with this name is used to execute the content. The
     *                   value {@code jamal} means that content has to be interpreted by Jamal itself.
     * @param content    the text of the macro that stands after the {@code =} character and before the macro closing
     *                   character.
     * @param parameters the names of the parameters. These do not actually need to be real identifiers, alphanumeric or
     *                   something like that. The only requirement is that there is no comma in these names. It is
     *                   recommended though to use usual identifiers.
     */
    public ScriptMacro(Processor processor, String id, String scriptType, String content, String... parameters) throws BadSyntax {
        this.processor = processor;
        this.optionsStore = OptionsStore.getInstance(processor);
        this.scriptType = scriptType;
        this.id = id;
        this.content = content;
        argumentHandler = new ArgumentHandler(this, parameters);
        isJShell = scriptType.equals("JShell");
    }

    /**
     * Get the name / identifier of the user defined macro.
     *
     * @return the id.
     */
    @Override
    public String getId() {
        return id;
    }

    /**
     * Evaluate the content of the user defined macro using the actual values for the parameter values.
     *
     * @param parameters the actual string values for the parameters
     * @return the string that is the result of the evaluation
     * @throws BadSyntaxAt if the user defined macro is a script and the script evaluation throws exception. This
     *                     exception is thrown if the number of the actual values is not the same as the number of the
     *                     parameters.
     */
    @Override
    public String evaluate(final String... parameters) throws BadSyntax {
        final var adjustedValues = argumentHandler.adjustActualValues(parameters, optionsStore.is(Processor.LENIENT));
        if (isJShell) {
            final var shell = processor.getJShellEngine();
            BadSyntax.when(shell == null, "The JShell engine is not available");
            for (int i = 0; i < argumentHandler.parameters.length; i++) {
                ScriptingTools.populateJShell(shell, argumentHandler.parameters[i], adjustedValues[i]);
            }
            return shell.evaluate(content);
        } else {
            final var engine = getEngine(scriptType);
            for (int i = 0; i < argumentHandler.parameters.length; i++) {
                populate(engine, argumentHandler.parameters[i], adjustedValues[i]);
            }
            try {
                return resultToString(ScriptingTools.evaluate(engine, content));
            } catch (Exception e) {
                throw new BadSyntax("Script '" + id + "' threw exception", e);
            }
        }
    }

    @Override
    public int expectedNumberOfArguments() {
        return argumentHandler.parameters.length;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy