/*
 * Licensed to the Apache Software Foundation (ASF) under one or more contributor license
 * agreements. See the NOTICE file distributed with this work for additional information regarding
 * copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the License. You may obtain a
 * copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License
 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing permissions and limitations under
 * the License.
 */
package org.apache.geode.cache.query.internal;

import java.io.StringReader;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import org.apache.logging.log4j.Logger;

import org.apache.geode.cache.query.FunctionDomainException;
import org.apache.geode.cache.query.NameResolutionException;
import org.apache.geode.cache.query.QueryInvalidException;
import org.apache.geode.cache.query.QueryInvocationTargetException;
import org.apache.geode.cache.query.TypeMismatchException;
import org.apache.geode.cache.query.internal.parse.GemFireAST;
import org.apache.geode.cache.query.internal.parse.OQLLexer;
import org.apache.geode.cache.query.internal.parse.OQLLexerTokenTypes;
import org.apache.geode.cache.query.internal.parse.OQLParser;
import org.apache.geode.cache.query.internal.types.CollectionTypeImpl;
import org.apache.geode.cache.query.internal.types.MapTypeImpl;
import org.apache.geode.cache.query.internal.types.ObjectTypeImpl;
import org.apache.geode.cache.query.internal.types.TypeUtils;
import org.apache.geode.cache.query.types.CollectionType;
import org.apache.geode.cache.query.types.MapType;
import org.apache.geode.cache.query.types.ObjectType;
import org.apache.geode.internal.Assert;
import org.apache.geode.internal.InternalDataSerializer;
import org.apache.geode.logging.internal.log4j.api.LogService;

/**
 * Class Description
 *
 * @version $Revision: 1.1 $s
 */
public class QCompiler implements OQLLexerTokenTypes {
  private static final Logger logger = LogService.getLogger();

  private Stack stack = new Stack();
  private Map imports = new HashMap();
  private final boolean isForIndexCompilation;
  private boolean traceOn;

  public QCompiler() {
    this.isForIndexCompilation = false;
  }

  public QCompiler(boolean isForIndexCompilation) {
    this.isForIndexCompilation = isForIndexCompilation;
  }

  /*
   * compile the string into a Query (returns the root CompiledValue)
   */
  public CompiledValue compileQuery(String oqlSource) {
    try {
      OQLLexer lexer = new OQLLexer(new StringReader(oqlSource));
      OQLParser parser = new OQLParser(lexer);
      // by default use Unsupported AST class, overridden for supported
      // operators in the grammer proper
      parser.setASTNodeClass("org.apache.geode.cache.query.internal.parse.ASTUnsupported");
      parser.queryProgram();
      GemFireAST n = (GemFireAST) parser.getAST();
      n.compile(this);
    } catch (Exception ex) { // This is to make sure that we are wrapping any antlr exception with
                             // GemFire Exception.
      throw new QueryInvalidException(
          String.format("Syntax error in query: %s", ex.getMessage()),
          ex);
    }
    Assert.assertTrue(stackSize() == 1, "stack size = " + stackSize());
    return (CompiledValue) pop();
  }

  /** Returns List<CompiledIteratorDef> */
  public List compileFromClause(String fromClause) {
    try {
      OQLLexer lexer = new OQLLexer(new StringReader(fromClause));
      OQLParser parser = new OQLParser(lexer);
      // by default use Unsupported AST class, overridden for supported
      // operators in the grammer proper
      parser.setASTNodeClass("org.apache.geode.cache.query.internal.parse.ASTUnsupported");
      parser.loneFromClause();
      GemFireAST n = (GemFireAST) parser.getAST();
      n.compile(this);
    } catch (Exception ex) { // This is to make sure that we are wrapping any antlr exception with
                             // GemFire Exception.
      throw new QueryInvalidException(
          String.format("Syntax error in query: %s", ex.getMessage()),
          ex);
    }
    Assert.assertTrue(stackSize() == 1, "stack size = " + stackSize());
    return (List) pop();
  }


