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);
      }
   }
}