# RuntimeJastInterpreter.java

    /*
    ** Module   : RuntimeJastInterpreter.java
    ** Abstract : Interpreter for a JAST tree that contains a compiling unit.
    **
    ** Copyright (c) 2015-2024, Golden Code Development Corporation.
    **
    ** -#- -I- --Date-- ---------------------------------------Description---------------------------------------
    ** 001 OM  20150123 Created initial version.
    ** 002 OM  20150210 Added support for anonymous WhereExpression and LogicalExpression.
    **                  Added support for calling methods in a super class. Refactoring method names.
    ** 003 OM  20150306 The strings literals are generated as ready to be written to java sources and
    **                  they had to be escaped to obtain their real value.
    ** 004 OM  20150318 Added Date and IntegerExpression implementation.
    ** 005 ECF 20150401 Removed Aast node instance member from InterpreterException class and made
    **                  this inner class static to allow it to be serialized, in case it needs to be
    **                  sent to a client over the DAP.
    ** 006 OM  20150610 Added support for calling methods with parameters.
    **                  Added support for accessing array variables and parameters.
    ** 007 OM  20150617 Added evaluation of expressions having JavaTokenTypes.LPARENS as root.
    ** 008 OM  20150731 Added support for interpreting JavaTokenTypes.MEMBER.
    ** 009 OM  20150904 Added support for interpreting (P2JQuery.Parameter) JavaTokenTypes.LAMBDA
    **                  expressions.
    ** 010 GES 20150923 Javadoc fix.
    ** 011 OM  20160201 Added support for interpreting remaining datatypes Expressions.
    ** 012 GES 20160505 Removed javaEscape() and replaced usage with StringHelper.processEscapes().
    ** 013 OM  20160526 Improved support for interpreted LAMBDA nodes (added LogicalOp interfaces).
    ** 014 GES 20160818 Replaced WhereExpression usage with lambda support for client where clause
    **                  support. Fixed varargs matching if the method call is annotated suitably.
    **         20160824 Reworked to handle delegated query substitution parameters that are general
    **                  purpose lambdas (as a subclass of Resolvable).
    ** 015 IAS 20160930 Fix for a regression caused by H014, a constructor can be the referent for a
    **                  method call.
    ** 016 ECF 20171227 Performance improvement and format cleanup.
    ** 017 OM  20181207 Added interpretIfExist() method.
    ** 018 OM  20190321 Specifically evaluate dynamic function calls on query open.
    **                  Throw ABL exceptions instead of InterpreterException.
    ** 019 ECF 20190829 Added optional logging of interpreter exceptions.
    ** 020 ECF 20190728 Log a failure to resolve a query substitution parameter.
    **     CA  20190812 Changes to allow for mutable buffers; any API which receives a Buffer instance
    **                  and is invoked from converted code must resolve the runtime instance before
    **                  saving the instance.
    ** 021 OM  20200109 Cached the evaluation of DYNAMIC-FUNCTIONS in here (there is one RJI for
    **                  each dynamic query) so that the JAST trees can be cached and reused.
    **     OM  20200123 Mild optimizations and code upgrade.
    ** 022 VVT 20200203 Invalid assertion removed.
    ** 023 OM  20200725 Fixed method resolution.
    ** 024 CA  20200924 Replaced Method.invoke with ReflectASM.
    **     OM  20210219 Added support for persist.***Expr types to getClass().
    **     CA  20210310 A dynamic predicate must set the default lock to NONE, instead of SHARE.
    **     ECF 20210504 Check for all ControlFlowOps dynamic function method names, not just the basic one.
    **     ECF 20210915 Allow recursion in callMethod.
    **     AL2 20220412 Do proxy checks for BDT when evaluating.
    **     CA  20221006 Added JMX instrumentation for interprate. Refs #6814
    **     TJD 20220504 Upgrade do Java 11 minor changes
    ** 025 GBB 20230512 Logging methods replaced by CentralLogger/ConversionStatus.
    ** 026 IAS 20230921 Added support for the P2JQuery.ParamResolver.
    ** 027 HC  20240222 Enabled JMX on FWD Client.
    ** 028 AL2 20230222 Made constructor look-up more relaxed. It fallbacks to the first constructor, not null.
    ** 029 CA  20240324 Performance improvement for runtime annotations: are stored using an integer instead of
    **                  string.
    ** 030 TT  20240411 Modified the logging when a second constructor is found in findMatchingConstructor().
    ** 031 CA  20240809 Skip using JMX timers when JMX_DEBUG flag is not set.
    ** 032 AL2 20240925 Fixed NPE when calling static method. If the static class was cached, but the method was
    **                  not, the method was no longer looked-up. Now, the method is looked-up properly.
    */

    /*
    ** This program is free software: you can redistribute it and/or modify
    ** it under the terms of the GNU Affero General Public License as
    ** published by the Free Software Foundation, either version 3 of the
    ** License, or (at your option) any later version.
    **
    ** This program is distributed in the hope that it will be useful,
    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    ** GNU Affero General Public License for more details.
    **
    ** You may find a copy of the GNU Affero GPL version 3 at the following
    ** location: https://www.gnu.org/licenses/agpl-3.0.en.html
    **
    ** Additional terms under GNU Affero GPL version 3 section 7:
    **
    **   Under Section 7 of the GNU Affero GPL version 3, the following additional
    **   terms apply to the works covered under the License.  These additional terms
    **   are non-permissive additional terms allowed under Section 7 of the GNU
    **   Affero GPL version 3 and may not be removed by you.
    **
    **   0. Attribution Requirement.
    **
    **     You must preserve all legal notices or author attributions in the covered
    **     work or Appropriate Legal Notices displayed by works containing the covered
    **     work.  You may not remove from the covered work any author or developer
    **     credit already included within the covered work.
    **
    **   1. No License To Use Trademarks.
    **
    **     This license does not grant any license or rights to use the trademarks
    **     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
    **     of Golden Code Development Corporation. You are not authorized to use the
    **     name Golden Code, FWD, or the names of any author or contributor, for
    **     publicity purposes without written authorization.
    **
    **   2. No Misrepresentation of Affiliation.
    **
    **     You may not represent yourself as Golden Code Development Corporation or FWD.
    **
    **     You may not represent yourself for publicity purposes as associated with
    **     Golden Code Development Corporation, FWD, or any author or contributor to
    **     the covered work, without written authorization.
    **
    **   3. No Misrepresentation of Source or Origin.
    **
    **     You may not represent the covered work as solely your work.  All modified
    **     versions of the covered work must be marked in a reasonable way to make it
    **     clear that the modified work is not originating from Golden Code Development
    **     Corporation or FWD.  All modified versions must contain the notices of
    **     attribution required in this license.
    */
    package com.goldencode.p2j.persist;

    import com.goldencode.ast.*;
    import com.goldencode.expr.*;
    import com.goldencode.util.*;
    import com.goldencode.p2j.jmx.*;
    import com.goldencode.p2j.uast.*;
    import com.goldencode.p2j.util.*;
    import com.goldencode.p2j.util.ErrorManager;
    import com.goldencode.p2j.util.logging.CentralLogger;

    import java.lang.reflect.*;
    import java.util.*;
    import java.util.concurrent.*;
    import java.util.function.Consumer;
    import java.util.function.Supplier;  // importing all conflicts with Function class
    import java.util.logging.*;

    /**
     * This class interprets a JAST tree. It is designed to be as generic as possible.
     *
     * It will use the annotations from a memory stored JAST if they are found. Otherwise it will
     * use reflection to select the appropriate method/constructor based on the actual parameters.
     * In the second case, the newly discovered piece of information will be cached back in the tree
     * for a fast evaluation in successive executions.
     *
     * The interpreter is week-typed, it only distinct two types of data: table buffers and variable.
     * variables can store any kind of data, the scalars are stored in their respective wrappers,
     * access being done using automatic boxing/unboxing. The datatypes are evaluated at runtime based
     * on the actual variable value.
     *
     * Known issues. At this moment:
     * <ul>
     *    <li>only sequential methods can be processed. Future versions will add support for loops
     *          and conditionals;
     *    <li>there is no [this] notion. In consequence other methods cannot be called. Not even the
     *          static ones;
     *    <li>no support for arrays;
     *    <li>no support for constructors. Objects of this class cannot be built/returned. All
     *          methods are called as they were static.
     *    <li>the root of the JAST is a COMPILE-UNIT that can hold only one (public) class;
     *    <li>others TBA.
     * </ul>
     *
     * Usage. There are 4 steps when working with the interpreter.
     * <ol>
     *    <li>Initialization. When an object is constructed, two optional types of data can be
     *       optionally supplied: a list of buffers and a set of pre-initialized variables that will
     *       be used in the process of evaluation.
     *    <li>Preparation. The JAST is supplied. The first traversal will collect paths, class
     *       variables and method names.
     *    <li>Interpretation. A method can be called. At this moment it cannot have any parameters.
     *       As workaround, they can be provided as pre-initialized variables in Initialization.
     *       This step can be repeated with different methods. If they are functions, the evaluated
     *       values is provided in the returned value.
     *    <li>Get the variable value. Extract the value of a variable. This can be combined with
     *       [Interpretation], and can be called multiple times. If the method invoked is a function,
     *       this step is optional, a value is obtained as teh result of the [Interpretation].
     * </ol>
     */
    public class RuntimeJastInterpreter
    {
       /** Instrumentation for {@link #interpret}. */
       private static final NanoTimer QUERY_INTERPRET = NanoTimer.getInstance(FwdServerJMX.TimeStat.OrmDynQueryInterpret);

       /**
        * This is a marker for not evaluated nodes. It is used to avoid conflicts with possible
        * {@code null} valid values already evaluated.
        */
       private final Object NOT_EVALUATED = new Object();

       /** Logger. */
       private static final CentralLogger LOG = CentralLogger.get(RuntimeJastInterpreter.class.getName());

       /** Cache of classes for faster lookup than {@code Class.forName} alone */
       private static final Map<String, Class<?>> classCache = new ConcurrentHashMap<>();

       /** The list of known buffers, by their name. */
       private Map<String, Buffer> buffers = null;

       /** The list of the variables, by their name. */
       private Map<String, Object> variables = null;

       /**
        * The stack of parameters from calling methods with actual values.
        * <p>
        * <b>NOTE:</b>This is not a perfect emulation of a java scopes.
        */
       private ScopedDictionary<String, Object> methodArgs = new ScopedDictionary<>();

       /** The list of import paths. Used for class and method dynamic resolution. */
       private String[] imports =
       {
          "java.lang.",               // always present
          "com.goldencode.p2j.util.", // usually needed
       };

       /** Identifies a DYNAMIC-FUNCTION call. */
       private final String DYNAMIC_CALL = "ControlFlowOps.invokeDynamicFunction";

       /**
        * The set of all DYNAMIC-FUNCTION calls from this compile unit. If {@code null} then it
        * contains no DYNAMIC-FUNCTION calls. These nodes will be evaluated only once, when the query
        * is open and the result is cached mapped to respective node. These values are valid for this
        * interpreter, ie for an individual dynamic query.
        */
       private Map<Aast, Object> dynamicCalls = null;

       /** The list of statically imported classes. Used for method dynamic resolution. */
       private Class<?>[] staticImports =
       {
          java.lang.Math.class,   // always present
       };

       /** The list of the method defined in this class. */
       private Map<String, Aast> classMethods = new HashMap<>();

       /** A consumer to process newly created instances. */
       private Consumer<Object> instanceProcessor = null;

       /**
        * The default constructor. Initiate the list of buffers and variables to empty sets.
        */
       public RuntimeJastInterpreter()
       {
          this.buffers = new HashMap<>();
          this.variables = new HashMap<>();
       }

       /**
        * A constructor that receives a set of buffers and pre-initialized variables.
        *
        * @param   buffers
        *          The list of buffers to be used. Must be open and ready to use.
        * @param   variables
        *          The list of variables (values mapped by their variable names).
        */
       public RuntimeJastInterpreter(List<Buffer> buffers, Map<String, Object> variables)
       {
          setBuffers(buffers);
          setVariables(variables);
       }

       /**
        * Get the class with the given name. The class cache is checked first, then the class is
        * retrieved from the current classloader, if not found in the cache.
        *
        * @param   className
        *          Fully qualified class name.
        *
        * @return  Class associated with {@code className}, if found.
        *
        * @throws  ClassNotFoundException
        *          if a class with the given name is not found.
        */
       private static Class<?> classForName(String className)
       throws ClassNotFoundException
       {
          Class<?> cls = classCache.get(className);
          if (cls == null)
          {
             cls = Class.forName(className);
             classCache.putIfAbsent(className, cls);
          }

          return cls;
       }

       /**
        * Updates the set of known buffers. The old list is lost.
        *
        * @param   buffers
        *          The new list of buffers to be used. Must be open and ready to use.
        */
       public void setBuffers(List<Buffer> buffers)
       {
          // map buffers for quick access by their alias
          this.buffers = new HashMap<>();
          if (buffers != null)
          {
             for (Buffer buf : buffers)
             {
                RecordBuffer rbuf = ((BufferImpl) buf).buffer();
                this.buffers.put(rbuf.getDMOAlias(), ((BufferImpl) buf).ref());
             }
          }
       }

       /**
        * Updates the set of known variables. The old list is lost.
        *
        * @param   variables
        *          The new list of variables (values mapped by their variable names).
        */
       public void setVariables(Map<String, Object> variables)
       {
          this.variables = new HashMap<>();
          if (variables != null)
          {
             this.variables.putAll(variables);
          }
       }

       /**
        * The preparation step. The node provided must be a COMPILE-UNIT. The method does a fast first
        * tree traversal (max two level deep) and will collect paths, class variables and method names
        * that will be used in future processing.
        *
        * @param   jast
        *          The JAST tree to be processed. It must be a COMPILE-UNIT node.
        * @param   dynamicEvaluation
        *          Use {@code true} when there is at least on DYNAMIC-FUNCTION in interpreted
        *          expression.
        *
        * @throws  RuntimeJastInterpreter.InterpreterException
        *          if the argument is null or not a COMPILE-UNIT node.
        */
       public void prepare(JavaAst jast, boolean dynamicEvaluation)
       {
          if (jast == null || jast.getType() != JavaTokenTypes.COMPILE_UNIT)
          {
             throw new InterpreterException("The argument for prepare must be a COMPILE-UNIT jast.", jast, null);
          }
          compileUnit(jast);
          if (dynamicEvaluation)
          {
             dynamicCalls = new HashMap<>();
             // scan for dynamic calls
             Iterator<Aast> it = jast.iterator();
             while (it.hasNext())
             {
                Aast next = it.next();
                String text = next.getText();
                if (text != null && text.startsWith(DYNAMIC_CALL))
                {
                   dynamicCalls.put(next, NOT_EVALUATED);
                }
             }

             if (dynamicCalls.isEmpty())
             {
                LOG.warning("Failed to detect the DYNAMIC-FUNCTION calls.");
             }
          }
       }

       /**
        * Obtain the value of a variable. This method can be called for each needed variable, at any
        * given moment.
        *
        * @param   varName
        *          the name of the variable whose value will be returned.
        *
        * @return  the value of requested variable.
        *
        * @throws  RuntimeJastInterpreter.InterpreterException
        *          if the argument is null or not a variable name.
        */
       public Object getVariableValue(String varName)
       {
          if (variables.containsKey(varName))
          {
             return variables.get(varName);
          }

          throw new InterpreterException("No variable named '" + varName + "' was defined", null, null);
       }

       /**
        * Executes a method. If the method returns a value (function) it it will be obtained as the
        * result.
        * Only simple methods, without parameters are supported. As workaround, the parameters can be
        * added to the list of initial pre-initialized variables.
        * <p>
        * This method does not throw any exception if no method if sound to match the requested name
        * and signature as {@link #interpret} does. In this case this method returns {@code null}.
        *
        * @param   methodName
        *          The name of the method to be called.
        * @param   args
        *          The list of actual values for the parameters.
        *
        * @return  if the method defines a RETURN statement, that value is returned, otherwise null.
        */
       public Object interpretIfExist(String methodName, Object... args)
       {
          Aast aMethod = classMethods.get(methodName);
          if (aMethod != null)
          {
             return execMethod(aMethod, args);
          }

          return null;
       }

       /**
        * Executes a method. If the method returns a value (function) it it will be obtained as the
        * result.
        * Only simple methods, without parameters are supported. As workaround, the parameters can be
        * added to the list of initial pre-initialized variables.
        *
        * @param   methodName
        *          The name of the method to be called.
        * @param   args
        *          The list of actual values for the parameters.
        *
        * @return  if the method defines a RETURN statement, that value is returned, otherwise null.
        *
        * @throws  RuntimeJastInterpreter.InterpreterException
        *          if the argument is null or not a method name or other exception occurred during
        *          the evaluation.
        */
       public Object interpret(String methodName, Object... args)
       {
          Aast aMethod = classMethods.get(methodName);
          if (aMethod != null)
          {
             if (FwdServerJMX.JMX_DEBUG)
             {
                Object[] res = new Object[1];
                QUERY_INTERPRET.timer(() -> res[0] = execMethod(aMethod, args));
                return res[0];
             }
             else
             {
                return execMethod(aMethod, args);
             }
          }
          throw new InterpreterException("No such method defined", null, null);
       }

       public void evaluateDynamicCalls()
       {
          if (dynamicCalls == null)
          {
             return;
          }

          try
          {
             Set<Aast> nodeSet = new HashSet<>(dynamicCalls.keySet());
             for (Aast dynamicCall : nodeSet)
             {
                if (dynamicCalls.get(dynamicCall) == NOT_EVALUATED)
                {
                   // replace the NOT_EVALUATED value with the result of the method evaluation
                   dynamicCalls.put(dynamicCall, callStaticMethod(dynamicCall));
                }
             }
          }
          catch (InterpreterException ie)
          {
             String err = "Incompatible data types in expression or assignment.";
             ErrorManager.recordOrThrowError(223, err);
          }
       }

       /**
        * Set a function which will process any newly created instances.
        *
        * @param    expr
        *           The function.
        */
       void processInstancesWith(Consumer<Object> expr)
       {
          this.instanceProcessor = expr;
       }

       /**
        * Prepares the JAST for use. The method does a fast first tree traversal (max two level deep)
        * and will collect paths, class variables and method names that will be used in future
        * processing.
        *
        * @param   cu
        *          The main node of a tree. It must be a COMPILE-UNIT node.
        */
       private void compileUnit(Aast cu)
       {
          // iterate to 'learn' how to resolve classes and (static) method  calls
          collectImportPaths(cu);
          collectStaticImports(cu);

          Aast mainClass = cu.getImmediateChild(JavaTokenTypes.KW_CLASS, null);
          if (mainClass == null)
          {
             throw new InterpreterException("Main class could not be determined", cu, null);
          }

          // store instance vars if any (the query should be listed here, normally)
          Aast classVars = mainClass.getImmediateChild(JavaTokenTypes.CS_INSTANCE_VARS, null);
          if (classVars != null)
          {
             declareVars(classVars);
          }

          // collect methods (all)
          Aast allMethods = mainClass.getImmediateChild(JavaTokenTypes.CS_INSTANCE_METHODS, null);
          if (allMethods == null)
          {
             throw new InterpreterException("No methods are defined in the class", cu, null);
          }

          Aast aMethod = allMethods.getImmediateChild(JavaTokenTypes.METHOD_DEF, null);
          while (aMethod != null)
          {
             classMethods.put(aMethod.getText(), aMethod);
             aMethod = (Aast) aMethod.getNextSibling();
          }
       }

       /**
        * Collects the import paths used for symbol resolution. Iterates KW_IMPORT nodes.
        * Previous collection of paths is dropped. The default "java.lang.*" package is automatically
        * inserted.
        *
        * @param   cu
        *          The main node of a tree. It must be a COMPILE-UNIT node.
        */
       private void collectImportPaths(Aast cu)
       {
          Aast importPath = cu.getImmediateChild(JavaTokenTypes.KW_IMPORT, null);
          imports = new String[cu.getNumImmediateChildren(JavaTokenTypes.KW_IMPORT) + 1];
          int k = 0;
          imports[k++] = "java.lang.";
          while (importPath != null)
          {
             String packageName = importPath.getText();
             imports[k++] = packageName.substring(0, packageName.length() - 1);

             importPath = cu.getImmediateChild(JavaTokenTypes.KW_IMPORT, importPath);
          }
       }

       /**
        * Collects the static import paths used for symbol resolution. Iterates STATIC_IMPORT nodes.
        * Previous collection of classes is dropped. The default "java.lang.Math" package is
        * automatically inserted at the end.
        *
        * @param   cu
        *          The main node of a tree. It must be a COMPILE-UNIT node.
        */
       private void collectStaticImports(Aast cu)
       {
          Aast staticImport = cu.getImmediateChild(JavaTokenTypes.STATIC_IMPORT, null);
          staticImports = new Class[cu.getNumImmediateChildren(JavaTokenTypes.STATIC_IMPORT) + 1];
          int k = 0;
          while (staticImport != null)
          {
             String className = staticImport.getText();
             className = className.substring(0, className.length() - 2);
             try
             {
                staticImports[k++] = classForName(className);
             }
             catch (ClassNotFoundException e)
             {
                throw new InterpreterException("Failed to load static import", staticImport, e);
             }
             staticImport = cu.getImmediateChild(JavaTokenTypes.STATIC_IMPORT, staticImport);
          }
          staticImports[k] = Math.class; // add as a last resort
       }

       /**
        * Collects the variables defined in this class. Table buffers are ignored.
        * Iterates the children of CS_INSTANCE_VARS nodes, adding them to the list of internal
        * variables. If the case the initialization is performed.
        *
        * @param   classVars
        *          The main node of a tree. It must be a CS_INSTANCE_VARS node.
        */
       private void declareVars(Aast classVars)
       {
          Aast varDef = (Aast) classVars.getFirstChild();
          while (varDef != null)
          {
             // add it to our class variables set
             Aast varRef = (Aast) varDef.getFirstChild();
             if (varRef != null)
             {
                if (!varRef.getText().endsWith(".Buf"))
                {
                   String varName = (String) varRef.getAnnotation("name");
                   variables.put(varName, null);
                   doAssign(varName, (Aast) varRef.getNextSibling());
                }
                // skip buffers, they are already collected
             }
             else
             {
                // simple declaration, without assignment
                String varName = (String) varDef.getAnnotation("name");
                variables.put(varName, null);
             }

             varDef = (Aast) varDef.getNextSibling();
          }
       }

       /**
        * Executes a method from this class by interpreting the sequence of statements from its body.
        * <p>
        * Each statement from this method definition is executed/evaluated in sequence. If the method
        * returns a value (function) it it will be obtained as the result.
        * <p>
        * Only simple methods, without parameters are supported. As workaround, the parameters can be
        * added to the list of initial pre-initialized variables.
        *
        * @param   aMethod
        *          The method node to be processed.
        * @param   params
        *          The arguments for this method.
        *
        * @return  if the method defines a RETURN statement, that value is returned, otherwise null.
        */
       private Object execMethod(Aast aMethod, Object... params)
       {
          assert (aMethod.getType() == JavaTokenTypes.METHOD_DEF);

          Aast methBlock = aMethod.getImmediateChild(JavaTokenTypes.BLOCK, null);
          assert (methBlock != null);

          Aast parList = aMethod.getImmediateChild(JavaTokenTypes.LPARENS, null);
          try
          {
             // optimization: add a new scope only if the method has parameters
             if (parList != null)
             {
                // push the parameters to the scoped dictionary:
                methodArgs.addScope(aMethod.getText());
                // iterate all parameters and map them to their value in the methodArgs dictionary
                Aast param = (Aast) parList.getFirstChild();
                int pIndex = 0;
                while (param != null)
                {
                   if (params == null || pIndex >= params.length)
                   {
                      throw new InterpreterException(
                         "Invalid parameter list in method call", aMethod, null);
                   }

                   methodArgs.addEntry(false, (String) param.getAnnotation("name"), params[pIndex++]);

                   param = (Aast) param.getNextSibling();
                }
             }

             // iterate all statements from the method block
             Aast statement = (Aast) methBlock.getFirstChild();
             while (statement != null)
             {
                switch (statement.getType())
                {
                   case JavaTokenTypes.KW_RETURN:
                      if (statement.getNumImmediateChildren() == 0)
                      {
                         return null;
                      }
                      else
                      {
                         // this a function definition; returning the result
                         Object res = evalExpression((Aast) statement.getFirstChild());
                         return res;
                      }

                   case JavaTokenTypes.METHOD_CALL:
                      callMethod(statement);
                      break;

                   case JavaTokenTypes.STATIC_METHOD_CALL:
                      callStaticMethod(statement);
                      break;

                   case JavaTokenTypes.ASSIGN:
                      Aast varRef = (Aast) statement.getFirstChild();
                      doAssign(varRef.getText(), (Aast) varRef.getNextSibling());
                      break;

                   default:
                      throw new InterpreterException("Unknown statement type", statement, null);
                }
                statement = (Aast) statement.getNextSibling();
             }
          }
          finally
          {
             if (parList != null)
             {
                // remove the last scope from the parameter dictionary if the method had parameters
                methodArgs.deleteScope();
             }
          }
          return null;
       }

       /**
        * Performs a variable assignment. The variable must be already defined.
        *
        * @param   varName
        *          The name of the variable.
        * @param   assignNode
        *          The node that contain the tree for evaluation of the variable value.
        *
        * @return  in order to support chaining, the evaluated value of the variable is returned.
        */
       private Object doAssign(String varName, Aast assignNode)
       {
          if (!variables.containsKey(varName))
          {
             throw new InterpreterException(
                   "No variable named '" + varName + "' was defined", assignNode, null);
          }

          Object val = evalExpression(assignNode);
          variables.put(varName, val);
          return val;
       }

       /**
        * Call a constructor and returns the built object.
        * <p>
        * The method will try to use the cached annotation from the node to speed up evaluation.
        * If not available, it will use reflection to resolve it. Once computed, the Constructor
        * object will be stored for future calls.
        * <p>
        * Before calling the constructor, all children nodes are (recursively) evaluated.
        *
        * @param   ctorNode
        *          A CONSTRUCTOR node used to build an object.
        *
        * @return  the newly constructed object is returned. Not null.
        */
       private Object callCtor(Aast ctorNode)
       {
          assert (ctorNode.getType() == JavaTokenTypes.CONSTRUCTOR);

          Constructor<?> ctor = null;
          Class<?> queryClass = null;
          Object[] parValues = null;

          // try to use the runtime annotation to speed up the interpreter
          Object cachedCtor = getCache(ctorNode, Aast.RUNTIME_CONSTRUCTOR);
          if (cachedCtor instanceof Constructor)
          {
             ctor = (Constructor<?>) cachedCtor;
          }
          else
          {
             // try to use the cached class name, at least
             Object cachedClass = getCache(ctorNode, Aast.RUNTIME_CLASS);
             if (cachedClass instanceof Class)
             {
                queryClass = (Class<?>) cachedClass;
             }
             else
             {
                // TODO: check if the classname contains the package to load it directly

                for (String path : imports)
                {
                   // load class, prepare constructor
                   String ctorClass = path + ctorNode.getText();
                   try
                   {
                      queryClass = classForName(ctorClass);
                      break; // found it
                   }
                   catch (ClassNotFoundException e)
                   {
                      // not the right package this class, try next package
                   }
                }
                if (queryClass == null)
                {
                   throw new InterpreterException(
                         "Failed to load the class for the constructor", ctorNode, null);
                }
                // cache the class:
                ctorNode.setRuntimeAnnotation(Aast.RUNTIME_CLASS, queryClass);
             }

             int parCount = ctorNode.getNumImmediateChildren();
             Class<?>[] parTypes = new Class[parCount];
             parValues = collectParameters(ctorNode, parTypes, 0);

             // look for the constructor
             try
             {
                ctor = queryClass.getDeclaredConstructor(parTypes);
             }
             catch (NoSuchMethodException e)
             {
                // attempt to do it manually (because of null values most likely)
                ctor = findMatchingConstructor(queryClass, parTypes);
                if (ctor == null)
                {
                   throw new InterpreterException(
                         "Failed to lookup the constructor with required signature", ctorNode, null);
                }
             }
             // cache the c'tor:
             ctorNode.setRuntimeAnnotation(Aast.RUNTIME_CONSTRUCTOR, ctor);
          }

          if (parValues == null)
          {
             // collect parameters now if not done already
             parValues = collectParameters(ctorNode, null, 0);
          }

          Object res = null;
          // invoke the constructor
          try
          {
             res = ctor.newInstance(parValues);

             if (instanceProcessor != null)
             {
                instanceProcessor.accept(res);
             }
          }
          catch (ReflectiveOperationException e)
          {
             throw new InterpreterException(
                "Error invoking constructor: " + ctor.toString(), ctorNode, e);
          }

          return res;
       }

       /**
        * Collects the list of parameters to a method/staticMethod/constructor and, optionally, the
        * signature in a pre-allocated table.
        *
        * @param   methNode
        *          The method node whose children will be inspected. It can be any type of node,
        *          but the operation only makes sense for METHOD_CALL, STATIC_METHOD_CALL and
        *          CONSTRUCTOR nodes.
        * @param   signature
        *          Optional. If not null, at return, it will be populated with the method signature.
        *          If provided (not null), it must be allocated to match the signature size.
        * @param   startAt
        *          The number of children to be ignored. In the case of standard METHOD_CALLs, the
        *          first child is the object on which the method will be applied so it must be
        *          skipped (startAt = 1). Otherwise should be 0.
        *
        * @return  an array with the values of the arguments for this method.
        */
       private Object[] collectParameters(Aast methNode, Class<?>[] signature, int startAt)
       {
          int parCount = methNode.getNumImmediateChildren() - startAt;
          Object[] parValues = new Object[parCount];

          assert (signature == null || signature.length == parCount);

          // iterate constructor parameters:
          for (int k = 0; k < parCount; k++)
          {
             parValues[k] = evalExpression(methNode.getChildAt(k + startAt));
             if (signature != null)
             {
                signature[k] = (parValues[k] == null) ? null : parValues[k].getClass();
             }
          }
          return parValues;
       }

       /**
        * Call a normal member method. If the method returns a value (function) it it will be
        * obtained as the result.
        * <p>
        * The method will try to use the cached annotation from the node to speed up evaluation.
        * If not available, it will use reflection to resolve it. Once computed, the Method
        * object will be stored for future calls.
        * <p>
        * Before calling the method, all children nodes are (recursively) evaluated.
        *
        * @param   aMethod
        *          The method node to be evaluated.
        *
        * @return  the result of calling the method on fist child, possible null
        */
       private Object callMethod(Aast aMethod)
       {
          assert (aMethod.getType() == JavaTokenTypes.METHOD_CALL);

          Method   method    = null;
          Class<?> aClass    = null;
          Object[] parValues = null;
          Object   obj       = null;
          int      minargs   = readMinArgs(aMethod);

          // 1st: find the object on which we invoke the method
          Aast ref = (Aast) aMethod.getFirstChild();
          if (ref.getType() == JavaTokenTypes.LPARENS)
          {
             ref = (Aast) ref.getFirstChild();
          }

          switch (ref.getType())
          {
             case JavaTokenTypes.CONSTRUCTOR:
                obj = callCtor(ref);
                break;

             case JavaTokenTypes.METHOD_CALL:
                obj = callMethod(ref); // recursive call
                break;

             case JavaTokenTypes.REFERENCE:
                // basic invocation: this should be a variable
                String refName = ref.getText();
                if (variables.containsKey(refName))
                {
                   obj = variables.get(refName);
                   break;
                }
                else if (buffers.containsKey(refName))
                {
                   obj = buffers.get(refName);

                   // NOTE: in dynamic queries, : and :: return some kind of value that is neither
                   //    null, neither not null. The EQ operator always returns FALSE and NE always
                   //    returns TRUE, even if compared with ? (unknown value).

                   break;
                }
                else
                {
                   throw new InterpreterException("Failed to execute method on reference", ref, null);
                }

             default:
                // TODO: chaining not implemented
                throw new InterpreterException("Unknown type of object to execute a method", ref, null);
          }
          aClass = obj.getClass();
          aMethod.setRuntimeAnnotation(Aast.RUNTIME_CLASS, aClass);

          // 2nd: find the method to be called
          Object cachedMethod = getCache(aMethod, Aast.RUNTIME_METHOD);

          if (cachedMethod instanceof Method)
          {
             method = (Method) cachedMethod;
          }
          else
          {
             String methodName = aMethod.getText();
             int parCount = aMethod.getNumImmediateChildren() - 1;
             Class<?>[] parTypes = new Class[parCount];
             parValues = collectParameters(aMethod, parTypes, 1); // skip the 1st child

             Class<?> itClass = aClass;

             // attempt to use simple reflection for all super classes
             while (itClass != null)
             {
                try
                {
                   method = itClass.getDeclaredMethod(methodName, parTypes);

                   // if we found the method, exit the while loop
                   break;
                }
                catch (NoSuchMethodException e)
                {
                   // do nothing, expected exception if method not defined here
                }

                itClass = itClass.getSuperclass();
             }

             if (method == null)
             {
                // attempt to do it manually (because of null values most likely)
                method = findMatchingMethod(aClass, methodName, parTypes, minargs);
             }

             if (method != null)
             {
                aMethod.setRuntimeAnnotation(Aast.RUNTIME_METHOD, method);
             }
             else
             {
                throw new InterpreterException(
                      "Failed to detect the method to be called", aMethod, null);
             }
          }

          if (parValues == null)
          {
             // collect parameters now if not done already
             parValues = collectParameters(aMethod, null, 1);
          }

          // 3rd: do the dew: invoke the method on the object
          Object res = null;
          try
          {
             parValues = fixupParameters(method, false, parValues);

             res = Utils.invoke(method, obj, parValues);
          }
          catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e)
          {
             throw new InterpreterException("Failed to execute method", aMethod, e);
          }
          return res;
       }

       /**
        * Check the given node for a "minargs" annotation and return it if present.
        *
        * @param    node
        *           The node to check.
        *
        * @return   The value of the annotation or -1 if the annotation is not present.
        */
       private int readMinArgs(Aast node)
       {
          int minargs = -1;

          // support varargs if minargs is set
          if (node.isAnnotation("minargs"))
          {
             minargs = ((Long) node.getAnnotation("minargs")).intValue();
          }

          return minargs;
       }

       /**
        * For varargs methods, rework the last parameters into an array of the proper type.
        *
        * @param    method
        *           The method to be considered.
        * @param    isStatic
        *           <code>true</code> if this is a static method, <code>false</code> for an instance
        *           method.
        * @param    parValues
        *           The parameters as passed by the converted code.
        *
        * @return   The original paramter list if no changes are needed. For varargs calls where
        *           fixups are needed, a rewritten array will be returned (and the original
        *           array should not be used in the subsequent invocation of the method).
        */
       private Object[] fixupParameters(Method method, boolean isStatic, Object[] parValues)
       {
          Object[] parms = parValues;

          // we only do something if the method uses varargs
          if (method.isVarArgs())
          {
             int num  = method.getParameterCount();
             int last = parValues.length - 1;
             int from = num - 1; // may be the same as last, or smaller

             boolean big = (parValues.length > num);

             Class<?>[] types = method.getParameterTypes();

             // there are 2 ways to detect if fixups are needed:
             // - given argument list is a different length than required
             // - the type of the last given parameter does not match the array type required
             if (big || !(parValues[last].getClass().equals(types[from])))
             {
                // allocate the parameter array for the expected parameter list (may be smaller than
                // the original)
                parms = Arrays.copyOf(parValues, num);

                // the last element must be converted to an array of the proper type (will hold the
                // varargs)
                parms[from] = Array.newInstance(types[from].getComponentType(),
                                                parValues.length - from);

                // copy the elements from the original array into the varargs array
                for (int i = from; i < parValues.length; i++)
                {
                   int n = i - from;

                   ((Object[])(parms[from]))[n] =  parValues[i];
                }
             }

             if (LOG.isLoggable(Level.FINER))
             {
                LOG.finer(String.format("Processing method %s with %d formal parms.", method.getName(), num));

                for (Class<?> cls : types)
                {
                   LOG.finer(String.format("   %s (expected)", cls.toString()));
                }
                for (Object obj : parValues)
                {
                   LOG.finer(String.format("   '%s' of type %s (given)", obj.toString(), obj.getClass().toString()));

                   if (obj.getClass().isArray())
                   {
                      Object[] vals = (Object[])obj;

                      for (Object val : vals)
                      {
                         LOG.finer(String.format("      element '%s' of type %s", val.toString(), val.getClass().toString()));
                      }
                   }
                }
                for (Object obj : parms)
                {
                   LOG.finer(String.format("   '%s' of type %s (fixed up)", obj.toString(), obj.getClass().toString()));

                   if (obj.getClass().isArray())
                   {
                      Object[] vals = (Object[])obj;

                      for (Object val : vals)
                      {
                         LOG.finer(String.format("      element '%s' of type %s", val.toString(), val.getClass().toString()));
                      }
                   }
                }
             }
          }

          return parms;
       }

       /**
        * Call a static method. If the method returns a value (function) it it will be
        * obtained as the result.
        * <p>
        * The method will try to use the cached annotation from the node to speed up evaluation.
        * If not available, it will use reflection to resolve it. Once computed, the Method
        * object will be stored for future calls.
        * <p>
        * Before calling the method, all children nodes are (recursively) evaluated.
        *
        * @param   staticMethod
        *          The method node to be evaluated.
        *
        * @return  the result of calling the static method, possible null
        */
       private Object callStaticMethod(Aast staticMethod)
       {
          assert (staticMethod.getType() == JavaTokenTypes.STATIC_METHOD_CALL);

          Method   method      = null;
          Class<?> staticClass = null;
          Object[] parValues   = null;
          int      minargs     = readMinArgs(staticMethod);
          String   methodName  = staticMethod.getText();

          // the dynamic calls do not cache the "runtime-value", instead the dynamicCalls map is used
          boolean dynamicCall = (dynamicCalls != null) && methodName.startsWith(DYNAMIC_CALL);
          if (dynamicCall)
          {
             Object cached = dynamicCalls.get(staticMethod);
             // was it already evaluated?
             if (cached != NOT_EVALUATED)
             {
                return cached;
             }
             // else evaluate it normally and cache the result in dynamicCalls map
          }

          // try to use the runtime annotation to speed up the interpreter
          Object cachedMethod = getCache(staticMethod, Aast.RUNTIME_METHOD);

          // check if method is already cached.
          if (cachedMethod instanceof Method)
          {
             method = (Method) cachedMethod;
          }
          else
          {
             // identify the static class for this static method
             // try to use the cached class name, at least
             Object cachedClass = getCache(staticMethod, Aast.RUNTIME_CLASS);
             if (cachedClass instanceof Class)
             {
                // cache hit
                staticClass = (Class<?>) cachedClass;
             }
             else
             {
                // cache missed: try to infer static class from the quantified method name
                // TODO: check if the classname contains the package to load it directly
                int k = methodName.indexOf('.');
                if (k != -1)
                {
                   // <Class>.<methodName>: extract the class name and find the right package
                   String className = methodName.substring(0, k);
                   methodName = methodName.substring(k + 1);

                   for (String path : imports)
                   {
                      try
                      {
                         staticClass = classForName(path + className);
                         break;
                      }
                      catch (ClassNotFoundException e)
                      {
                         // don't worry, try next import path
                      }
                   }

                   if (staticClass == null)
                   {
                      throw new InterpreterException(
                            "Failed to find class for static method", staticMethod, null);
                   }

                   // cache the class object
                   staticMethod.setRuntimeAnnotation(Aast.RUNTIME_CLASS, staticClass);
                }
             }

             int parCount = staticMethod.getNumImmediateChildren();
             Class<?>[] parTypes = new Class[parCount];
             parValues = collectParameters(staticMethod, parTypes, 0);

             if (staticClass != null)
             {
                // method is actually quantified with a static class; do the resolution NOW!
                try
                {
                   method = staticClass.getDeclaredMethod(methodName, parTypes);
                }
                catch (NoSuchMethodException e)
                {
                   // attempt to do it manually (because of null values most likely)
                   method = findMatchingMethod(staticClass, methodName, parTypes, minargs);
                   if (method == null)
                   {
                      throw new InterpreterException(
                            "Failed to find static method from class", staticMethod, e);
                   }
                }
             }

             // still no method found; maybe it wasn't quantified with a static class
             // check the static imports then
             if (method == null)
             {
                // we do not know the classname, we will use the static import list
                for (Class<?> aClass : staticImports)
                {
                   try
                   {
                      method = aClass.getDeclaredMethod(methodName, parTypes);
                   }
                   catch (NoSuchMethodException e)
                   {
                      // attempt to do it manually (because of [null] values, most likely)
                      method = findMatchingMethod(aClass, methodName, parTypes, minargs);
                   }

                   if (method != null)
                   {
                      // yes, we found it!
                      staticClass = aClass;
                      staticMethod.setRuntimeAnnotation(Aast.RUNTIME_CLASS, staticClass);
                      break;
                   }
                   // otherwise, no problemo, try the next class
                }
             }

             // too bad; no method was found
             if (method == null)
             {
                throw new InterpreterException(
                      "Failed to find static method from class", staticMethod, null);
             }

             // cache the method name for later use
             staticMethod.setRuntimeAnnotation(Aast.RUNTIME_METHOD, method);
          }

          if (parValues == null)
          {
             // collect parameters now if not done already
             parValues = collectParameters(staticMethod, null, 0);
          }

          Object res = null;

          // invoke the method
          try
          {
             parValues = fixupParameters(method, true, parValues);

             res = Utils.invoke(method, null, parValues);
          }
          catch (IllegalAccessException | InvocationTargetException | IllegalArgumentException e)
          {
             throw new InterpreterException("Failed to execute static method", staticMethod, e);
          }

          if (dynamicCall)
          {
             dynamicCalls.put(staticMethod, res);
          }
          return res;
       }

       /**
        * Evaluates an expression to a value that is returned.
        * If the node evaluates to a constant, it is cashed for fast access.
        * If it is a reference to a buffer, the list of buffers is checked. Similar for variables.
        *
        * @param   exprNode
        *          The JAST node that contains the expression.
        *
        * @return  the value of the expression.
        */
       private Object evalExpression(Aast exprNode)
       {
          if (exprNode.isRuntimeAnnotation(Aast.RUNTIME_VALUE))
          {
             // this node has been already processed and decided the result is constant
             Object res = getCache(exprNode, Aast.RUNTIME_VALUE);
             return res;
          }

          String nodeText = exprNode.getText();
          Object res = null;
          switch (exprNode.getType())
          {
             case JavaTokenTypes.CONSTRUCTOR:
                res = callCtor(exprNode);
                break;

             case JavaTokenTypes.METHOD_CALL:
                res = callMethod(exprNode); // keep the result (function case)
                break;

             case JavaTokenTypes.LPARENS:
                res = evalExpression((Aast) exprNode.getFirstChild());
                break;

             case JavaTokenTypes.PLACEHOLDER:
                res = evalExpression((Aast) exprNode.getFirstChild());
                break;

             case JavaTokenTypes.CAST:
                res = evalExpression((Aast) exprNode.getFirstChild());
                if (!exprNode.isRuntimeAnnotation(Aast.RUNTIME_CLASS))
                {
                   // if not already set
                   exprNode.setRuntimeAnnotation(Aast.RUNTIME_CLASS, getClass(nodeText));
                }
                break;

             case JavaTokenTypes.STRING:
                res = StringHelper.processEscapes(nodeText);
                // avoid processing java escapes the next time
                exprNode.setRuntimeAnnotation(Aast.RUNTIME_VALUE, res);
                break;

             case JavaTokenTypes.EXPRESSION:
                res = evalExpression((Aast) exprNode.getFirstChild());
                break;

             case JavaTokenTypes.MEMBER:
                Class<?> queryClass = null;
                Aast of = (Aast) exprNode.getFirstChild();
                for (String path : imports)
                {
                   // load class | TODO: (extract common code for class by name from imports)
                   String ctorClass = path + of.getText();
                   try
                   {
                      queryClass = classForName(ctorClass);
                      break; // found it
                   }
                   catch (ClassNotFoundException e)
                   {
                      // not the right package this class, try next package
                   }
                }
                if (queryClass == null)
                {
                   throw new InterpreterException(
                        "Failed to load the class for the member evaluation", exprNode, null);
                }
                try
                {
                   Field member = queryClass.getDeclaredField(exprNode.getText());
                   res = member.get(null); // MEMEBER are always static ?
                }
                catch (NoSuchFieldException | IllegalAccessException e)
                {
                   throw new InterpreterException(
                         "Failed to find member in parent class", exprNode, e);
                }

                break;
             case JavaTokenTypes.REFERENCE_DEF:
                if ("new Object".equals(nodeText))
                {
                   Aast initializer = (Aast) exprNode.getNextSibling();
                   int childrenCount = initializer.getNumImmediateChildren();
                   Object[] objectArray = new Object[childrenCount];
                   for (int k = 0; k < childrenCount; k++)
                   {
                      objectArray[k] = evalExpression(initializer.getChildAt(k));
                   }
                   res = objectArray;
                   break;
                }

                throw new InterpreterException("Unknown REFERENCE_DEF type", exprNode, null);

             case JavaTokenTypes.REFERENCE:
                // first check if this is a buffer
                if (buffers.containsKey(nodeText))
                {
                   res = buffers.get(nodeText);
                   break;
                }

                // prepare for array identifiers
                String identName = null;
                int arrayIndex = -1;
                int lsb = nodeText.indexOf('[');
                int rsb = nodeText.indexOf(']');
                if (lsb == -1 && rsb == -1)
                {
                   identName = nodeText;
                }
                else if (lsb != -1 && rsb != -1 && lsb < rsb)
                {
                   identName = nodeText.substring(0, lsb);
                   arrayIndex = Integer.parseInt(nodeText.substring(lsb + 1, rsb));
                }

                if (identName != null)
                {
                   boolean checkArray = false;
                   // or perhaps a method parameter name ?
                   if (methodArgs.locate(identName) != -1)
                   {
                      res = methodArgs.lookup(identName);
                      checkArray = true;
                   }
                   // or perhaps a variable name ?
                   else if (variables.containsKey(identName))
                   {
                      res = variables.get(identName);
                      checkArray = true;
                   }

                   if (checkArray) // check if only an item from array is requested
                   {
                      if (arrayIndex >= 0 && res instanceof Object[])
                      {
                         Object[] ufo = (Object[]) res;
                         res = ufo[arrayIndex];
                      }
                      break;
                   }
                }

                throw new InterpreterException(
                      "No REFERENCE named (" + nodeText + ")", exprNode, null);

             case JavaTokenTypes.NUM_LITERAL:
                if (nodeText.endsWith("L"))
                {
                   nodeText = nodeText.substring(0, nodeText.length() - 1);
                   res = Long.parseLong(nodeText);
                }
                else
                {
                   res = Integer.parseInt(nodeText);
                }
                exprNode.setRuntimeAnnotation(Aast.RUNTIME_VALUE, res); // save constant to cache
                break;

             case JavaTokenTypes.BOOL_FALSE:
                res = Boolean.FALSE;
                exprNode.setRuntimeAnnotation(Aast.RUNTIME_VALUE, Boolean.FALSE); // save const to cache
                break;

             case JavaTokenTypes.BOOL_TRUE:
                res = Boolean.TRUE;
                exprNode.setRuntimeAnnotation(Aast.RUNTIME_VALUE, Boolean.TRUE); // save const to cache
                break;

             case JavaTokenTypes.NULL_LITERAL:
                // a null parameter. It will make it difficult to select the correct method/c'tor
                res = null;
                exprNode.setRuntimeAnnotation(Aast.RUNTIME_VALUE, null); // save const to cache
                break;

             case JavaTokenTypes.STATIC_METHOD_CALL:
                res = callStaticMethod(exprNode);
                break;

             case JavaTokenTypes.TERN_IF_ELSE:
                Aast cond = (Aast) exprNode.getFirstChild();
                Object bool = evalExpression(cond);
                if (bool instanceof Boolean)
                {
                   Aast first = (Aast) cond.getNextSibling();
                   if ((Boolean) bool)
                   {
                      res = evalExpression(first);
                   }
                   else
                   {
                      res = evalExpression((Aast) first.getNextSibling());
                   }
                   break;
                }
                else
                {
                   throw new InterpreterException(
                         "Not a logical expression type in ternary IF ", exprNode, null);
                }

             // TODO: Can this be removed?  If it is only ever used for WHERE clauses, then this
             //       is probably dead code. However, these kinds of constructors can be generated
             //       for complex BY clauses in conversion.  Are they in play here?
             case JavaTokenTypes.ANON_CTOR:
                // we handle only the well known cases:
                switch (exprNode.getText())
                {
                   case "CharacterExpression":
                      res = buildTypedExpression(exprNode, "character");
                      break;
                   case "DateExpression":
                      res = buildTypedExpression(exprNode, "date");
                      break;
                   case "DatetimeExpression":
                      res = buildTypedExpression(exprNode, "datetime");
                      break;
                   case "DatetimeTzExpression":
                      res = buildTypedExpression(exprNode, "datetimetz");
                      break;
                   case "DecimalExpression":
                      res = buildTypedExpression(exprNode, "decimal");
                      break;
                   case "Int64Expression":
                      res = buildTypedExpression(exprNode, "int64");
                      break;
                   case "IntegerExpression":
                      res = buildTypedExpression(exprNode, "integer");
                      break;
                   case "LogicalExpression":
                      res = buildTypedExpression(exprNode, "logical");
                      break;
                   case "RawExpression":
                      res = buildTypedExpression(exprNode, "raw");
                      break;
                   case "RecidExpression":
                      res = buildTypedExpression(exprNode, "recid");
                      break;
                   case "RowidExpression":
                      res = buildTypedExpression(exprNode, "rowid");
                      break;
                   default:
                      throw new InterpreterException("Unknown anonymous constructor", exprNode, null);
                }
                break;

             case JavaTokenTypes.LAMBDA:

                if (exprNode.isAnnotation("client_where") &&
                    (Boolean) exprNode.getAnnotation("client_where"))
                {
                   res = new ClientWhere(this, exprNode);
                   break;
                }

                Aast parentJast = exprNode.getParent();
                if (parentJast.getType() == JavaTokenTypes.CAST)
                {
                   String cast = parentJast.getText();

                   switch (cast)
                   {
                      case "P2JQuery.Parameter":
                         res = new P2JQueryParameter(this, exprNode);
                         break;
                      case "CharacterExpr":
                         res = new CharacterExprAdapter(this, exprNode);
                         break;
                      case "DateExpr":
                         res = new DateExprAdapter(this, exprNode);
                         break;
                      case "DatetimeExpr":
                         res = new DatetimeExprAdapter(this, exprNode);
                         break;
                      case "DatetimeTzExpr":
                         res = new DatetimeTzExprAdapter(this, exprNode);
                         break;
                      case "DecimalExpr":
                         res = new DecimalExprAdapter(this, exprNode);
                         break;
                      case "Int64Expr":
                         res = new Int64ExprAdapter(this, exprNode);
                         break;
                      case "IntegerExpr":
                         res = new IntegerExprAdapter(this, exprNode);
                         break;
                      case "LogicalExpr":
                         res = new LogicalExprAdapter(this, exprNode);
                         break;
                      case "RawExpr":
                         res = new RawExprAdapter(this, exprNode);
                         break;
                      case "RecidExpr":
                         res = new RecidExprAdapter(this, exprNode);
                         break;
                      case "RowidExpr":
                         res = new RowidExprAdapter(this, exprNode);
                         break;
                      case "P2JQuery.ParamResolver":
                         res = new P2JQueryParamResolver(this, exprNode);
                         break;
                      default:
                         String msg = "Unknown CAST expression type %s ";
                         throw new InterpreterException(String.format(msg, cast), exprNode, null);
                   }

                   break;
                   // TODO: collect other CAST-ed lambda types
                }

                // default to LogicalLambda class
                res = new LogicalLambda(this, exprNode);
                break;

             default:
                throw new InterpreterException("Unknown expression type", exprNode, null);
          }

          if (res instanceof BaseDataType && BaseDataType.isProxy((BaseDataType) res))
          {
             res = ((BaseDataType) res).val();
          }

          return res;
       }

       /**
        * Build an anonymous object that extends some kind of typed expression:
        * {@link IntegerExpression}, {@link LogicalExpression}, {@link DateExpression} etc.
        *
        * @param   typedExpr
        *          The JAST node that describe the new object to be built.
        * @param   retType
        *          The return type JAST of the {@code execute} method of the expected class type.
        *          Must not be {@code null} or empty.
        *
        * @return  the object built
        */
       private Resolvable buildTypedExpression(Aast typedExpr, String retType)
       {
          assert (typedExpr.getType() == JavaTokenTypes.ANON_CTOR);

          if (LOG.isLoggable(Level.FINER))
          {
             LOG.finer(typedExpr.dumpTree(true));
          }

          Aast allMethods = typedExpr.getImmediateChild(JavaTokenTypes.CS_INSTANCE_METHODS, null);
          assert (allMethods != null && allMethods.getNumImmediateChildren() != 0);

          JavaAst executeMethod = null;
          Aast meth = allMethods.getImmediateChild(JavaTokenTypes.METHOD_DEF, null);
          while (meth != null)
          {
             if ("execute".equals(meth.getText()) &&
                 retType.equals(meth.getAnnotation("rettype")))
             {
                // TODO: the full signature is not checked, no other overloaded method should exist
                executeMethod = (JavaAst) meth;
             }
             meth = allMethods.getImmediateChild(JavaTokenTypes.METHOD_DEF, meth);
          }

          switch (retType)
          {
             case "logical":
                return new LogicalExpressionAdapter(this, executeMethod);
             case "integer":
                return new IntegerExpressionAdapter(this, executeMethod);
             case "int64":
                return new Int64ExpressionAdapter(this, executeMethod);
             case "date":
                return new DateExpressionAdapter(this, executeMethod);
             case "datetime":
                return new DatetimeExpressionAdapter(this, executeMethod);
             case "datetimetz":
                return new DatetimeTzExpressionAdapter(this, executeMethod);
             case "character":
                return new CharacterExpressionAdapter(this, executeMethod);
             case "decimal":
                return new DecimalExpressionAdapter(this, executeMethod);
             case "rowid":
                return new RowidExpressionAdapter(this, executeMethod);
             // case "handle":
             //    return new HandleExpressionAdapter(this, executeMethod);
             case "raw":
                return new RawExpressionAdapter(this, executeMethod);
             default:
                throw new InterpreterException("Unknown anonymous constructor", typedExpr, null);
          }
       }

       /**
        * Obtain the class by its name.
        * <p>
        * At this moment this is only used by CAST nodes.
        * <p>
        * For performance issues, the classes are hardcoded in a String switch. Using the reflection
        * and iterating through all all packages imported uses a great amount of CPU cycles. Other
        * classes will be possible added in the future as they occur in the client code.
        *
        * @param   nodeText
        *          The class name.
        *
        * @return  The requested Class object.
        */
       private Class<?> getClass(String nodeText)
       {
          // this is a fast out
          switch (nodeText)
          {
             // java.lang:
             case "String":
                return java.lang.String.class;

             // BaseDataType
             case "logical":
                return com.goldencode.p2j.util.logical.class;
             case "integer":
                return com.goldencode.p2j.util.integer.class;
             case "int64":
                return com.goldencode.p2j.util.int64.class;
             case "date":
                return com.goldencode.p2j.util.date.class;
             case "datetime":
                return com.goldencode.p2j.util.datetime.class;
             case "datetimetz":
                return com.goldencode.p2j.util.datetimetz.class;
             case "character":
                return com.goldencode.p2j.util.character.class;
             case "decimal":
                return com.goldencode.p2j.util.decimal.class;
             case "raw":
                return com.goldencode.p2j.util.raw.class;
             case "recid":
                return com.goldencode.p2j.util.recid.class;
             case "rowid":
                return com.goldencode.p2j.util.rowid.class;

             // Resolvable types:
             case "LogicalExpr":
                return com.goldencode.p2j.persist.LogicalExpr.class;
             case "IntegerExpr":
                return com.goldencode.p2j.persist.IntegerExpr.class;
             case "Int64Expr":
                return com.goldencode.p2j.persist.Int64Expr.class;
             case "DateExpr":
                return com.goldencode.p2j.persist.DateExpr.class;
             case "DatetimeExpr":
                return com.goldencode.p2j.persist.DatetimeExpr.class;
             case "DatetimeTzExpr":
                return com.goldencode.p2j.persist.DatetimeTzExpr.class;
             case "CharacterExpr":
                return com.goldencode.p2j.persist.CharacterExpr.class;
             case "DecimalExpr":
                return com.goldencode.p2j.persist.DecimalExpr.class;
             case "RawExpr":
                return com.goldencode.p2j.persist.RawExpr.class;
             case "RecidExpr":
                return com.goldencode.p2j.persist.RecidExpr.class;
             case "RowidExpr":
                return com.goldencode.p2j.persist.RowidExpr.class;

             // other P2J specific types
             case "P2JQuery.Parameter":
                return com.goldencode.p2j.persist.P2JQuery.Parameter.class;
             case "P2JQuery.ParamResolver":
                return com.goldencode.p2j.persist.P2JQuery.ParamResolver.class;

             default:
                throw new InterpreterException("Unknown class type: " + nodeText, null, null);
          }
       }

       /**
        * Look into the list of constructors for a class for the one that matches the list of
        * argument types. Only return a valid object if there is a clean choice. In case of
        * collisions (multiple matching) null is returned as error.
        *
        * @param   aClass
        *          The class whose constructor list is checked.
        * @param   signature
        *          An array with the java types of the arguments of the required constructor. Use null
        *          as a wildcard for unknown or null parameter type.
        *
        * @return  the matching constructor. If none is found, null is returned. null is also returned
        *          if multiple constructors are found to match the signature
        */
       private static Constructor<?> findMatchingConstructor(Class<?> aClass, Class<?>[] signature)
       {
          Constructor<?> ret = null;
          for (Constructor<?> ctor : aClass.getDeclaredConstructors())
          {
             Class<?>[] required = ctor.getParameterTypes();
             if (Function.matchSignature(required, signature, -1, true))
             {
                if (ret != null)
                {
                   if (LOG.isLoggable(Level.WARNING))
                   {
                      LOG.log(Level.WARNING,
                              "Two matching constructors were found for class " +
                                      aClass.getName() +
                                      " in run-time JAST interpreter");
                      if (LOG.isLoggable(Level.FINE))
                      {
                         LOG.log(Level.FINE, "Location: ", new Throwable());
                      }
                   }
                   break;
                }

                // do not return yet, check for sanity
                ret = ctor;
             }
          }
          return ret;
       }

       /**
        * Look into the list of methods of a class for the one that matches name and the list of
        * argument types. Only return a valid object if there is a clean choice. In case of
        * collisions (multiple matching) null is returned as error.
        * The process is rather costly. the worse case scenario involves a second pass to re-analyze
        * the list overloaded methods if the first one (in strict mode) provided no solution.
        * <p>
        * This method calls {@link #findMatchingMethodFromClass}, for each super class until a method
        * with requested name is found, or reaching the top of the hierarchy, in which case
        * {@code null} is returned.
        *
        * @param   aClass
        *          The class whose constructor list is checked.
        * @param   methodName
        *          The method name being searched for.
        * @param   signature
        *          An array with the java types of the arguments of the required constructor. Use null
        *          as a wildcard for unknown or null parameter type.
        * @param   minargs
        *          The minimum number of arguments for this call (used to detect varargs matches) or
        *          -1 if no varargs support is used.
        *
        * @return  the matching constructor. If none is found, null is returned. null is also returned
        *          if multiple constructors are found to match the signature
        */
       private Method findMatchingMethod(Class<?>   aClass,
                                         String     methodName,
                                         Class<?>[] signature,
                                         int        minargs)
       {
          while (aClass != null)
          {
             Method ret = findMatchingMethodFromClass(aClass, methodName, signature, minargs);
             if (ret != null)
             {
                return ret;
             }
             aClass = aClass.getSuperclass();
          }
          return null;
       }

       /**
        * Look into the list of methods of a class for the one that matches name and the list of
        * argument types. Only return a valid object if there is a clean choice. In case of
        * collisions (multiple matching) null is returned as error.
        * The process is rather costly. the worse case scenario involves a second pass to re-analyze
        * the list overloaded methods if the first one (in strict mode) provided no solution.
        * <p>
        * This method is called only from {@link #findMatchingMethod}.
        *
        * @param   aClass
        *          The class whose constructor list is checked.
        * @param   methodName
        *          The method name being searched for.
        * @param   signature
        *          An array with the java types of the arguments of the required constructor. Use
        *          {@code null} as a wildcard for unknown or {@code null} parameter type.
        * @param   minargs
        *          The minimum number of arguments for this call (used to detect varargs matches) or
        *          -1 if no varargs support is used.
        *
        * @return  the matching constructor. If none is found, {@code null} is returned. {@code null}
        *          is also returned if multiple constructors are found to match the signature.
        */
       private Method findMatchingMethodFromClass(Class<?>   aClass,
                                                  String     methodName,
                                                  Class<?>[] signature,
                                                  int        minargs)
       {
          Method ret = null;
          Set<Method> overloaded = new HashSet<>();
          Set<Method> strictCheck = new HashSet<>();
          for (Method meth : aClass.getDeclaredMethods())
          {
             if (meth.isSynthetic() || !meth.getName().equals(methodName))
             {
                continue; // the name does not match
             }

             overloaded.add(meth); // collect overloaded methods for a second iteration
             Class<?>[] required = meth.getParameterTypes();

             // try strict checking first
             if (Function.matchSignature(required, signature, minargs, true))
             {
                strictCheck.add(meth);
                ret = meth;
             }
          }

          if (strictCheck.size() == 1)
          {
             // only one perfect match:
             return ret;
          }
          else if (strictCheck.size() != 0)
          {
             // TODO: choose the most specific form of overloaded method
             //       * simple case with a single parameter:
             //          how to pick between: valueOf(Object), valueOf(BDT) when the argument is char ?
             //       * complex case:
             //          four classes: a extends A, b extends B
             //          two methods: m(A, b), m(a, B)
             //          which method is called when m(a, b) is invoked?
             // temporary fix: return one of them, assuming they are well written (valueOf(Object) tests the
             //       parameter type and invokes valueOf(BDT) when appropriate)
             return ret;
          }

          if (ret == null && !overloaded.isEmpty())
          {
             // second chance, check no-strict for overloaded methods
             for (Method meth : overloaded)
             {
                Class<?>[] required = meth.getParameterTypes();

                // now try non-strict checking
                if (Function.matchSignature(required, signature, minargs, false))
                {
                   // TODO: this is not correct we should refine the search the same way java does
                   // Ex: if the sig is an Integer and there are two methods: Long & Double
                   // Solution: sort overloaded on auto-promotions and choose the first match ?
                   ret = meth;
                   break;
                }
             }
          }

          return ret;
       }

       /***
        * Inspects the node annotation for a runtime cached value. By convention, such annotations
        * have "runtime-" prefix.
        *
        * The reason of existence of this method is debugging, to print the already computed
        * runtime-annotations for a node.
        *
        * @param   node
        *          The JAST node to be inspected.
        * @param   key
        *          The annotation name.
        *
        * @return  the annotation value, or null, if annotation is not present.
        */
       private Object getCache(Aast node, int key)
       {
          Object o = node.getRuntimeAnnotation(key);
          if (o != null && LOG.isLoggable(Level.FINER))
          {
             LOG.finer("Found cached " + key + " for " + node.toString() +
                                "(" + node.getText() + ") = " + o);
          }
          return o;
       }

       /**
        * Exception thrown within the RuntimeJastInterpreter. It contains the optional JAST node that
        * caused the exceptional situation beside of normal message.
        */
       static class InterpreterException
       extends RuntimeException
       {
          /** Suffix to append to the error message of the cause; may be <code>null</code>. */
          private String messageSuffix;

          /**
           * The constructor.
           *
           * @param   message
           *          Message that explains the situation.
           * @param   node
           *          The node that caused the exception, possible null in some case.
           * @param   cause
           *          Another Throwable that caused this exception, possible none.
           */
          public InterpreterException(String message, Aast node, Throwable cause)
          {
             super(message, cause);

             if (node != null)
             {
                messageSuffix = " in [" + node.toString() + ": " + node.getText() + "].";
             }

             if (LOG.isLoggable(Level.FINE))
             {
                LOG.log(Level.FINE, message, cause);
                if (node != null)
                {
                   LOG.fine(System.lineSeparator() + node.dumpTree());
                }
             }
          }

          /**
           * Returns a short description of this exception, the message and  node type and text that
           * caused it if the node was provided at construction.
           *
           * @return  Short description of this exception.
           */
          @Override
          public String toString()
          {
             String s = "Interpreter exception: " + super.getMessage();
             if (messageSuffix != null)
             {
                s += messageSuffix;
             }

             return s;
          }
       }

       /**
        * Adapter for an adapter class built using an anonymous constructor of the class
        * {@link LogicalExpression}. Overriding JASTs should implement at least the {@code execute}
        * method. The evaluation of result of the overridden method is delegated to the interpreter.
        * <p>
        * This class is immutable so the instances of it are constants, once created, the internal
        * data cannot be changed.
        */
       class LogicalExpressionAdapter
       extends LogicalExpression
       {
          /**
           * The {@code RuntimeJastInterpreter} that will handle interpretation of this anonymous
           * object. Must not be {@code null}.
           */
          private RuntimeJastInterpreter interpreter;

          /**
           * The JAST tree that describes the {@code execute} method to be implemented by this object.
           */
          private JavaAst executeMethod;

          /**
           * The only constructor.
           * Takes a parameters the interpreter to which the evaluation of the {@code execute} method
           * is delegated and the JAST of the implemented method.
           *
           * @param   interpreter
           *          The {@link RuntimeJastInterpreter} responsible with interpretation of the
           *          methods overridden by this anonymous object.
           * @param   executeMethod
           *          The JAST that describes the {@code execute} method.
           */
          public LogicalExpressionAdapter(RuntimeJastInterpreter interpreter,
                                          JavaAst executeMethod)
          {
             this.interpreter = interpreter;
             this.executeMethod = executeMethod;
          }

          /**
           * Evaluates the {@code execute} method. If overridden, the {@code interpreter} is
           * responsible for interpretation of the JAST, otherwise the super method is called.
           *
           * @return  the interpreted result of the method.
           */
          @Override
          public logical execute()
          {
             if (executeMethod == null)
             {
                // not overridden ? call super class' method
                return super.execute();
             }

             Object res = interpreter.execMethod(executeMethod);
             return (logical) res;
          }
       }

       /**
        * Adapter for an adapter class built using an anonymous constructor of the class
        * {@link DateExpression}. Overriding JASTs should implement at least the {@code execute}
        * method. The evaluation of result of the overridden method is delegated to the interpreter.
        * <p>
        * This class is immutable so the instances of it are constants, once created, the internal
        * data cannot be changed.
        */
       static class DateExpressionAdapter
       extends DateExpression
       {
          /**
           * The {@code RuntimeJastInterpreter} that will handle interpretation of this anonymous
           * object. Must not be {@code null}.
           */
          private RuntimeJastInterpreter interpreter;

          /**
           * The JAST tree that describes the {@code execute} method to be implemented by this object.
           */
          private JavaAst executeMethod;

          /**
           * The only constructor.
           * Takes a parameters the interpreter to which the evaluation of the {@code execute} method
           * is delegated and the JAST of the implemented method.
           *
           * @param   interpreter
           *          The {@link RuntimeJastInterpreter} responsible with interpretation of the
           *          methods overridden by this anonymous object.
           * @param   executeMethod
           *          The JAST that describes the {@code execute} method.
           */
          public DateExpressionAdapter(RuntimeJastInterpreter interpreter, JavaAst executeMethod)
          {
             this.interpreter = interpreter;
             this.executeMethod = executeMethod;
          }

          /**
           * Evaluates the {@code execute} method. If overridden, the {@code interpreter} is
           * responsible for interpretation of the JAST, otherwise the super method is called.
           *
           * @return  the interpreted result of the method.
           */
          @Override
          public date execute()
          {
             if (executeMethod == null)
             {
                // not overridden ? call super class' method
                return super.execute();
             }

             Object res = interpreter.execMethod(executeMethod);
             return (date) res;
          }
       }

       /**
        * Adapter for an adapter class built using an anonymous constructor of the class
        * {@link DatetimeExpression}. Overriding JASTs should implement at least the {@code execute}
        * method. The evaluation of result of the overridden method is delegated to the interpreter.
        * <p>
        * This class is immutable so the instances of it are constants, once created, the internal
        * data cannot be changed.
        */
       static class DatetimeExpressionAdapter
       extends DatetimeExpression
       {
          /**
           * The {@code RuntimeJastInterpreter} that will handle interpretation of this anonymous
           * object. Must not be {@code null}.
           */
          private RuntimeJastInterpreter interpreter;

          /**
           * The JAST tree that describes the {@code execute} method to be implemented by this object.
           */
          private JavaAst executeMethod;

          /**
           * The only constructor.
           * Takes a parameters the interpreter to which the evaluation of the {@code execute} method
           * is delegated and the JAST of the implemented method.
           *
           * @param   interpreter
           *          The {@link RuntimeJastInterpreter} responsible with interpretation of the
           *          methods overridden by this anonymous object.
           * @param   executeMethod
           *          The JAST that describes the {@code execute} method.
           */
          public DatetimeExpressionAdapter(RuntimeJastInterpreter interpreter, JavaAst executeMethod)
          {
             this.interpreter = interpreter;
             this.executeMethod = executeMethod;
          }

          /**
           * Evaluates the {@code execute} method. If overridden, the {@code interpreter} is
           * responsible for interpretation of the JAST, otherwise the super method is called.
           *
           * @return  the interpreted result of the method.
           */
          @Override
          public datetime execute()
          {
             if (executeMethod == null)
             {
                // not overridden ? call super class' method
                return super.execute();
             }

             Object res = interpreter.execMethod(executeMethod);
             return (datetime) res;
          }
       }

       /**
        * Adapter for an adapter class built using an anonymous constructor of the class
        * {@link DatetimeTzExpression}. Overriding JASTs should implement at least the {@code execute}
        * method. The evaluation of result of the overridden method is delegated to the interpreter.
        * <p>
        * This class is immutable so the instances of it are constants, once created, the internal
        * data cannot be changed.
        */
       static class DatetimeTzExpressionAdapter
       extends DatetimeTzExpression
       {
          /**
           * The {@code RuntimeJastInterpreter} that will handle interpretation of this anonymous
           * object. Must not be {@code null}.
           */
          private RuntimeJastInterpreter interpreter;

          /**
           * The JAST tree that describes the {@code execute} method to be implemented by this object.
           */
          private JavaAst executeMethod;

          /**
           * The only constructor.
           * Takes a parameters the interpreter to which the evaluation of the {@code execute} method
           * is delegated and the JAST of the implemented method.
           *
           * @param   interpreter
           *          The {@link RuntimeJastInterpreter} responsible with interpretation of the
           *          methods overridden by this anonymous object.
           * @param   executeMethod
           *          The JAST that describes the {@code execute} method.
           */
          public DatetimeTzExpressionAdapter(RuntimeJastInterpreter interpreter,
                                             JavaAst executeMethod)
          {
             this.interpreter = interpreter;
             this.executeMethod = executeMethod;
          }

          /**
           * Evaluates the {@code execute} method. If overridden, the {@code interpreter} is
           * responsible for interpretation of the JAST, otherwise the super method is called.
           *
           * @return  the interpreted result of the method.
           */
          @Override
          public datetimetz execute()
          {
             if (executeMethod == null)
             {
                // not overridden ? call super class' method
                return super.execute();
             }

             Object res = interpreter.execMethod(executeMethod);
             return (datetimetz) res;
          }
       }

       /**
        * Adapter for an adapter class built using an anonymous constructor of the class
        * {@link IntegerExpression}. Overriding JASTs should implement at least the {@code execute}
        * method. The evaluation of result of the overridden method is delegated to the interpreter.
        * <p>
        * This class is immutable so the instances of it are constants, once created, the internal
        * data cannot be changed.
        */
       static class IntegerExpressionAdapter
       extends IntegerExpression
       {
          /**
           * The {@code RuntimeJastInterpreter} that will handle interpretation of this anonymous
           * object. Must not be {@code null}.
           */
          private RuntimeJastInterpreter interpreter;

          /**
           * The JAST tree that describes the {@code execute} method to be implemented by this object.
           */
          private JavaAst executeMethod;

          /**
           * The only constructor.
           * Takes a parameters the interpreter to which the evaluation of the {@code execute} method
           * is delegated and the JAST of the implemented method.
           *
           * @param   interpreter
           *          The {@link RuntimeJastInterpreter} responsible with interpretation of the
           *          methods overridden by this anonymous object.
           * @param   executeMethod
           *          The JAST that describes the {@code execute} method.
           */
          public IntegerExpressionAdapter(RuntimeJastInterpreter interpreter, JavaAst executeMethod)
          {
             this.interpreter = interpreter;
             this.executeMethod = executeMethod;
          }

          /**
           * Evaluates the {@code execute} method. If overridden, the {@code interpreter} is
           * responsible for interpretation of the JAST, otherwise the super method is called.
           *
           * @return  the interpreted result of the method.
           */
          @Override
          public integer execute()
          {
             if (executeMethod == null)
             {
                // not overridden ? call super class' method
                return super.execute();
             }

             Object res = interpreter.execMethod(executeMethod);
             return (integer) res;
          }
       }

       /**
        * Adapter for an adapter class built using an anonymous constructor of the class
        * {@link Int64Expression}. Overriding JASTs should implement at least the {@code execute}
        * method. The evaluation of result of the overridden method is delegated to the interpreter.
        * <p>
        * This class is immutable so the instances of it are constants, once created, the internal
        * data cannot be changed.
        */
       static class Int64ExpressionAdapter
       extends Int64Expression
       {
          /**
           * The {@code RuntimeJastInterpreter} that will handle interpretation of this anonymous
           * object. Must not be {@code null}.
           */
          private RuntimeJastInterpreter interpreter;

          /**
           * The JAST tree that describes the {@code execute} method to be implemented by this object.
           */
          private JavaAst executeMethod;

          /**
           * The only constructor.
           * Takes a parameters the interpreter to which the evaluation of the {@code execute} method
           * is delegated and the JAST of the implemented method.
           *
           * @param   interpreter
           *          The {@link RuntimeJastInterpreter} responsible with interpretation of the
           *          methods overridden by this anonymous object.
           * @param   executeMethod
           *          The JAST that describes the {@code execute} method.
           */
          public Int64ExpressionAdapter(RuntimeJastInterpreter interpreter, JavaAst executeMethod)
          {
             this.interpreter = interpreter;
             this.executeMethod = executeMethod;
          }

          /**
           * Evaluates the {@code execute} method. If overridden, the {@code interpreter} is
           * responsible for interpretation of the JAST, otherwise the super method is called.
           *
           * @return  the interpreted result of the method.
           */
          @Override
          public int64 execute()
          {
             if (executeMethod == null)
             {
                // not overridden ? call super class' method
                return super.execute();
             }

             Object res = interpreter.execMethod(executeMethod);
             return (int64) res;
          }
       }

       /**
        * Adapter for an adapter class built using an anonymous constructor of the class
        * {@link DecimalExpression}. Overriding JASTs should implement at least the {@code execute}
        * method. The evaluation of result of the overridden method is delegated to the interpreter.
        * <p>
        * This class is immutable so the instances of it are constants, once created, the internal
        * data cannot be changed.
        */
       static class DecimalExpressionAdapter
       extends DecimalExpression
       {
          /**
           * The {@code RuntimeJastInterpreter} that will handle interpretation of this anonymous
           * object. Must not be {@code null}.
           */
          private RuntimeJastInterpreter interpreter;

          /**
           * The JAST tree that describes the {@code execute} method to be implemented by this object.
           */
          private JavaAst executeMethod;

          /**
           * The only constructor.
           * Takes a parameters the interpreter to which the evaluation of the {@code execute} method
           * is delegated and the JAST of the implemented method.
           *
           * @param   interpreter
           *          The {@link RuntimeJastInterpreter} responsible with interpretation of the
           *          methods overridden by this anonymous object.
           * @param   executeMethod
           *          The JAST that describes the {@code execute} method.
           */
          public DecimalExpressionAdapter(RuntimeJastInterpreter interpreter, JavaAst executeMethod)
          {
             this.interpreter = interpreter;
             this.executeMethod = executeMethod;
          }

          /**
           * Evaluates the {@code execute} method. If overridden, the {@code interpreter} is
           * responsible for interpretation of the JAST, otherwise the super method is called.
           *
           * @return  the interpreted result of the method.
           */
          @Override
          public decimal execute()
          {
             if (executeMethod == null)
             {
                // not overridden ? call super class' method
                return super.execute();
             }

             Object res = interpreter.execMethod(executeMethod);
             return (decimal) res;
          }
       }

       /**
        * Adapter for an adapter class built using an anonymous constructor of the class
        * {@link CharacterExpression}. Overriding JASTs should implement at least the {@code execute}
        * method. The evaluation of result of the overridden method is delegated to the interpreter.
        * <p>
        * This class is immutable so the instances of it are constants, once created, the internal
        * data cannot be changed.
        */
       static class CharacterExpressionAdapter
       extends CharacterExpression
       {
          /**
           * The {@code RuntimeJastInterpreter} that will handle interpretation of this anonymous
           * object. Must not be {@code null}.
           */
          private RuntimeJastInterpreter interpreter;

          /**
           * The JAST tree that describes the {@code execute} method to be implemented by this object.
           */
          private JavaAst executeMethod;

          /**
           * The only constructor.
           * Takes a parameters the interpreter to which the evaluation of the {@code execute} method
           * is delegated and the JAST of the implemented method.
           *
           * @param   interpreter
           *          The {@link RuntimeJastInterpreter} responsible with interpretation of the
           *          methods overridden by this anonymous object.
           * @param   executeMethod
           *          The JAST that describes the {@code execute} method.
           */
          public CharacterExpressionAdapter(RuntimeJastInterpreter interpreter, JavaAst executeMethod)
          {
             if (executeMethod == null)
             {
                throw new InterpreterException("Anonymous class does not override 'execute' method " +
                                               "from CharacterExpression abstract superclass",
                                               null, null);
             }

             this.interpreter = interpreter;
             this.executeMethod = executeMethod;
          }

          /**
           * Evaluates the {@code execute} method. If overridden, the {@code interpreter} is
           * responsible for interpretation of the JAST, otherwise the super method is called.
           *
           * @return  the interpreted result of the method.
           */
          @Override
          public character execute()
          {
             return (character) interpreter.execMethod(executeMethod);
          }
       }

       /**
        * Adapter for an adapter class built using an anonymous constructor of the class
        * {@link RawExpression}. Overriding JASTs should implement at least the {@code execute}
        * method. The evaluation of result of the overridden method is delegated to the interpreter.
        * <p>
        * This class is immutable so the instances of it are constants, once created, the internal
        * data cannot be changed.
        */
       static class RawExpressionAdapter
       extends RawExpression
       {
          /**
           * The {@code RuntimeJastInterpreter} that will handle interpretation of this anonymous
           * object. Must not be {@code null}.
           */
          private RuntimeJastInterpreter interpreter;

          /**
           * The JAST tree that describes the {@code execute} method to be implemented by this object.
           */
          private JavaAst executeMethod;

          /**
           * The only constructor.
           * Takes a parameters the interpreter to which the evaluation of the {@code execute} method
           * is delegated and the JAST of the implemented method.
           *
           * @param   interpreter
           *          The {@link RuntimeJastInterpreter} responsible with interpretation of the
           *          methods overridden by this anonymous object.
           * @param   executeMethod
           *          The JAST that describes the {@code execute} method.
           */
          public RawExpressionAdapter(RuntimeJastInterpreter interpreter, JavaAst executeMethod)
          {
             if (executeMethod == null)
             {
                throw new InterpreterException("Anonymous class does not override 'execute' method " +
                                               "from RawExpression abstract superclass",
                                               null, null);
             }

             this.interpreter = interpreter;
             this.executeMethod = executeMethod;
          }

          /**
           * Evaluates the {@code execute} method. If overridden, the {@code interpreter} is
           * responsible for interpretation of the JAST, otherwise the super method is called.
           *
           * @return  the interpreted result of the method.
           */
          @Override
          public raw execute()
          {
             return (raw) interpreter.execMethod(executeMethod);
          }
       }

       /**
        * Adapter for an adapter class built using an anonymous constructor of the class
        * {@link RowidExpression}. Overriding JASTs should implement at least the {@code execute}
        * method. The evaluation of result of the overridden method is delegated to the interpreter.
        * <p>
        * This class is immutable so the instances of it are constants, once created, the internal
        * data cannot be changed.
        */
       static class RowidExpressionAdapter
       extends RowidExpression
       {
          /**
           * The {@code RuntimeJastInterpreter} that will handle interpretation of this anonymous
           * object. Must not be {@code null}.
           */
          private RuntimeJastInterpreter interpreter;

          /**
           * The JAST tree that describes the {@code execute} method to be implemented by this object.
           */
          private JavaAst executeMethod;

          /**
           * The only constructor.
           * Takes a parameters the interpreter to which the evaluation of the {@code execute} method
           * is delegated and the JAST of the implemented method.
           *
           * @param   interpreter
           *          The {@link RuntimeJastInterpreter} responsible with interpretation of the
           *          methods overridden by this anonymous object.
           * @param   executeMethod
           *          The JAST that describes the {@code execute} method.
           */
          public RowidExpressionAdapter(RuntimeJastInterpreter interpreter, JavaAst executeMethod)
          {
             if (executeMethod == null)
             {
                throw new InterpreterException("Anonymous class does not override 'execute' method " +
                                               "from RowidExpression abstract superclass",
                                               null, null);
             }

             this.interpreter = interpreter;
             this.executeMethod = executeMethod;
          }

          /**
           * Evaluates the {@code execute} method. If overridden, the {@code interpreter} is
           * responsible for interpretation of the JAST, otherwise the super method is called.
           *
           * @return  the interpreted result of the method.
           */
          @Override
          public rowid execute()
          {
             return (rowid) interpreter.execMethod(executeMethod);
          }
       }

       /**
        * Implements an interpreted generic lambda expression stored as a JAST node, using the
        * {@code RuntimeJastInterpreter}.
        */
       abstract static class Lambda
       {
          /**
           * The {@code RuntimeJastInterpreter} that will handle interpretation of this lambda
           * expression. Must not be {@code null}.
           */
          protected RuntimeJastInterpreter interpreter;

          /**
           * The JAST node that contains the expression this lambda expression evaluates to.
           * Always not {@code null}.
           */
          protected Aast valueNode;

          /** The list of parameters for this lambda expression */
          protected Aast paramNodes;

          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public Lambda(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             // validate the arguments
             if (interpreter == null                       ||
                 lambdaNode == null                        ||
                 lambdaNode.getNumImmediateChildren() != 2 ||
                 lambdaNode.getChildAt(0).getType() != JavaTokenTypes.LPARENS)
             {
                throw new InterpreterException("Invalid lambda expression", lambdaNode, null);
             }

             this.interpreter = interpreter;
             this.valueNode = lambdaNode.getChildAt(1);
          }
       }

       /**
        * Implements an interpreted {@link P2JQuery.Parameter} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class P2JQueryParameter
       extends Lambda
       implements P2JQuery.Parameter
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public P2JQueryParameter(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }

          /**
           * Evaluate the lambda expression.
           * <p>
           * Use the {@code RuntimeJastInterpreter} set in constructor to evaluate the node. That
           * result is the value of the lambda expression.
           *
           * @return  The value of the {@code (P2JQuery.Parameter) ()} lambda expression.
           */
          @Override
          public Object resolve()
          {
             try
             {
                return interpreter.evalExpression(valueNode);
             }
             catch (InterpreterException ie)
             {
                String err = "Incompatible data types in expression or assignment.";
                if (LOG.isLoggable(Level.FINE))
                {
                   LOG.log(Level.FINE, err, ie);
                }
                else if (LOG.isLoggable(Level.WARNING))
                {
                   String msg = err + " Use FINE level logging for a stack trace";
                   LOG.log(Level.WARNING, msg);
                }
                ErrorManager.recordOrThrowError(223, err);
                return new unknown();
             }
          }
       }

       /**
        * Implements an interpreted {@link P2JQuery.Parameter} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class P2JQueryParamResolver
       extends Lambda
       implements P2JQuery.ParamResolver
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public P2JQueryParamResolver(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }

          /**
           * Evaluate the lambda expression.
           * <p>
           * Use the {@code RuntimeJastInterpreter} set in constructor to evaluate the node. That
           * result is the value of the lambda expression.
           *
           * @return  The value of the {@code (P2JQuery.Parameter) ()} lambda expression.
           */
          @Override
          public BaseDataType resolve()
          {
             try
             {
                return (BaseDataType)interpreter.evalExpression(valueNode);
             }
             catch (InterpreterException ie)
             {
                String err = "Incompatible data types in expression or assignment.";
                if (LOG.isLoggable(Level.FINE))
                {
                   LOG.log(Level.FINE, err, ie);
                }
                else if (LOG.isLoggable(Level.WARNING))
                {
                   String msg = err + " Use FINE level logging for a stack trace";
                   LOG.log(Level.WARNING, msg);
                }
                ErrorManager.recordOrThrowError(223, err);
                return new unknown();
             }
          }
       }

       /**
        * Implements an interpreted {@code Supplier<logical>} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class ClientWhere
       extends Lambda
       implements Supplier<logical>
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public ClientWhere(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }

          /**
           * Evaluate the lambda expression.
           *
           * @return  The value of the {@code (Supplier<logical>) ()} lambda expression.
           */
          @Override
          public logical get()
          {
             try
             {
                return (logical) interpreter.evalExpression(valueNode);
             }
             catch (InterpreterException ie)
             {
                String err = "Incompatible data types in expression or assignment.";
                ErrorManager.recordOrThrowError(223, err);
                return new logical();
             }
          }
       }

       /**
        * Implements an interpreted {@link LogicalOp} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class LogicalLambda
       extends Lambda
       implements LogicalOp
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public LogicalLambda(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }

          /**
           * Evaluate the lambda expression.
           *
           * @return  The value of the {@code (LogicalOp) ()} lambda expression.
           */
          @Override
          public logical evaluate()
          {
             try
             {
                return (logical) interpreter.evalExpression(valueNode);
             }
             catch (InterpreterException ie)
             {
                String err = "Incompatible data types in expression or assignment.";
                ErrorManager.recordOrThrowError(223, err);
                return new logical();
             }
          }
       }

       /**
        * Implements an interpreted {@link Resolvable} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       abstract static class ResolvableAdapter
       extends Lambda
       implements Resolvable
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public ResolvableAdapter(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }

          /**
           * Evaluate the lambda expression.
           * <p>
           * Use the {@code RuntimeJastInterpreter} set in constructor to evaluate the node. That
           * result is the value of the lambda expression.
           *
           * @return  The value of the lambda expression.
           */
          @Override
          public BaseDataType resolve()
          {
             try
             {
                return (BaseDataType) interpreter.evalExpression(valueNode);
             }
             catch (InterpreterException ie)
             {
                String err = "Incompatible data types in expression or assignment.";
                ErrorManager.recordOrThrowError(223, err);
                return new unknown();
             }
          }
       }

       /**
        * Implements an interpreted {@link CharacterExpr} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class CharacterExprAdapter
       extends ResolvableAdapter
       implements CharacterExpr
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public CharacterExprAdapter(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }
       }

       /**
        * Implements an interpreted {@link DateExpr} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class DateExprAdapter
       extends ResolvableAdapter
       implements DateExpr
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public DateExprAdapter(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }
       }

       /**
        * Implements an interpreted {@link DatetimeExpr} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class DatetimeExprAdapter
       extends ResolvableAdapter
       implements DatetimeExpr
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public DatetimeExprAdapter(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }
       }

       /**
        * Implements an interpreted {@link DatetimeTzExpr} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class DatetimeTzExprAdapter
       extends ResolvableAdapter
       implements DatetimeTzExpr
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public DatetimeTzExprAdapter(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }
       }

       /**
        * Implements an interpreted {@link DecimalExpr} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class DecimalExprAdapter
       extends ResolvableAdapter
       implements DecimalExpr
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public DecimalExprAdapter(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }
       }

       /**
        * Implements an interpreted {@link Int64Expr} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class Int64ExprAdapter
       extends ResolvableAdapter
       implements Int64Expr
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public Int64ExprAdapter(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }
       }

       /**
        * Implements an interpreted {@link IntegerExpr} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class IntegerExprAdapter
       extends ResolvableAdapter
       implements IntegerExpr
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public IntegerExprAdapter(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }
       }

       /**
        * Implements an interpreted {@link LogicalExpr} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class LogicalExprAdapter
       extends ResolvableAdapter
       implements LogicalExpr
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public LogicalExprAdapter(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }
       }

       /**
        * Implements an interpreted {@link RawExpr} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class RawExprAdapter
       extends ResolvableAdapter
       implements RawExpr
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public RawExprAdapter(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }
       }

       /**
        * Implements an interpreted {@link RecidExpr} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class RecidExprAdapter
       extends ResolvableAdapter
       implements RecidExpr
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public RecidExprAdapter(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }
       }

       /**
        * Implements an interpreted {@link RowidExpr} lambda expression stored as a JAST node,
        * using the {@code RuntimeJastInterpreter}.
        */
       static class RowidExprAdapter
       extends ResolvableAdapter
       implements RowidExpr
       {
          /**
           * Constructor.
           *
           * @param   interpreter
           *          The {@code RuntimeJastInterpreter} that will handle interpretation of this
           *          lambda expression. Must not be {@code null}.
           * @param   lambdaNode
           *          A JAST node with {@link com.goldencode.p2j.uast.JavaTokenTypes#LAMBDA} type and
           *          no arguments (they will be ignored, anyway).
           */
          public RowidExprAdapter(RuntimeJastInterpreter interpreter, Aast lambdaNode)
          {
             super(interpreter, lambdaNode);
          }
       }
    }