  /** Returns List<CompiledIteratorDef> or null if projectionAttrs is '*' */
  public List compileProjectionAttributes(String projectionAttributes) {
    try {
      OQLLexer lexer = new OQLLexer(new StringReader(projectionAttributes));
      OQLParser parser = new OQLParser(lexer);
      // by default use Unsupported AST class, overridden for supported
      // operators in the grammer proper
      parser.setASTNodeClass("org.apache.geode.cache.query.internal.parse.ASTUnsupported");
      parser.loneProjectionAttributes();
      GemFireAST n = (GemFireAST) parser.getAST();
      // don't compile TOK_STAR
      if (n.getType() == TOK_STAR) {
        return null;
      }
      n.compile(this);
    } catch (Exception ex) { // This is to make sure that we are wrapping any antlr exception with
                             // GemFire Exception.
      throw new QueryInvalidException(
          String.format("Syntax error in query: %s", ex.getMessage()),
          ex);
    }
    Assert.assertTrue(stackSize() == 1, "stack size = " + stackSize() + ";stack=" + this.stack);
    return (List) pop();
  }

  /**
   * Yogesh: compiles order by clause and push into the stack
   *
   */
  public void compileOrederByClause(int numOfChildren) {
    List list = new ArrayList();
    for (int i = 0; i < numOfChildren; i++) {
      CompiledSortCriterion csc = (CompiledSortCriterion) this.stack.pop();
      list.add(0, csc);
    }
    push(list);
  }

  public void compileGroupByClause(int numOfChildren) {
    List list = new ArrayList();
    for (int i = 0; i < numOfChildren; i++) {
      Object csc = this.stack.pop();
      list.add(0, csc);
    }
    push(list);
  }

  /**
   * Yogesh: compiles sort criteria present in order by clause and push into the stack
   *
   */
  public void compileSortCriteria(String sortCriterion) {

    CompiledValue obj = (CompiledValue) this.stack.pop();
    boolean criterion = false;
    if (sortCriterion.equals("desc"))
      criterion = true;
    CompiledSortCriterion csc = new CompiledSortCriterion(criterion, obj);
    push(csc);

  }

  public void compileLimit(String limitNum) {
    push(Integer.valueOf(limitNum));
  }

  /**
   * Processes import statements only. This compiler instance remembers the imports and can be used
   * to compile other strings with this context info
   */
  public void compileImports(String imports) {
    try {
      OQLLexer lexer = new OQLLexer(new StringReader(imports));
      OQLParser parser = new OQLParser(lexer);
      // by default use Unsupported AST class, overridden for supported
      // operators in the grammer proper
      parser.setASTNodeClass("org.apache.geode.cache.query.internal.parse.ASTUnsupported");
      parser.loneImports();
      GemFireAST n = (GemFireAST) parser.getAST();
      n.compile(this);
    } catch (Exception ex) { // This is to make sure that we are wrapping any antlr exception with
                             // GemFire Exception.
      throw new QueryInvalidException(
          String.format("Syntax error in query: %s", ex.getMessage()),
          ex);
    }
    Assert.assertTrue(stackSize() == 0, "stack size = " + stackSize() + ";stack=" + this.stack);
  }

  private void checkWhereClauseForAggregates(CompiledValue compiledValue) {
    if (compiledValue instanceof CompiledAggregateFunction) {
      throw new QueryInvalidException(
          "Aggregate functions can not be used as part of the WHERE clause.");
    }

    // Inner queries are supported.
    if (compiledValue instanceof CompiledSelect) {
      return;
    }

    for (Object compiledChildren : compiledValue.getChildren()) {
      checkWhereClauseForAggregates((CompiledValue) compiledChildren);
    }
  }

