/*
 * Copyright 2018 The GraphicsFuzz Project Authors
 *
 * Licensed 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
 *
 *     https://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 com.graphicsfuzz.generator.fuzzer.templates;

import com.graphicsfuzz.common.ast.expr.Expr;
import com.graphicsfuzz.common.ast.type.Type;
import com.graphicsfuzz.common.util.IRandom;
import java.util.List;

public interface IExprTemplate {

  /**
   * Instantiates the template with the given arguments to produce an expression.
   * @param generator Used when randomization is required to determine the result.
   * @param args The expressions used to instantiate the template.
   * @return An expression over the arguments, determinied by the kind of template this is.
   */
  Expr generateExpr(IRandom generator, Expr... args);

  /**
   * Helper to allow templates to be instantiated using lists rather than arrays/variable numbers
   * of arguments.
   */
  default Expr generateExpr(IRandom generator, List<Expr> args) {
    Expr[] temp = new Expr[args.size()];
    return generateExpr(generator, args.toArray(temp));
  }

  /**
   * Yields an unqualified type guaranteed to match the unqualified version of the result type of
   * an expression generated by the template.
   * @return The (unqualified) result type of the template.
   */
  Type getResultType();

  /**
   * Returns a list of k lists, indicating that the template requires k expressions in order to be
   * evaluated, and that the type of the ith expression used to evaluate the template must be one
   * of the types in the ith list.  Each list returned must thus contain at least one type.
   *
   * <p>Most templates will return a list of singleton lists.  However, the comma operator template
   * can work for any pair of argument types</p>

   * @return The acceptable argument types with which the template can be instantiated.
   */
  List<List<Type>> getArgumentTypes();

  /**
   * Indicates whether a particular argument of the template needs to be an l-value.
   * @param index A template argument index.
   * @return true if and only if the argument provided for this index is required to be an l-value.
   */
  boolean requiresLValueForArgument(int index);

  /**
   * Indicates whether the template produces an l-value.
   * @return true if and only if the expression generated by the template is guaranteed to be an
   *         l-value.
   */
  boolean isLValue();

  /**
   * Indicates whether the template produces a compile-time constant expression.
   * @return true if and only if the expression generated by the template is guaranteed to be
   *         compile-time constant.
   */
  boolean isConst();

  int getNumArguments();

}
