Re: [commons-jexl] branch master updated: JEXL-307: tidy API (made JexlOptions a concrete non derivable class), try to ensure lexical interpretation on lexical feature, allow runtime options to be controlled through pragma (jexl.options) Task #JEXL-307 - Variable redeclaration option

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Re: [commons-jexl] branch master updated: JEXL-307: tidy API (made JexlOptions a concrete non derivable class), try to ensure lexical interpretation on lexical feature, allow runtime options to be controlled through pragma (jexl.options) Task #JEXL-307 - Variable redeclaration option

garydgregory
I do not think your changes to JexlOptions are binary compatible so -1 :-(

Gary

On Tue, Nov 12, 2019, 17:01 <[hidden email]> wrote:

> This is an automated email from the ASF dual-hosted git repository.
>
> henrib pushed a commit to branch master
> in repository https://gitbox.apache.org/repos/asf/commons-jexl.git
>
>
> The following commit(s) were added to refs/heads/master by this push:
>      new 753d6e6  JEXL-307: tidy API (made JexlOptions a concrete non
> derivable class), try to ensure lexical interpretation on lexical feature,
> allow runtime options to be controlled through pragma (jexl.options) Task
> #JEXL-307 - Variable redeclaration option
> 753d6e6 is described below
>
> commit 753d6e634d94022871b481896db78e323d7ccfed
> Author: henrib <[hidden email]>
> AuthorDate: Tue Nov 12 23:00:39 2019 +0100
>
>     JEXL-307: tidy API (made JexlOptions a concrete non derivable class),
> try to ensure lexical interpretation on lexical feature, allow runtime
> options to be controlled through pragma (jexl.options)
>     Task #JEXL-307 - Variable redeclaration option
> ---
>  .../java/org/apache/commons/jexl3/JexlBuilder.java |  21 +-
>  .../java/org/apache/commons/jexl3/JexlContext.java |  16 ++
>  .../java/org/apache/commons/jexl3/JexlEngine.java  |  10 +-
>  .../java/org/apache/commons/jexl3/JexlInfo.java    |  11 +
>  .../java/org/apache/commons/jexl3/JexlOptions.java | 223 +++++++++++++++--
>  .../org/apache/commons/jexl3/internal/Engine.java  |  68 ++++-
>  .../apache/commons/jexl3/internal/Interpreter.java |  33 ++-
>  .../commons/jexl3/internal/InterpreterBase.java    |   7 +-
>  .../org/apache/commons/jexl3/internal/Options.java | 274
> ---------------------
>  .../org/apache/commons/jexl3/internal/Script.java  |  45 +++-
>  .../jexl3/internal/TemplateInterpreter.java        |   2 +-
>  .../org/apache/commons/jexl3/AntishCallTest.java   |  15 +-
>  .../org/apache/commons/jexl3/Issues300Test.java    |  25 +-
>  .../java/org/apache/commons/jexl3/JXLTTest.java    |   3 +-
>  .../org/apache/commons/jexl3/JexlEvalContext.java  |   3 +-
>  .../org/apache/commons/jexl3/JexlTestCase.java     |   2 +-
>  .../java/org/apache/commons/jexl3/LexicalTest.java |  43 ++++
>  17 files changed, 431 insertions(+), 370 deletions(-)
>
> diff --git a/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
> b/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
> index 35c8d5f..744dfe1 100644
> --- a/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
> +++ b/src/main/java/org/apache/commons/jexl3/JexlBuilder.java
> @@ -18,7 +18,6 @@
>  package org.apache.commons.jexl3;
>
>  import org.apache.commons.jexl3.internal.Engine;
> -import org.apache.commons.jexl3.internal.Options;
>  import org.apache.commons.jexl3.introspection.JexlSandbox;
>  import org.apache.commons.jexl3.introspection.JexlUberspect;
>  import org.apache.commons.logging.Log;
> @@ -81,7 +80,7 @@ public class JexlBuilder {
>      private Boolean cancellable = null;
>
>      /** The options. */
> -    private final Options options = new Options();
> +    private final JexlOptions options = new JexlOptions();
>
>      /** Whether getVariables considers all potential equivalent syntactic
> forms. */
>      private Boolean collectAll = null;
> @@ -109,23 +108,7 @@ public class JexlBuilder {
>
>      /** The features. */
>      private JexlFeatures features = null;
> -
> -    /**
> -     * Sets the default (static, shared) option flags.
> -     * <p>
> -     * Whenever possible, we recommend using JexlBuilder methods to
> unambiguously instantiate a JEXL
> -     * engine; this method should only be used for testing / validation.
> -     * <p>A '+flag' or 'flag' will set the option named 'flag' as true,
> '-flag' set as false.
> -     * The possible flag names are:
> -     * cancellable, strict, silent, safe, lexical, antish, lexicalShade
> -     * <p>Calling JexlBuilder.setDefaultOptions("+safe") once before JEXL
> engine creation
> -     * may ease validating JEXL3.2 in your environment.
> -     * @param flags the flags to set
> -     */
> -    public static void setDefaultOptions(String...flags) {
> -        Options.setDefaultFlags(flags);
> -    }
> -
> +
>      /**
>       * Sets the JexlUberspect instance the engine will use.
>       *
> diff --git a/src/main/java/org/apache/commons/jexl3/JexlContext.java
> b/src/main/java/org/apache/commons/jexl3/JexlContext.java
> index fdc85a3..ce730f7 100644
> --- a/src/main/java/org/apache/commons/jexl3/JexlContext.java
> +++ b/src/main/java/org/apache/commons/jexl3/JexlContext.java
> @@ -159,4 +159,20 @@ public interface JexlContext {
>           */
>          JexlOptions getEngineOptions();
>      }
> +
> +    /**
> +     * A marker interface of the JexlContext that processes pragmas.
> +     * It is called by the engine before interpreter creation; as a
> marker of
> +     * JexlContext, it is expected to have access and interact with the
> context
> +     * instance.
> +     * @since 3.2
> +     */
> +    interface PragmaProcessor {
> +        /**
> +         * Process one pragma.
> +         * @param key the key
> +         * @param value the value
> +         */
> +        void processPragma(String key, Object value);
> +    }
>  }
> diff --git a/src/main/java/org/apache/commons/jexl3/JexlEngine.java
> b/src/main/java/org/apache/commons/jexl3/JexlEngine.java
> index bc41a82..7b9d198 100644
> --- a/src/main/java/org/apache/commons/jexl3/JexlEngine.java
> +++ b/src/main/java/org/apache/commons/jexl3/JexlEngine.java
> @@ -352,7 +352,7 @@ public abstract class JexlEngine {
>       * @return A {@link JexlScript} which can be executed using a {@link
> JexlContext}
>       * @throws JexlException if there is a problem parsing the script
>       */
> -    public abstract JexlScript createScript(JexlFeatures features,
> JexlInfo info, String source, String[] names);
> +    public abstract JexlScript createScript(JexlFeatures features,
> JexlInfo info, String source, String... names);
>
>      /**
>       * Creates a JexlScript from a String containing valid JEXL syntax.
> @@ -365,7 +365,7 @@ public abstract class JexlEngine {
>       * @return A {@link JexlScript} which can be executed using a {@link
> JexlContext}
>       * @throws JexlException if there is a problem parsing the script
>       */
> -    public final JexlScript createScript(JexlInfo info, String source,
> String[] names) {
> +    public final JexlScript createScript(JexlInfo info, String source,
> String... names) {
>          return createScript(null, info, source, names);
>      }
>
> @@ -378,7 +378,7 @@ public abstract class JexlEngine {
>       * @throws JexlException if there is a problem parsing the script.
>       */
>      public final JexlScript createScript(String scriptText) {
> -        return createScript(null, null, scriptText, null);
> +        return createScript(null, null, scriptText, (String[]) null);
>      }
>
>      /**
> @@ -404,7 +404,7 @@ public abstract class JexlEngine {
>       * @throws JexlException if there is a problem reading or parsing the
> script.
>       */
>      public final JexlScript createScript(File scriptFile) {
> -        return createScript(null, null, readSource(scriptFile), null);
> +        return createScript(null, null, readSource(scriptFile),
> (String[]) null);
>      }
>
>      /**
> @@ -445,7 +445,7 @@ public abstract class JexlEngine {
>       * @throws JexlException if there is a problem reading or parsing the
> script.
>       */
>      public final JexlScript createScript(URL scriptUrl) {
> -        return createScript(null, readSource(scriptUrl), null);
> +        return createScript(null, readSource(scriptUrl), (String[]) null);
>      }
>
>      /**
> diff --git a/src/main/java/org/apache/commons/jexl3/JexlInfo.java
> b/src/main/java/org/apache/commons/jexl3/JexlInfo.java
> index 19a4a72..296138b 100644
> --- a/src/main/java/org/apache/commons/jexl3/JexlInfo.java
> +++ b/src/main/java/org/apache/commons/jexl3/JexlInfo.java
> @@ -17,6 +17,8 @@
>
>  package org.apache.commons.jexl3;
>
> +import org.apache.commons.jexl3.internal.Script;
> +
>  /**
>   * Helper class to carry information such as a url/file name, line and
> column for
>   * debugging information reporting.
> @@ -182,5 +184,14 @@ public class JexlInfo {
>      public final int getColumn() {
>          return column;
>      }
> +
> +    /**
> +     * Gets the info from a script.
> +     * @param script the script
> +     * @return the info
> +     */
> +    public static JexlInfo from(JexlScript script) {
> +        return script instanceof Script? ((Script) script).getInfo() :
> null;
> +    }
>  }
>
> diff --git a/src/main/java/org/apache/commons/jexl3/JexlOptions.java
> b/src/main/java/org/apache/commons/jexl3/JexlOptions.java
> index dc35074..c650e9b 100644
> --- a/src/main/java/org/apache/commons/jexl3/JexlOptions.java
> +++ b/src/main/java/org/apache/commons/jexl3/JexlOptions.java
> @@ -18,6 +18,7 @@
>  package org.apache.commons.jexl3;
>
>  import java.math.MathContext;
> +import org.apache.commons.jexl3.internal.Engine;
>
>  /**
>   * Flags and properties that can alter the evaluation behavior.
> @@ -35,31 +36,150 @@ import java.math.MathContext;
>   * <p>This interface replaces the now deprecated JexlEngine.Options.
>   * @since 3.2
>   */
> -public interface JexlOptions {
> +public final class JexlOptions {
> +    /** The local shade bit. */
> +    private static final int SHADE = 6;
> +    /** The antish var bit. */
> +    private static final int ANTISH = 5;
> +    /** The lexical scope bit. */
> +    private static final int LEXICAL = 4;
> +    /** The safe bit. */
> +    private static final int SAFE = 3;
> +    /** The silent bit. */
> +    private static final int SILENT = 2;
> +    /** The strict bit. */
> +    private static final int STRICT = 1;
> +    /** The cancellable bit. */
> +    private static final int CANCELLABLE = 0;
> +    /** The flags names ordered. */
> +    private static final String[] NAMES = {
> +        "cancellable", "strict", "silent", "safe", "lexical", "antish",
> "lexicalShade"
> +    };
> +    /** Default mask .*/
> +    private static int DEFAULT = 1 /*<< CANCELLABLE*/ | 1 << STRICT | 1
> << ANTISH | 1 << SAFE;
> +    /** The arithmetic math context. */
> +    private MathContext mathContext = null;
> +    /** The arithmetic math scale. */
> +    private int mathScale = Integer.MIN_VALUE;
> +    /** The arithmetic strict math flag. */
> +    private boolean strictArithmetic = true;
> +    /** The default flags, all but safe. */
> +    private int flags = DEFAULT;
> +
> +    /**
> +     * Sets the value of a flag in a mask.
> +     * @param ordinal the flag ordinal
> +     * @param mask the flags mask
> +     * @param value true or false
> +     * @return the new flags mask value
> +     */
> +    private static int set(int ordinal, int mask, boolean value) {
> +        return value? mask | (1 << ordinal) : mask & ~(1 << ordinal);
> +    }
> +
> +    /**
> +     * Checks the value of a flag in the mask.
> +     * @param ordinal the flag ordinal
> +     * @param mask the flags mask
> +     * @return the mask value with this flag or-ed in
> +     */
> +    private static boolean isSet(int ordinal, int mask) {
> +        return (mask & 1 << ordinal) != 0;
> +    }
> +
> +    /**
> +     * Default ctor.
> +     */
> +    public JexlOptions() {}
> +
> +    /**
> +     * Sets the default (static, shared) option flags.
> +     * <p>
> +     * Whenever possible, we recommend using JexlBuilder methods to
> unambiguously instantiate a JEXL
> +     * engine; this method should only be used for testing / validation.
> +     * <p>A '+flag' or 'flag' will set the option named 'flag' as true,
> '-flag' set as false.
> +     * The possible flag names are:
> +     * cancellable, strict, silent, safe, lexical, antish, lexicalShade
> +     * <p>Calling JexlBuilder.setDefaultOptions("+safe") once before JEXL
> engine creation
> +     * may ease validating JEXL3.2 in your environment.
> +     * @param flags the flags to set
> +     */
> +    public static void setDefaultFlags(String...flags) {
> +        DEFAULT = parseFlags(DEFAULT, flags);
> +    }
> +
> +    /**
> +     * Parses flags by name.
> +     * <p>A '+flag' or 'flag' will set flag as true, '-flag' set as false.
> +     * The possible flag names are:
> +     * cancellable, strict, silent, safe, lexical, antish, lexicalShade
> +     * @param mask the initial mask state
> +     * @param flags the flags to set
> +     * @return the flag mask updated
> +     */
> +    public static int parseFlags(int mask, String...flags) {
> +        for(String name : flags) {
> +            boolean b = true;
> +            if (name.charAt(0) == '+') {
> +                name = name.substring(1);
> +            } else if (name.charAt(0) == '-') {
> +                name = name.substring(1);
> +                b = false;
> +            }
> +            for(int flag = 0; flag < NAMES.length; ++flag) {
> +                if (NAMES[flag].equals(name)) {
> +                    if (b) {
> +                        mask |= (1 << flag);
> +                    } else {
> +                        mask &= ~(1 << flag);
> +                    }
> +                    break;
> +                }
> +            }
> +        }
> +        return mask;
> +    }
> +
> +    /**
> +     * Sets this option flags using the +/- syntax.
> +     * @param opts the option flags
> +     */
> +    public void setFlags(String[] opts) {
> +        flags = parseFlags(flags, opts);
> +    }
> +
>      /**
>       * The MathContext instance used for +,-,/,*,% operations on big
> decimals.
>       * @return the math context
>       */
> -    MathContext getMathContext();
> +    public MathContext getMathContext() {
> +        return mathContext;
> +    }
>
>      /**
>       * The BigDecimal scale used for comparison and coercion operations.
>       * @return the scale
>       */
> -    int getMathScale();
> +    public int getMathScale() {
> +        return mathScale;
> +    }
>
>      /**
>       * Checks whether evaluation will attempt resolving antish variable
> names.
>       * @return true if antish variables are solved, false otherwise
>       */
> -    boolean isAntish();
> +    public boolean isAntish() {
> +        return isSet(ANTISH, flags);
> +    }
>
>      /**
>       * Checks whether evaluation will throw JexlException.Cancel (true) or
>       * return null (false) if interrupted.
>       * @return true when cancellable, false otherwise
>       */
> -    boolean isCancellable();
> +    public boolean isCancellable() {
> +        return isSet(CANCELLABLE, flags);
> +    }
>
>      /**
>       * Checks whether runtime variable scope is lexical.
> @@ -67,7 +187,9 @@ public interface JexlOptions {
>       * Redefining a variable in the same lexical unit will generate
> errors.
>       * @return true if scope is lexical, false otherwise
>       */
> -    boolean isLexical();
> +    public boolean isLexical() {
> +        return isSet(LEXICAL, flags);
> +    }
>
>      /**
>       * Checks whether local variables shade global ones.
> @@ -79,122 +201,169 @@ public interface JexlOptions {
>       * raise an error.
>       * @return true if lexical shading is applied, false otherwise
>       */
> -    boolean isLexicalShade();
> +    public boolean isLexicalShade() {
> +        return isSet(SHADE, flags);
> +    }
>
>      /**
>       * Checks whether the engine considers null in navigation expression
> as
>       * errors during evaluation..
>       * @return true if safe, false otherwise
>       */
> -    boolean isSafe();
> +    public boolean isSafe() {
> +        return isSet(SAFE, flags);
> +    }
>
>      /**
>       * Checks whether the engine will throw a {@link JexlException} when
> an
>       * error is encountered during evaluation.
>       * @return true if silent, false otherwise
>       */
> -    boolean isSilent();
> +    public boolean isSilent() {
> +        return isSet(SILENT, flags);
> +    }
>
>      /**
>       * Checks whether the engine considers unknown variables, methods and
>       * constructors as errors during evaluation.
>       * @return true if strict, false otherwise
>       */
> -    boolean isStrict();
> +    public boolean isStrict() {
> +        return isSet(STRICT, flags);
> +    }
>
>      /**
>       * Checks whether the arithmetic triggers errors during evaluation
> when null
>       * is used as an operand.
>       * @return true if strict, false otherwise
>       */
> -    boolean isStrictArithmetic();
> +    public boolean isStrictArithmetic() {
> +        return strictArithmetic;
> +    }
>
>      /**
>       * Sets whether the engine will attempt solving antish variable names
> from
>       * context.
>       * @param flag true if antish variables are solved, false otherwise
>       */
> -    void setAntish(boolean flag);
> +    public void setAntish(boolean flag) {
> +        flags = set(ANTISH, flags, flag);
> +    }
>
>      /**
>       * Sets whether the engine will throw JexlException.Cancel (true) or
> return
>       * null (false) when interrupted during evaluation.
>       * @param flag true when cancellable, false otherwise
>       */
> -    void setCancellable(boolean flag);
> +    public void setCancellable(boolean flag) {
> +        flags = set(CANCELLABLE, flags, flag);
> +    }
>
>      /**
>       * Sets whether the engine uses a strict block lexical scope during
>       * evaluation.
>       * @param flag true if lexical scope is used, false otherwise
>       */
> -    void setLexical(boolean flag);
> +    public void setLexical(boolean flag) {
> +        flags = set(LEXICAL, flags, flag);
> +    }
>
>      /**
>       * Sets whether the engine strictly shades global variables.
>       * Local symbols shade globals after definition and creating global
>       * variables is prohibited evaluation.
> +     * If setting to lexical shade, lexical is also set.
>       * @param flag true if creation is allowed, false otherwise
>       */
> -    void setLexicalShade(boolean flag);
> +    public void setLexicalShade(boolean flag) {
> +        flags = set(SHADE, flags, flag);
> +        if (flag) {
> +            flags = set(LEXICAL, flags, true);
> +        }
> +    }
>
>      /**
>       * Sets the arithmetic math context.
>       * @param mcontext the context
>       */
> -    void setMathContext(MathContext mcontext);
> +    public void setMathContext(MathContext mcontext) {
> +        this.mathContext = mcontext;
> +    }
>
>      /**
>       * Sets the arithmetic math scale.
>       * @param mscale the scale
>       */
> -    void setMathScale(int mscale);
> +    public void setMathScale(int mscale) {
> +        this.mathScale = mscale;
> +    }
>
>      /**
>       * Sets whether the engine considers null in navigation expression as
> errors
>       * during evaluation.
>       * @param flag true if safe, false otherwise
>       */
> -    void setSafe(boolean flag);
> +    public void setSafe(boolean flag) {
> +        flags = set(SAFE, flags, flag);
> +    }
>
>      /**
>       * Sets whether the engine will throw a {@link JexlException} when an
> error
>       * is encountered during evaluation.
>       * @param flag true if silent, false otherwise
>       */
> -    void setSilent(boolean flag);
> +    public void setSilent(boolean flag) {
> +        flags = set(SILENT, flags, flag);
> +    }
>
>      /**
>       * Sets whether the engine considers unknown variables, methods and
>       * constructors as errors during evaluation.
>       * @param flag true if strict, false otherwise
>       */
> -    void setStrict(boolean flag);
> +    public void setStrict(boolean flag) {
> +        flags = set(STRICT, flags, flag);
> +    }
>
>      /**
>       * Sets the strict arithmetic flag.
>       * @param stricta true or false
>       */
> -    void setStrictArithmetic(boolean stricta);
> +    public void setStrictArithmetic(boolean stricta) {
> +        this.strictArithmetic = stricta;
> +    }
>
>      /**
>       * Set options from engine.
>       * @param jexl the engine
>       * @return this instance
> -     */
> -    JexlOptions set(JexlEngine jexl);
> +     */
> +    public JexlOptions set(JexlEngine jexl) {
> +        if (jexl instanceof Engine) {
> +            ((Engine) jexl).optionsSet(this);
> +        }
> +        return this;
> +    }
>
>      /**
>       * Set options from options.
> -     * @param options the options
> +     * @param src the options
>       * @return this instance
>       */
> -    JexlOptions set(JexlOptions options);
> -
> +    public JexlOptions set(JexlOptions src) {
> +        mathContext = src.mathContext;
> +        mathScale = src.mathScale;
> +        strictArithmetic = src.strictArithmetic;
> +        flags = src.flags;
> +        return this;
> +    }
> +
>      /**
>       * Creates a copy of this instance.
>       * @return a copy
>       */
> -    JexlOptions copy();
> +    public JexlOptions copy() {
> +        return new JexlOptions().set(this);
> +    }
>
>  }
> \ No newline at end of file
> diff --git a/src/main/java/org/apache/commons/jexl3/internal/Engine.java
> b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
> index d752cca..4895578 100644
> --- a/src/main/java/org/apache/commons/jexl3/internal/Engine.java
> +++ b/src/main/java/org/apache/commons/jexl3/internal/Engine.java
> @@ -74,6 +74,10 @@ public class Engine extends JexlEngine {
>          private UberspectHolder() {}
>      }
>      /**
> +     * The name of the options pragma.
> +     */
> +    protected static final String PRAGMA_OPTIONS = "jexl.options";
> +    /**
>       * The Log to which all JexlEngine messages will be logged.
>       */
>      protected final Log logger;
> @@ -347,18 +351,62 @@ public class Engine extends JexlEngine {
>              cache.clear();
>          }
>      }
> -
> +
> +    /**
> +     * Sets options from this engine options.
> +     * @param opts the options to set
> +     * @return the options
> +     */
> +    public JexlOptions optionsSet(JexlOptions opts) {
> +        if (opts != null) {
> +            opts.set(options);
> +        }
> +        return opts;
> +    }
> +
> +    /**
> +     * Creates a script evaluation options.
> +     * <p>This also calls the pragma processor if any
> +     * @param script the script
> +     * @param context the context
> +     * @return the options
> +     */
> +    protected JexlOptions createOptions(Script script, JexlContext
> context) {
> +        JexlOptions opts = options(context);
> +        Map<String, Object> pragmas = script.getPragmas();
> +        if (pragmas != null) {
> +            JexlContext.PragmaProcessor processor =
> +                    context instanceof JexlContext.PragmaProcessor
> +                    ? (JexlContext.PragmaProcessor) context
> +                    : null;
> +            for(Map.Entry<String, Object> pragma : pragmas.entrySet()) {
> +                String key = pragma.getKey();
> +                Object value = pragma.getValue();
> +                if (PRAGMA_OPTIONS.equals(key) && opts != null) {
> +                    if (value instanceof String) {
> +                        String[] vs = ((String) value).split(" ");
> +                        opts.setFlags(vs);
> +                    }
> +                }
> +                if (processor != null) {
> +                    processor.processPragma(key, value);
> +                }
> +            }
> +        }
> +        return opts;
> +    }
> +
>      /**
>       * Creates an interpreter.
>       * @param context a JexlContext; if null, the empty context is used
> instead.
>       * @param frame   the interpreter frame
> +     * @param opts    the evaluation options
>       * @return an Interpreter
>       */
> -    protected Interpreter createInterpreter(JexlContext context, Frame
> frame) {
> -        return new Interpreter(this, context, frame);
> +    protected Interpreter createInterpreter(JexlContext context, Frame
> frame, JexlOptions opts) {
> +        return new Interpreter(this, opts, context, frame);
>      }
>
> -
>      @Override
>      public Script createExpression(JexlInfo info, String expression) {
>          return createScript(expressionFeatures, info, expression, null);
> @@ -371,8 +419,12 @@ public class Engine extends JexlEngine {
>          }
>          String source = trimSource(scriptText);
>          Scope scope = names == null ? null : new Scope(null, names);
> -        ASTJexlScript tree = parse(info, features == null? scriptFeatures
> : features, source, scope);
> -        return new Script(this, source, tree);
> +        JexlFeatures ftrs = features == null? scriptFeatures : features;
> +        ASTJexlScript tree = parse(info, ftrs, source, scope);
> +        // when parsing lexical, try hard to run lexical
> +        return ftrs.isLexical()
> +            ? new Script.Lexical(this, source, tree)
> +            : new Script(this, source, tree);
>      }
>
>      /**
> @@ -405,7 +457,7 @@ public class Engine extends JexlEngine {
>              final ASTJexlScript script = parse(null, PROPERTY_FEATURES,
> src, scope);
>              final JexlNode node = script.jjtGetChild(0);
>              final Frame frame = script.createFrame(bean);
> -            final Interpreter interpreter = createInterpreter(context,
> frame);
> +            final Interpreter interpreter = createInterpreter(context,
> frame, null);
>              return interpreter.visitLexicalNode(node, null);
>          } catch (JexlException xjexl) {
>              if (silent) {
> @@ -434,7 +486,7 @@ public class Engine extends JexlEngine {
>              final ASTJexlScript script = parse(null, PROPERTY_FEATURES,
> src, scope);
>              final JexlNode node = script.jjtGetChild(0);
>              final Frame frame = script.createFrame(bean, value);
> -            final Interpreter interpreter = createInterpreter(context,
> frame);
> +            final Interpreter interpreter = createInterpreter(context,
> frame, null);
>              interpreter.visitLexicalNode(node, null);
>          } catch (JexlException xjexl) {
>              if (silent) {
> diff --git
> a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
> b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
> index ed7efa7..9c27f61 100644
> --- a/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
> +++ b/src/main/java/org/apache/commons/jexl3/internal/Interpreter.java
> @@ -17,13 +17,18 @@
>  //CSOFF: FileLength
>  package org.apache.commons.jexl3.internal;
>
> +import java.util.Iterator;
> +import java.util.concurrent.Callable;
> +
>  import org.apache.commons.jexl3.JexlArithmetic;
>  import org.apache.commons.jexl3.JexlContext;
>  import org.apache.commons.jexl3.JexlEngine;
>  import org.apache.commons.jexl3.JexlException;
>  import org.apache.commons.jexl3.JexlOperator;
> +import org.apache.commons.jexl3.JexlOptions;
>  import org.apache.commons.jexl3.JexlScript;
>  import org.apache.commons.jexl3.JxltEngine;
> +
>  import org.apache.commons.jexl3.introspection.JexlMethod;
>  import org.apache.commons.jexl3.introspection.JexlPropertyGet;
>
> @@ -105,9 +110,6 @@ import
> org.apache.commons.jexl3.parser.ASTWhileStatement;
>  import org.apache.commons.jexl3.parser.JexlNode;
>  import org.apache.commons.jexl3.parser.Node;
>
> -import java.util.Iterator;
> -import java.util.concurrent.Callable;
> -
>  /**
>   * An interpreter of JEXL syntax.
>   *
> @@ -130,11 +132,12 @@ public class Interpreter extends InterpreterBase {
>      /**
>       * Creates an interpreter.
>       * @param engine   the engine creating this interpreter
> -     * @param aContext the context to evaluate expression
> -     * @param eFrame   the interpreter evaluation frame
> +     * @param aContext the evaluation context, global variables, methods
> and functions
> +     * @param opts     the evaluation options, flags modifying evaluation
> behavior
> +     * @param eFrame   the evaluation frame, arguments and local variables
>       */
> -    protected Interpreter(Engine engine, JexlContext aContext, Frame
> eFrame) {
> -        super(engine, aContext);
> +    protected Interpreter(Engine engine, JexlOptions opts, JexlContext
> aContext, Frame eFrame) {
> +        super(engine, opts, aContext);
>          this.frame = eFrame;
>      }
>
> @@ -1122,7 +1125,7 @@ public class Interpreter extends InterpreterBase {
>          JexlNode objectNode = null;
>          JexlNode ptyNode = null;
>          StringBuilder ant = null;
> -        boolean antish = !(parent instanceof ASTReference) &&
> options.isAntish();
> +        boolean antish = !(parent instanceof ASTReference);
>          int v = 1;
>          main:
>          for (int c = 0; c < numChildren; c++) {
> @@ -1172,15 +1175,21 @@ public class Interpreter extends InterpreterBase {
>                      if (first instanceof ASTIdentifier) {
>                          ASTIdentifier afirst = (ASTIdentifier) first;
>                          ant = new StringBuilder(afirst.getName());
> -                        // skip the first node case since it was trialed
> in jjtAccept above and returned null
> -                        if (c == 0) {
> -                            continue;
> -                        }
> +                        // skip the else...*
>                      } else {
>                          // not an identifier, not antish
>                          ptyNode = objectNode;
>                          break main;
>                      }
> +                    // *... and continue
> +                    if (!options.isAntish()) {
> +                        antish = false;
> +                        continue;
> +                    }
> +                    // skip the first node case since it was trialed in
> jjtAccept above and returned null
> +                    if (c == 0) {
> +                        continue;
> +                    }
>                  }
>                  // catch up to current node
>                  for (; v <= c; ++v) {
> diff --git
> a/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
> b/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
> index 74c8f8f..504c1c1 100644
> --- a/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
> +++ b/src/main/java/org/apache/commons/jexl3/internal/InterpreterBase.java
> @@ -78,16 +78,17 @@ public abstract class InterpreterBase extends
> ParserVisitor {
>      /**
>       * Creates an interpreter base.
>       * @param engine   the engine creating this interpreter
> -     * @param aContext the context to evaluate expression
> +     * @param opts     the evaluation options
> +     * @param aContext the evaluation context
>       */
> -    protected InterpreterBase(Engine engine, JexlContext aContext) {
> +    protected InterpreterBase(Engine engine, JexlOptions opts,
> JexlContext aContext) {
>          this.jexl = engine;
>          this.logger = jexl.logger;
>          this.uberspect = jexl.uberspect;
>          this.context = aContext != null ? aContext : Engine.EMPTY_CONTEXT;
>          this.cache = engine.cache != null;
>          JexlArithmetic jexla = jexl.arithmetic;
> -        this.options = jexl.options(context);
> +        this.options = opts == null? engine.options(aContext) : opts;
>          this.arithmetic = jexla.options(options);
>          if (arithmetic != jexla &&
> !arithmetic.getClass().equals(jexla.getClass())) {
>              logger.warn("expected arithmetic to be " +
> jexla.getClass().getSimpleName()
> diff --git a/src/main/java/org/apache/commons/jexl3/internal/Options.java
> b/src/main/java/org/apache/commons/jexl3/internal/Options.java
> deleted file mode 100644
> index 04dd182..0000000
> --- a/src/main/java/org/apache/commons/jexl3/internal/Options.java
> +++ /dev/null
> @@ -1,274 +0,0 @@
> -/*
> - * Licensed to the Apache Software Foundation (ASF) under one or more
> - * contributor license agreements.  See the NOTICE file distributed with
> - * this work for additional information regarding copyright ownership.
> - * The ASF licenses this file to You under the Apache License, Version 2.0
> - * (the "License"); you may not use this file except in compliance with
> - * the License.  You may obtain a copy of the License at
> - *
> - *      http://www.apache.org/licenses/LICENSE-2.0
> - *
> - * Unless required by applicable law or agreed to in writing, software
> - * distributed under the License is distributed on an "AS IS" BASIS,
> - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
> implied.
> - * See the License for the specific language governing permissions and
> - * limitations under the License.
> - */
> -
> -package org.apache.commons.jexl3.internal;
> -
> -import org.apache.commons.jexl3.JexlOptions;
> -import org.apache.commons.jexl3.JexlEngine;
> -
> -import java.math.MathContext;
> -
> -/**
> - * A basic implementation of JexlOptions.
> - * <p>Thread safety is only guaranteed if no modifications (call set*
> method)
> - * occurs in different threads; note however that using the 'callable()'
> method to
> - * allow a script to run as such will use a copy.
> - */
> -public class Options implements JexlOptions {
> -    /** The local shade bit. */
> -    protected static final int SHADE = 6;
> -    /** The antish var bit. */
> -    protected static final int ANTISH = 5;
> -    /** The lexical scope bit. */
> -    protected static final int LEXICAL = 4;
> -    /** The safe bit. */
> -    protected static final int SAFE = 3;
> -    /** The silent bit. */
> -    protected static final int SILENT = 2;
> -    /** The strict bit. */
> -    protected static final int STRICT = 1;
> -    /** The cancellable bit. */
> -    protected static final int CANCELLABLE = 0;
> -    /** The flags names ordered. */
> -    private static final String[] NAMES = {
> -        "cancellable", "strict", "silent", "safe", "lexical", "antish",
> "lexicalShade"
> -    };
> -    /** Default mask .*/
> -    protected static int DEFAULT = 1 /*<< CANCELLABLE*/ | 1 << STRICT | 1
> << ANTISH | 1 << SAFE;
> -    /** The arithmetic math context. */
> -    private MathContext mathContext = null;
> -    /** The arithmetic math scale. */
> -    private int mathScale = Integer.MIN_VALUE;
> -    /** The arithmetic strict math flag. */
> -    private boolean strictArithmetic = true;
> -    /** The default flags, all but safe. */
> -    private int flags = DEFAULT;
> -
> -    /**
> -     * Sets the value of a flag in a mask.
> -     * @param ordinal the flag ordinal
> -     * @param mask the flags mask
> -     * @param value true or false
> -     * @return the new flags mask value
> -     */
> -    protected static int set(int ordinal, int mask, boolean value) {
> -        return value? mask | (1 << ordinal) : mask & ~(1 << ordinal);
> -    }
> -
> -    /**
> -     * Checks the value of a flag in the mask.
> -     * @param ordinal the flag ordinal
> -     * @param mask the flags mask
> -     * @return the mask value with this flag or-ed in
> -     */
> -    protected static boolean isSet(int ordinal, int mask) {
> -        return (mask & 1 << ordinal) != 0;
> -    }
> -
> -    /**
> -     * Default ctor.
> -     */
> -    public Options() {}
> -
> -    /**
> -     * Sets the default flags.
> -     * <p>Used by tests to force default options.
> -     * @param flags the flags to set
> -     */
> -    public static void setDefaultFlags(String...flags) {
> -        DEFAULT = parseFlags(DEFAULT, flags);
> -    }
> -
> -    /**
> -     * Parses flags by name.
> -     * <p>A '+flag' or 'flag' will set flag as true, '-flag' set as false.
> -     * The possible flag names are:
> -     * cancellable, strict, silent, safe, lexical, antish, lexicalShade
> -     * @param mask the initial mask state
> -     * @param flags the flags to set
> -     * @return the flag mask updated
> -     */
> -    public static int parseFlags(int mask, String...flags) {
> -        for(String name : flags) {
> -            boolean b = true;
> -            if (name.charAt(0) == '+') {
> -                name = name.substring(1);
> -            } else if (name.charAt(0) == '-') {
> -                name = name.substring(1);
> -                b = false;
> -            }
> -            for(int flag = 0; flag < NAMES.length; ++flag) {
> -                if (NAMES[flag].equals(name)) {
> -                    if (b) {
> -                        mask |= (1 << flag);
> -                    } else {
> -                        mask &= ~(1 << flag);
> -                    }
> -                    break;
> -                }
> -            }
> -        }
> -        return mask;
> -    }
> -
> -    @Override
> -    public Options set(JexlEngine jexl) {
> -        if (jexl instanceof Engine) {
> -            set(((Engine) jexl).options);
> -        } else {
> -            mathContext = jexl.getArithmetic().getMathContext();
> -            mathScale = jexl.getArithmetic().getMathScale();
> -            strictArithmetic = jexl.getArithmetic().isStrict();
> -            set(STRICT, flags, jexl.isStrict());
> -            set(SILENT, flags, jexl.isSilent());
> -            set(SAFE, flags, jexl.isSafe());
> -            set(CANCELLABLE, flags, jexl.isCancellable());
> -        }
> -        return this;
> -    }
> -
> -    @Override
> -    public Options set(JexlOptions opts) {
> -        if (opts instanceof Options) {
> -            Options src = (Options) opts;
> -            mathContext = src.mathContext;
> -            mathScale = src.mathScale;
> -            strictArithmetic = src.strictArithmetic;
> -            flags = src.flags;
> -        } else {
> -            mathContext = opts.getMathContext();
> -            mathScale = opts.getMathScale();
> -            strictArithmetic = opts.isStrict();
> -            int mask = DEFAULT;
> -            mask = set(STRICT, mask, opts.isStrict());
> -            mask = set(SILENT, mask, opts.isSilent());
> -            mask = set(SAFE, mask, opts.isSafe());
> -            mask = set(CANCELLABLE, mask, opts.isCancellable());
> -            mask = set(LEXICAL, mask, opts.isLexical());
> -            mask = set(SHADE, mask, opts.isLexicalShade());
> -            mask = set(ANTISH, mask, opts.isAntish());
> -            flags = mask;
> -        }
> -        return this;
> -    }
> -
> -    @Override
> -    public Options copy() {
> -        return new Options().set(this);
> -    }
> -
> -    @Override
> -    public void setAntish(boolean flag) {
> -        flags = set(ANTISH, flags, flag);
> -    }
> -
> -    @Override
> -    public void setMathContext(MathContext mcontext) {
> -        this.mathContext = mcontext;
> -    }
> -
> -    @Override
> -    public void setMathScale(int mscale) {
> -        this.mathScale = mscale;
> -    }
> -
> -    @Override
> -    public void setStrictArithmetic(boolean stricta) {
> -        this.strictArithmetic = stricta;
> -    }
> -
> -    @Override
> -    public void setStrict(boolean flag) {
> -        flags = set(STRICT, flags, flag);
> -    }
> -
> -    @Override
> -    public void setSafe(boolean flag) {
> -        flags = set(SAFE, flags, flag);
> -    }
> -
> -    @Override
> -    public void setSilent(boolean flag) {
> -        flags = set(SILENT, flags, flag);
> -    }
> -
> -    @Override
> -    public void setCancellable(boolean flag) {
> -        flags = set(CANCELLABLE, flags, flag);
> -    }
> -
> -    @Override
> -    public void setLexical(boolean flag) {
> -        flags = set(LEXICAL, flags, flag);
> -    }
> -
> -    @Override
> -    public void setLexicalShade(boolean flag) {
> -        flags = set(SHADE, flags, flag);
> -    }
> -
> -    @Override
> -    public boolean isAntish() {
> -        return isSet(ANTISH, flags);
> -    }
> -
> -    @Override
> -    public boolean isSilent() {
> -        return isSet(SILENT, flags);
> -    }
> -
> -    @Override
> -    public boolean isStrict() {
> -        return isSet(STRICT, flags);
> -    }
> -
> -    @Override
> -    public boolean isSafe() {
> -        return isSet(SAFE, flags);
> -    }
> -
> -    @Override
> -    public boolean isCancellable() {
> -        return isSet(CANCELLABLE, flags);
> -    }
> -
> -    @Override
> -    public boolean isLexical() {
> -        return isSet(LEXICAL, flags);
> -    }
> -
> -    @Override
> -    public boolean isLexicalShade() {
> -        return isSet(SHADE, flags);
> -    }
> -
> -    @Override
> -    public boolean isStrictArithmetic() {
> -        return strictArithmetic;
> -    }
> -
> -    @Override
> -    public MathContext getMathContext() {
> -        return mathContext;
> -    }
> -
> -    @Override
> -    public int getMathScale() {
> -        return mathScale;
> -    }
> -
> -}
> diff --git a/src/main/java/org/apache/commons/jexl3/internal/Script.java
> b/src/main/java/org/apache/commons/jexl3/internal/Script.java
> index 62ecaca..593ad08 100644
> --- a/src/main/java/org/apache/commons/jexl3/internal/Script.java
> +++ b/src/main/java/org/apache/commons/jexl3/internal/Script.java
> @@ -17,6 +17,8 @@
>  package org.apache.commons.jexl3.internal;
>
>  import org.apache.commons.jexl3.JexlContext;
> +import org.apache.commons.jexl3.JexlInfo;
> +import org.apache.commons.jexl3.JexlOptions;
>  import org.apache.commons.jexl3.JexlEngine;
>  import org.apache.commons.jexl3.JexlScript;
>  import org.apache.commons.jexl3.JexlExpression;
> @@ -96,7 +98,39 @@ public class Script implements JexlScript,
> JexlExpression {
>      protected Frame createFrame(Object[] args) {
>          return script.createFrame(args);
>      }
> +
> +    /**
> +     * Creates this script options for evaluation.
> +     * <p>This also calls the pragma processor
> +     * @param context the context
> +     * @return the options
> +     */
> +    protected JexlOptions createOptions(JexlContext context) {
> +        return jexl.createOptions(this, context);
> +    }
> +
> +    /**
> +     * A lexical script, ensures options are lexical.
> +     */
> +    public static class Lexical extends Script {
> +        /**
> +         * Sole ctor.
> +         * @param engine the engine
> +         * @param expr the source.
> +         * @param ref the ast
> +         */
> +        protected Lexical(Engine engine, String expr, ASTJexlScript ref) {
> +            super(engine, expr, ref);
> +        }
>
> +        @Override
> +        public JexlOptions createOptions(JexlContext ctxt) {
> +            JexlOptions opts = super.createOptions(ctxt);
> +            opts.setLexical(true);
> +            return opts;
> +        }
> +    }
> +
>      /**
>       * Creates this script interpreter.
>       * @param context the context
> @@ -104,7 +138,7 @@ public class Script implements JexlScript,
> JexlExpression {
>       * @return  the interpreter
>       */
>      protected Interpreter createInterpreter(JexlContext context, Frame
> frame) {
> -        return jexl.createInterpreter(context, frame);
> +        return jexl.createInterpreter(context, frame,
> createOptions(context));
>      }
>
>      /**
> @@ -215,6 +249,13 @@ public class Script implements JexlScript,
> JexlExpression {
>      public String[] getLocalVariables() {
>          return script.getLocalVariables();
>      }
> +
> +    /**
> +     * @return the info
> +     */
> +    public JexlInfo getInfo() {
> +        return script.jexlInfo();
> +    }
>
>      /**
>       * Gets this script variables.
> @@ -259,7 +300,7 @@ public class Script implements JexlScript,
> JexlExpression {
>       */
>      @Override
>      public Callable callable(JexlContext context, Object... args) {
> -        return new Callable(jexl.createInterpreter(context,
> script.createFrame(args)));
> +        return new Callable(createInterpreter(context,
> script.createFrame(args)));
>      }
>
>      /**
> diff --git
> a/src/main/java/org/apache/commons/jexl3/internal/TemplateInterpreter.java
> b/src/main/java/org/apache/commons/jexl3/internal/TemplateInterpreter.java
> index 17b0ff9..7babe6f 100644
> ---
> a/src/main/java/org/apache/commons/jexl3/internal/TemplateInterpreter.java
> +++
> b/src/main/java/org/apache/commons/jexl3/internal/TemplateInterpreter.java
> @@ -48,7 +48,7 @@ public class TemplateInterpreter extends Interpreter {
>       */
>      TemplateInterpreter(Engine jexl,
>              JexlContext jcontext, Frame jframe, TemplateExpression[]
> expressions, Writer out) {
> -        super(jexl, jcontext, jframe);
> +        super(jexl, null, jcontext, jframe);
>          exprs = expressions;
>          writer = out;
>          block = new LexicalFrame(frame, null);
> diff --git a/src/test/java/org/apache/commons/jexl3/AntishCallTest.java
> b/src/test/java/org/apache/commons/jexl3/AntishCallTest.java
> index 5f23b11..8397ce0 100644
> --- a/src/test/java/org/apache/commons/jexl3/AntishCallTest.java
> +++ b/src/test/java/org/apache/commons/jexl3/AntishCallTest.java
> @@ -173,7 +173,8 @@ public class AntishCallTest extends JexlTestCase {
>      // JEXL-300
>      @Test
>      public void testSafeAnt() throws Exception {
> -        JexlContext ctxt = new MapContext();
> +        JexlEvalContext ctxt = new JexlEvalContext();
> +        JexlOptions options = ctxt.getEngineOptions();
>          ctxt.set("x.y.z", 42);
>          JexlScript script;
>          Object result;
> @@ -182,6 +183,18 @@ public class AntishCallTest extends JexlTestCase {
>          result = script.execute(ctxt);
>          Assert.assertEquals(42, result);
>          Assert.assertEquals(42, ctxt.get("x.y.z"));
> +
> +        options.setAntish(false);
> +        try {
> +            result = script.execute(ctxt);
> +            Assert.fail("antish var shall not be resolved");
> +        } catch(JexlException.Variable xvar) {
> +            Assert.assertTrue("x".equals(xvar.getVariable()));
> +        } catch(JexlException xother) {
> +            Assert.assertTrue(xother != null);
> +        } finally {
> +            options.setAntish(true);
> +        }
>
>          result = null;
>          script = JEXL.createScript("x?.y?.z");
> diff --git a/src/test/java/org/apache/commons/jexl3/Issues300Test.java
> b/src/test/java/org/apache/commons/jexl3/Issues300Test.java
> index d2b45ec..913133b 100644
> --- a/src/test/java/org/apache/commons/jexl3/Issues300Test.java
> +++ b/src/test/java/org/apache/commons/jexl3/Issues300Test.java
> @@ -324,25 +324,24 @@ public class Issues300Test {
>          Assert.assertEquals(52, result);
>      }
>
> -    public static class ClazzB {
> -        public int methodB()  {
> -            return 42;
> -        }
> -    }
> -    public static class ClazzA {
> -        public ClazzB methodA() {
> -            return new ClazzB();
> -        }
> -    }
>
>      @Test
> -    public void test317Tentative() throws Exception {
> +    public void test317() throws Exception {
>          JexlEngine jexl = new JexlBuilder().strict(true).create();
>          JexlContext ctxt = new MapContext();
>          JexlScript script;
>          Object result;
> -        script = jexl.createScript("x.methodA().methodB()", "x");
> -        result = script.execute(ctxt, new ClazzA());
> +        JexlInfo info = new JexlInfo("test317", 1, 1);
> +        script = jexl.createScript(info, "var f = "
> +                + "()-> {x + x }; f",
> +                "x");
> +        result = script.execute(ctxt, 21);
> +        Assert.assertTrue(result instanceof JexlScript);
> +        script = (JexlScript) result;
> +        info = JexlInfo.from(script);
> +        Assert.assertNotNull(info);
> +        Assert.assertEquals("test317", info.getName());
> +        result = script.execute(ctxt, 21);
>          Assert.assertEquals(42, result);
>      }
>  }
> diff --git a/src/test/java/org/apache/commons/jexl3/JXLTTest.java
> b/src/test/java/org/apache/commons/jexl3/JXLTTest.java
> index c59193d..3986c2e 100644
> --- a/src/test/java/org/apache/commons/jexl3/JXLTTest.java
> +++ b/src/test/java/org/apache/commons/jexl3/JXLTTest.java
> @@ -19,7 +19,6 @@ package org.apache.commons.jexl3;
>  import org.apache.commons.jexl3.internal.TemplateDebugger;
>  import org.apache.commons.jexl3.internal.TemplateScript;
>  import org.apache.commons.jexl3.internal.Debugger;
> -import org.apache.commons.jexl3.internal.Options;
>
>  import org.apache.commons.logging.Log;
>  import org.apache.commons.logging.LogFactory;
> @@ -806,7 +805,7 @@ public class JXLTTest extends JexlTestCase {
>          }
>
>          JexlOptions newOptions() {
> -            options = new Options();
> +            options = new JexlOptions();
>              return options;
>          }
>      }
> diff --git a/src/test/java/org/apache/commons/jexl3/JexlEvalContext.java
> b/src/test/java/org/apache/commons/jexl3/JexlEvalContext.java
> index 55fdcad..f0c233c 100644
> --- a/src/test/java/org/apache/commons/jexl3/JexlEvalContext.java
> +++ b/src/test/java/org/apache/commons/jexl3/JexlEvalContext.java
> @@ -19,7 +19,6 @@ package org.apache.commons.jexl3;
>  import java.util.Collections;
>  import java.util.Map;
>  import org.apache.commons.jexl3.annotations.NoJexl;
> -import org.apache.commons.jexl3.internal.Options;
>
>  /**
>   * A JEXL evaluation environment wrapping variables, namespace and
> options.
> @@ -35,7 +34,7 @@ public class JexlEvalContext implements
>      /** The namespace. */
>      private final JexlContext.NamespaceResolver ns;
>      /** The options. */
> -    private final JexlOptions options = new Options();
> +    private final JexlOptions options = new JexlOptions();
>
>
>
> diff --git a/src/test/java/org/apache/commons/jexl3/JexlTestCase.java
> b/src/test/java/org/apache/commons/jexl3/JexlTestCase.java
> index f8d00d3..294ea4a 100644
> --- a/src/test/java/org/apache/commons/jexl3/JexlTestCase.java
> +++ b/src/test/java/org/apache/commons/jexl3/JexlTestCase.java
> @@ -35,7 +35,7 @@ public class JexlTestCase {
>      // important can be identified by the builder  calling lexical(...).
>      static {
>          //JexlBuilder.setDefaultOptions("+safe", "-lexical");
> -        JexlBuilder.setDefaultOptions("-safe", "+lexical");
> +        JexlOptions.setDefaultFlags("-safe", "+lexical");
>      }
>      /** No parameters signature for test run. */
>      private static final Class<?>[] NO_PARMS = {};
> diff --git a/src/test/java/org/apache/commons/jexl3/LexicalTest.java
> b/src/test/java/org/apache/commons/jexl3/LexicalTest.java
> index cf8943e..891393a 100644
> --- a/src/test/java/org/apache/commons/jexl3/LexicalTest.java
> +++ b/src/test/java/org/apache/commons/jexl3/LexicalTest.java
> @@ -19,6 +19,7 @@ package org.apache.commons.jexl3;
>  import java.io.StringReader;
>  import java.io.StringWriter;
>  import java.util.Set;
> +import org.apache.commons.jexl3.internal.LexicalScope;
>  import org.junit.Assert;
>  import org.junit.Test;
>
> @@ -344,4 +345,46 @@ public class LexicalTest {
>              Assert.assertNotNull(xany);
>          }
>      }
> +
> +    @Test
> +    public void testPragmaOptions() throws Exception {
> +        // same as 6d but using a pragma
> +        String str = "#pragma jexl.options '+strict +lexical
> +lexicalShade -safe'\n"
> +                + "i = 0; for (var i : [42]) i; i";
> +        JexlEngine jexl = new JexlBuilder().strict(false).create();
> +        JexlScript e = jexl.createScript(str);
> +        JexlContext ctxt = new MapContext();
> +        try {
> +            Object o = e.execute(ctxt);
> +            Assert.fail("i should be shaded");
> +        } catch (JexlException xany) {
> +            Assert.assertNotNull(xany);
> +        }
> +    }
> +
> +    @Test
> +    public void testPragmaNoop() throws Exception {
> +        // unknow pragma
> +        String str = "#pragma jexl.options 'no effect'\ni = -42; for (var
> i : [42]) i; i";
> +        JexlEngine jexl = new
> JexlBuilder().lexical(false).strict(true).create();
> +        JexlScript e = jexl.createScript(str);
> +        JexlContext ctxt = new MapContext();
> +        Object result = e.execute(ctxt);
> +        Assert.assertEquals(42, result);
> +    }
> +
> +
> +    @Test
> +    public void testScopeFrame() throws Exception {
> +        LexicalScope scope = new LexicalScope(null);
> +        for(int i = 0; i < 128; i += 2) {
> +            Assert.assertTrue(scope.declareSymbol(i));
> +            Assert.assertFalse(scope.declareSymbol(i));
> +        }
> +        for(int i = 0; i < 128; i += 2) {
> +            Assert.assertTrue(scope.hasSymbol(i));
> +            Assert.assertFalse(scope.hasSymbol(i + 1));
> +        }
> +    }
> +
>  }
>
>
Reply | Threaded
Open this post in threaded view
|

Re: [commons-jexl] branch master updated: JEXL-307: tidy API (made JexlOptions a concrete non derivable class), try to ensure lexical interpretation on lexical feature, allow runtime options to be controlled through pragma (jexl.options) Task #JEXL-307 - Variable redeclaration option

sebb-2-2
If you are referring to the class

org.apache.commons.jexl3.internal.Options

Is binary compat required for an internal class?

On Wed, 13 Nov 2019 at 10:20, Gary Gregory <[hidden email]> wrote:

> I do not think your changes to JexlOptions are binary compatible so -1 :-(
>
> Gary
>
> On Tue, Nov 12, 2019, 17:01 <[hidden email]> wrote:
>
> > This is an automated email from the ASF dual-hosted git repository.
> >
> > henrib pushed a commit to branch master
> > in repository https://gitbox.apache.org/repos/asf/commons-jexl.git
> >
> >
> > The following commit(s) were added to refs/heads/master by this push:
> >      new 753d6e6  JEXL-307: tidy API (made JexlOptions a concrete non
> > derivable class), try to ensure lexical interpretation on lexical
> feature,
> > allow runtime options to be controlled through pragma (jexl.options) Task
> > #JEXL-307 - Variable redeclaration option
> > 753d6e6 is described below
> >
> > commit 753d6e634d94022871b481896db78e323d7ccfed
> > Author: henrib <[hidden email]>
> > AuthorDate: Tue Nov 12 23:00:39 2019 +0100
> >
> >     JEXL-307: tidy API (made JexlOptions a concrete non derivable class),
> > try to ensure lexical interpretation on lexical feature, allow runtime
> > options to be controlled through pragma (jexl.options)
> >     Task #JEXL-307 - Variable redeclaration option
>


> <snip>
Reply | Threaded
Open this post in threaded view
|

Re: [commons-jexl] branch master updated: JEXL-307: tidy API (made JexlOptions a concrete non derivable class), try to ensure lexical interpretation on lexical feature, allow runtime options to be controlled through pragma (jexl.options) Task #JEXL-307 - Variable redeclaration option

henrib
In reply to this post by garydgregory
JexlOptions is introduced in 3.2, this class has not been released yet.
I understand your reaction but I believe it is not warranted in this case.

I also believe 'internal' classes are clearly out of the API contract - they
are documented as such.
If you believe there are already showstoppers that warrant a package change,
aka jexl4, I should not even try releasing 3.2; please let me know.

Cheers




--
Sent from: http://apache-commons.680414.n4.nabble.com/Commons-Dev-f680415.html

---------------------------------------------------------------------
To unsubscribe, e-mail: [hidden email]
For additional commands, e-mail: [hidden email]