  public void select(Map<Integer, Object> queryComponents) {

    CompiledValue limit = null;
    Object limitObject = queryComponents.remove(OQLLexerTokenTypes.LIMIT);
    if (limitObject instanceof Integer) {
      limit = new CompiledLiteral(limitObject);
    } else {
      limit = (CompiledBindArgument) limitObject;
    }
    List<CompiledSortCriterion> orderByAttrs =
        (List<CompiledSortCriterion>) queryComponents.remove(OQLLexerTokenTypes.LITERAL_order);

    List iterators = (List) queryComponents.remove(OQLLexerTokenTypes.LITERAL_from);
    List projAttrs = (List) queryComponents.remove(OQLLexerTokenTypes.PROJECTION_ATTRS);
    if (projAttrs == null) {
      // remove any * or all attribute
      queryComponents.remove(OQLLexerTokenTypes.TOK_STAR);
      queryComponents.remove(OQLLexerTokenTypes.LITERAL_all);
    }
    // "COUNT" or null
    /*
     * String aggrExpr = (String) queryComponents .remove(OQLLexerTokenTypes.LITERAL_count);
     */

    // "DISTINCT" or null
    String distinct = (String) queryComponents.remove(OQLLexerTokenTypes.LITERAL_distinct);
    List<String> hints = null;
    Object hintObject = queryComponents.remove(OQLLexerTokenTypes.LITERAL_hint);
    if (hintObject != null) {
      hints = (List<String>) hintObject;
    }

    List<CompiledValue> groupByClause =
        (List<CompiledValue>) queryComponents.remove(OQLLexerTokenTypes.LITERAL_group);

    // whatever remains , treat it as where
    // whereClause
    CompiledValue where = null;

    if (queryComponents.size() == 1) {
      where = (CompiledValue) queryComponents.values().iterator().next();
      // Where clause can not contain aggregate functions.
      checkWhereClauseForAggregates(where);
    } else if (queryComponents.size() > 1) {
      throw new QueryInvalidException("Unexpected/unsupported query clauses found");
    }
    LinkedHashMap<Integer, CompiledAggregateFunction> aggMap =
        identifyAggregateExpressions(projAttrs);
    boolean isCountOnly = checkForCountOnly(aggMap, projAttrs, groupByClause);
    if (isCountOnly) {
      projAttrs = null;
    }
    CompiledSelect select = createSelect(distinct != null, isCountOnly, where, iterators, projAttrs,
        orderByAttrs, limit, hints, groupByClause, aggMap);
    push(select);
  }

  private boolean checkForCountOnly(Map<Integer, CompiledAggregateFunction> aggregateMap,
      List projAttribs, List<CompiledValue> groupBy) {
    if (aggregateMap != null && aggregateMap.size() == 1 && projAttribs.size() == 1
        && groupBy == null) {
      for (Map.Entry<Integer, CompiledAggregateFunction> entry : aggregateMap.entrySet()) {
        CompiledAggregateFunction caf = entry.getValue();
        if (caf.getFunctionType() == OQLLexerTokenTypes.COUNT && caf.getParameter() == null) {
          return true;
        }
      }
    }
    return false;
  }

  private CompiledSelect createSelect(boolean isDistinct, boolean isCountOnly, CompiledValue where,
      List iterators, List projAttrs, List<CompiledSortCriterion> orderByAttrs, CompiledValue limit,
      List<String> hints, List<CompiledValue> groupByClause,
      LinkedHashMap<Integer, CompiledAggregateFunction> aggMap) {
    if (isCountOnly || (groupByClause == null && aggMap == null)
        || (aggMap == null && orderByAttrs == null)) {
      return new CompiledSelect(isDistinct, isCountOnly, where, iterators, projAttrs, orderByAttrs,
          limit, hints, groupByClause);
    } else {
      return new CompiledGroupBySelect(isDistinct, isCountOnly, where, iterators, projAttrs,
          orderByAttrs, limit, hints, groupByClause, aggMap);
    }
  }

  private LinkedHashMap<Integer, CompiledAggregateFunction> identifyAggregateExpressions(
      List projAttribs) {
    if (projAttribs != null) {
      LinkedHashMap<Integer, CompiledAggregateFunction> mapping =
          new LinkedHashMap<Integer, CompiledAggregateFunction>();
      int index = 0;
      for (Object o : projAttribs) {
        CompiledValue proj = (CompiledValue) ((Object[]) o)[1];
        if (proj.getType() == OQLLexerTokenTypes.AGG_FUNC) {
          mapping.put(index, (CompiledAggregateFunction) proj);
        }
        ++index;
      }
      return mapping.size() == 0 ? null : mapping;
    } else {
      return null;
    }

  }

  public void projection() {
    // find an id or null on the stack, then an expr CompiledValue
    // push an Object[2] on the stack. First element is id, second is CompiledValue
    CompiledID id = (CompiledID) pop();
    CompiledValue expr = (CompiledValue) pop();
    push(new Object[] {id == null ? null : id.getId(), expr});
  }

  public void aggregateFunction(CompiledValue expr, int aggFuncType, boolean distinctOnly) {
    push(new CompiledAggregateFunction(expr, aggFuncType, distinctOnly));
  }

  public void iteratorDef() {
    // find type id and colln on the stack

    ObjectType type = assembleType(); // can be null
    CompiledID id = (CompiledID) TypeUtils.checkCast(pop(), CompiledID.class); // can be null
    CompiledValue colln = (CompiledValue) TypeUtils.checkCast(pop(), CompiledValue.class);

    if (type == null) {
      type = TypeUtils.OBJECT_TYPE;
    }

    push(new CompiledIteratorDef(id == null ? null : id.getId(), type, colln));
  }


  public void undefinedExpr(boolean is_defined) {
    CompiledValue value = (CompiledValue) pop();
    push(new CompiledUndefined(value, is_defined));
  }

  public void function(int function, int numOfChildren) {
    CompiledValue[] cvArr = new CompiledValue[numOfChildren];
    for (int i = numOfChildren - 1; i >= 0; i--) {
      cvArr[i] = (CompiledValue) pop();
    }
    push(new CompiledFunction(cvArr, function));
  }

  public void inExpr() {
    CompiledValue collnExpr = (CompiledValue) TypeUtils.checkCast(pop(), CompiledValue.class);
    CompiledValue elm = (CompiledValue) TypeUtils.checkCast(pop(), CompiledValue.class);
    push(new CompiledIn(elm, collnExpr));
  }

  public void constructObject(Class clazz) {
    // find argList on stack
    // only support SET for now
    Assert.assertTrue(clazz == ResultsSet.class);
    List argList = (List) TypeUtils.checkCast(pop(), List.class);
    push(new CompiledConstruction(clazz, argList));
  }

  public void pushId(String id) {
    push(new CompiledID(id));
  }

  public void pushRegion(String regionPath) {
    push(new CompiledRegion(regionPath));
  }

  public void appendPathComponent(String id) {
    CompiledValue rcvr = (CompiledValue) pop();
    push(new CompiledPath(rcvr, id));
  }


  public void pushBindArgument(int i) {
    push(new CompiledBindArgument(i));
  }


  public void pushLiteral(Object obj) {
    push(new CompiledLiteral(obj));
  }

  public void pushNull() // used as a placeholder for a missing clause
  {
    push(null);
  }


  public void combine(int num) {
    List list = new ArrayList();
    for (int i = 0; i < num; i++) {
      list.add(0, pop());
    }
    push(list);
  }


  public void methodInvocation() {
    // find on stack:
    // argList, methodName, receiver (which may be null if receiver is implicit)
    List argList = (List) TypeUtils.checkCast(pop(), List.class);
    CompiledID methodName = (CompiledID) TypeUtils.checkCast(pop(), CompiledID.class);
    CompiledValue rcvr = (CompiledValue) TypeUtils.checkCast(pop(), CompiledValue.class);
    push(new CompiledOperation(rcvr, methodName.getId(), argList));
  }

  public void indexOp() {
    // find the List of index expressions and the receiver on the stack
    Object indexParams = pop();
    final CompiledValue rcvr = (CompiledValue) TypeUtils.checkCast(pop(), CompiledValue.class);
    CompiledValue indexExpr = CompiledValue.MAP_INDEX_ALL_KEYS;

    if (indexParams != null) {
      final List indexList = (List) TypeUtils.checkCast(indexParams, List.class);
      if (!isForIndexCompilation && indexList.size() != 1) {
        throw new UnsupportedOperationException(
            "Only one index expression supported");
      }
      if (indexList.size() == 1) {
        indexExpr = (CompiledValue) TypeUtils.checkCast(indexList.get(0), CompiledValue.class);

        if (indexExpr.getType() == TOK_COLON) {
          throw new UnsupportedOperationException(
              "Ranges not supported in index operators");
        }
        indexExpr = (CompiledValue) TypeUtils.checkCast(indexList.get(0), CompiledValue.class);
        push(new CompiledIndexOperation(rcvr, indexExpr));
      } else {
        assert this.isForIndexCompilation;

        MapIndexable mi = new MapIndexOperation(rcvr, indexList);
        push(mi);
      }
    } else {
      if (!this.isForIndexCompilation) {
        throw new QueryInvalidException(String.format("Syntax error in query: %s",
            "* use incorrect"));
      }
      push(new CompiledIndexOperation(rcvr, indexExpr));
    }

  }



  /**
   * Creates appropriate CompiledValue for the like predicate based on the sargability of the String
   * or otherwise. It also works on the last character to see if the sargable like predicate results
   * in a CompiledJunction or a Comparison. Currently we are supporting only the '%' terminated
   * "like" predicate.
   *
   * @param var The CompiledValue representing the variable
   * @param patternOrBindParam The CompiledLiteral reprsenting the pattern of the like predicate
   * @return CompiledValue representing the "like" predicate
   *
   */
  CompiledValue createCompiledValueForLikePredicate(CompiledValue var,
      CompiledValue patternOrBindParam) {
    if (!(patternOrBindParam.getType() == CompiledBindArgument.QUERY_PARAM)) {
      CompiledLiteral pattern = (CompiledLiteral) patternOrBindParam;
      if (pattern._obj == null) {
        throw new UnsupportedOperationException(
            "Null values are not supported with LIKE predicate.");
      }
    }
    // From 6.6 Like is enhanced to support special character (% and _) at any
    // position of the string.
    return new CompiledLike(var, patternOrBindParam);
  }


  public void like() {
    CompiledValue v2 = (CompiledValue) pop();
    CompiledValue v1 = (CompiledValue) pop();
    CompiledValue cv = createCompiledValueForLikePredicate(v1, v2);
    push(cv);
  }

  public void compare(int opKind) {
    CompiledValue v2 = (CompiledValue) pop();
    CompiledValue v1 = (CompiledValue) pop();
    push(new CompiledComparison(v1, v2, opKind));
  }

  public void mod(int opKind) {
    CompiledValue v2 = (CompiledValue) pop();
    CompiledValue v1 = (CompiledValue) pop();
    push(new CompiledMod(v1, v2, opKind));
  }

  public void arithmetic(int opKind) {
    switch (opKind) {
      case TOK_PLUS:
        addition(opKind);
        break;
      case TOK_MINUS:
        subtraction(opKind);
        break;
      case TOK_SLASH:
        division(opKind);
        break;
      case TOK_STAR:
        multiplication(opKind);
        break;
      case LITERAL_mod:
        mod(opKind);
        break;
      case TOK_PERCENTAGE:
        mod(opKind);
        break;
    }
  }

  private void addition(int opKind) {
    CompiledValue v2 = (CompiledValue) pop();
    CompiledValue v1 = (CompiledValue) pop();
    push(new CompiledAddition(v1, v2, opKind));
  }

  private void subtraction(int opKind) {
    CompiledValue v2 = (CompiledValue) pop();
    CompiledValue v1 = (CompiledValue) pop();
    push(new CompiledSubtraction(v1, v2, opKind));
  }

  private void division(int opKind) {
    CompiledValue v2 = (CompiledValue) pop();
    CompiledValue v1 = (CompiledValue) pop();
    push(new CompiledDivision(v1, v2, opKind));
  }

  private void multiplication(int opKind) {
    CompiledValue v2 = (CompiledValue) pop();
    CompiledValue v1 = (CompiledValue) pop();
    push(new CompiledMultiplication(v1, v2, opKind));
  }


  public void or(int numTerms) {
    junction(numTerms, LITERAL_or);
  }

  public void and(int numTerms) {
    junction(numTerms, LITERAL_and);
  }

  private void junction(int numTerms, int operator) {
    /*
     * if any of the operands are junctions with same operator as this one then flatten
     */
    List operands = new ArrayList(numTerms);
    for (int i = 0; i < numTerms; i++) {
      CompiledValue operand = (CompiledValue) pop();
      // flatten if we can
      if (operand instanceof CompiledJunction
          && ((CompiledJunction) operand).getOperator() == operator) {
        CompiledJunction junction = (CompiledJunction) operand;
        List jOperands = junction.getOperands();
        for (int j = 0; j < jOperands.size(); j++)
          operands.add(jOperands.get(j));
      } else
        operands.add(operand);
    }

    push(new CompiledJunction(
        (CompiledValue[]) operands.toArray(new CompiledValue[0]), operator));
  }



  public void not() {
    Object obj = this.stack.peek();
    Assert.assertTrue(obj instanceof CompiledValue);

    if (obj instanceof Negatable)
      ((Negatable) obj).negate();
    else
      push(new CompiledNegation((CompiledValue) pop()));
  }

  public void unaryMinus() {
    Object obj = this.stack.peek();
    Assert.assertTrue(obj instanceof CompiledValue);
    push(new CompiledUnaryMinus((CompiledValue) pop()));

  }

  public void typecast() {
    // pop expr and type, apply type, then push result
    AbstractCompiledValue cmpVal =
        (AbstractCompiledValue) TypeUtils.checkCast(pop(), AbstractCompiledValue.class);
    ObjectType objType = assembleType();
    cmpVal.setTypecast(objType);
    push(cmpVal);
  }


  // returns null if null is on the stack
  public ObjectType assembleType() {
    ObjectType objType = (ObjectType) TypeUtils.checkCast(pop(), ObjectType.class);
    if (objType instanceof CollectionType) {
      // pop the elementType
      ObjectType elementType = assembleType();

      if (objType instanceof MapType) {
        // pop the key type
        ObjectType keyType = assembleType();
        return new MapTypeImpl(objType.resolveClass(), keyType, elementType);
      }
      return new CollectionTypeImpl(objType.resolveClass(), elementType);
    }
    return objType;
  }

  public void traceRequest() {
    this.traceOn = true;
  }

  public boolean isTraceRequested() {
    return traceOn;
  }

  public void setHint(int numOfChildren) {
    ArrayList list = new ArrayList();
    for (int i = 0; i < numOfChildren; i++) {
      String hi = (String) this.stack.pop();
      list.add(0, hi);
    }
    push(list);
    // setHints(list);
  }

  public void setHintIdentifier(String text) {
    push(text);
  }

  public void importName(String qualifiedName, String asName) {
    if (asName == null) {
      // if no AS, then use the short name from qualifiedName
      // as the AS
      int idx = qualifiedName.lastIndexOf('.');
      if (idx >= 0) {
        asName = qualifiedName.substring(idx + 1);
      } else {
        asName = qualifiedName;
      }
    }
    if (logger.isTraceEnabled()) {
      logger.trace("QCompiler.importName: {},{}", asName, qualifiedName);
    }
    this.imports.put(asName, qualifiedName);
  }


  public Object pop() {
    Object obj = this.stack.pop();
    if (logger.isTraceEnabled()) {
      logger.trace("QCompiler.pop: {}", obj);
    }
    return obj;
  }

  public void push(Object obj) {
    if (logger.isTraceEnabled()) {
      logger.trace("QCompiler.push: {}", obj);
    }
    this.stack.push(obj);
  }

  public int stackSize() {
    return this.stack.size();
  }

  public ObjectType resolveType(String typeName) {
    if (typeName == null) {
      if (logger.isTraceEnabled()) {
        logger.trace("QCompiler.resolveType= {}", Object.class.getName());
      }
      return TypeUtils.OBJECT_TYPE;
    }
    // resolve with imports
    String as = null;
    if (this.imports != null) {
      as = (String) this.imports.get(typeName);
    }
    if (as != null)
      typeName = as;

    Class resultClass;
    try {
      resultClass = InternalDataSerializer.getCachedClass(typeName);
    } catch (ClassNotFoundException e) {
      throw new QueryInvalidException(
          String.format("Type not found: %s", typeName), e);
    }
    if (logger.isTraceEnabled()) {
      logger.trace("QCompiler.resolveType= {}", resultClass.getName());
    }
    return new ObjectTypeImpl(resultClass);
  }

  private static class MapIndexOperation extends AbstractCompiledValue implements MapIndexable {
    private final CompiledValue rcvr;
    private final List<CompiledValue> indexList;

    public MapIndexOperation(CompiledValue rcvr, List<CompiledValue> indexList) {
      this.rcvr = rcvr;
      this.indexList = indexList;
    }

    @Override
    public CompiledValue getReceiverSansIndexArgs() {
      return rcvr;
    }

    @Override
    public CompiledValue getMapLookupKey() {
      throw new UnsupportedOperationException("Function invocation not expected");
    }

    @Override
    public List<CompiledValue> getIndexingKeys() {
      return (List<CompiledValue>) indexList;
    }

    @Override
    public Object evaluate(ExecutionContext context) throws FunctionDomainException,
        TypeMismatchException, NameResolutionException, QueryInvocationTargetException {
      throw new UnsupportedOperationException("Method execution not expected");
    }

    @Override
    public int getType() {
      throw new UnsupportedOperationException("Method execution not expected");
    }
  }

}
