Exemplo n.º 1
0
 public void visit(FuncallExpression node) {
   if (node.getObject() != null) {
     visit(node.getObject());
   }
   visit(node.getFunction());
   visitAll(node.getArguments());
 }
Exemplo n.º 2
0
  /**
   * The outer calling convention to a BaseFunction.
   *
   * @param args a list of all positional arguments (as in *starArg)
   * @param kwargs a map for key arguments (as in **kwArgs)
   * @param ast the expression for this function's definition
   * @param env the Environment in the function is called
   * @return the value resulting from evaluating the function with the given arguments
   * @throws EvalException-s containing source information.
   */
  public Object call(
      List<Object> args,
      @Nullable Map<String, Object> kwargs,
      @Nullable FuncallExpression ast,
      Environment env)
      throws EvalException, InterruptedException {
    Preconditions.checkState(isConfigured(), "Function %s was not configured", getName());

    // ast is null when called from Java (as there's no Skylark call site).
    Location loc = ast == null ? Location.BUILTIN : ast.getLocation();

    Object[] arguments = processArguments(args, kwargs, loc);
    canonicalizeArguments(arguments, loc);

    return call(arguments, ast, env);
  }
Exemplo n.º 3
0
  @Override
  @Nullable
  public Object call(Object[] args, @Nullable FuncallExpression ast, @Nullable Environment env)
      throws EvalException, InterruptedException {
    final Location loc = (ast == null) ? location : ast.getLocation();

    // Add extra arguments, if needed
    if (extraArgs != null) {
      int i = args.length - extraArgs.length;
      for (BuiltinFunction.ExtraArgKind extraArg : extraArgs) {
        switch (extraArg) {
          case LOCATION:
            args[i] = loc;
            break;

          case SYNTAX_TREE:
            args[i] = ast;
            break;

          case ENVIRONMENT:
            args[i] = env;
            break;
        }
        i++;
      }
    }

    // Last but not least, actually make an inner call to the function with the resolved arguments.
    try {
      return invokeMethod.invoke(this, args);
    } catch (InvocationTargetException x) {
      Throwable e = x.getCause();
      if (e instanceof EvalException) {
        throw ((EvalException) e).ensureLocation(loc);
      } else if (e instanceof InterruptedException) {
        throw (InterruptedException) e;
      } else if (e instanceof ClassCastException
          || e instanceof ExecutionException
          || e instanceof IllegalStateException) {
        throw new EvalException(loc, "in call to " + getName(), e);
      } else if (e instanceof IllegalArgumentException) {
        throw new EvalException(loc, "Illegal argument in call to " + getName(), e);
      } else {
        throw badCallException(loc, e, args);
      }
    } catch (IllegalArgumentException e) {
      // Either this was thrown by Java itself, or it's a bug
      // To cover the first case, let's manually check the arguments.
      final int len = args.length - ((extraArgs == null) ? 0 : extraArgs.length);
      final Class<?>[] types = invokeMethod.getParameterTypes();
      for (int i = 0; i < args.length; i++) {
        if (args[i] != null && !types[i].isAssignableFrom(args[i].getClass())) {
          String paramName =
              i < len ? signature.getSignature().getNames().get(i) : extraArgs[i - len].name();
          int extraArgsCount = (extraArgs == null) ? 0 : extraArgs.length;
          throw new EvalException(
              loc,
              String.format(
                  "Method %s is not applicable for arguments %s: '%s' is %s, but should be %s",
                  getShortSignature(true),
                  printTypeString(args, args.length - extraArgsCount),
                  paramName,
                  EvalUtils.getDataTypeName(args[i]),
                  EvalUtils.getDataTypeNameFromClass(types[i])));
        }
      }
      throw badCallException(loc, e, args);
    } catch (IllegalAccessException e) {
      throw badCallException(loc, e, args);
    }
  }
Exemplo n.º 4
0
  @Override
  public Object call(
      List<Object> args, Map<String, Object> kwargs, FuncallExpression ast, Environment env)
      throws EvalException, InterruptedException {

    // ast is null when called from Java (as there's no Skylark call site).
    Location loc = ast == null ? location : ast.getLocation();
    if (onlyNamedArguments && !args.isEmpty()) {
      throw new EvalException(loc, getSignature() + " does not accept positional arguments");
    }

    if (kwargs == null) {
      kwargs = ImmutableMap.<String, Object>of();
    }

    int numParams = parameters.size();
    int numArgs = args.size();
    Object[] namedArguments = new Object[numParams];

    // first, positional arguments:
    if (numArgs > numParams) {
      throw new EvalException(loc, "too many positional arguments in call to " + getSignature());
    }
    for (int ii = 0; ii < numArgs; ++ii) {
      namedArguments[ii] = args.get(ii);
    }

    // TODO(bazel-team): here, support *varargs splicing

    // second, keyword arguments:
    for (Map.Entry<String, Object> entry : kwargs.entrySet()) {
      String keyword = entry.getKey();
      int pos = parameters.indexOf(keyword);
      if (pos == -1) {
        List<String> unexpected = listDifference(new ArrayList<>(kwargs.keySet()), parameters);
        Collections.sort(unexpected); // issue stable error messages.
        throw new EvalException(
            loc,
            "unexpected keyword"
                + (unexpected.size() > 1 ? "s" : "")
                + " '"
                + Joiner.on("', '").join(unexpected)
                + "' in call to "
                + getSignature());
      } else {
        if (namedArguments[pos] != null) {
          throw new EvalException(
              loc, getSignature() + " got multiple values for keyword argument '" + keyword + "'");
        }
        namedArguments[pos] = kwargs.get(keyword);
      }
    }

    // third, check mandatory parameters:
    for (int ii = 0; ii < numMandatoryParameters; ++ii) {
      if (namedArguments[ii] == null) {
        throw new EvalException(loc, getSignature() + " received insufficient arguments");
      }
    }

    // fourth, fill in defaults from the signature, if any
    List<Object> defaults = signature.getDefaultValues();
    if (defaults != null) {
      int jj = 0;
      for (int ii = numMandatoryParameters; ii < numParams; ++ii) {
        if (namedArguments[ii] == null) {
          namedArguments[ii] = defaults.get(jj);
        }
        jj++;
      }
    }

    try {
      return call(namedArguments, ast, env);
    } catch (ConversionException
        | IllegalArgumentException
        | IllegalStateException
        | ClassCastException e) {
      throw new EvalException(loc, e.getMessage());
    }
  }
Exemplo n.º 5
0
 // Don't make it abstract, so that subclasses may be defined that @Override the outer call() only.
 protected Object call(Object[] args, @Nullable FuncallExpression ast, @Nullable Environment env)
     throws EvalException, ConversionException, InterruptedException {
   throw new EvalException(
       (ast == null) ? Location.BUILTIN : ast.getLocation(),
       String.format("function %s not implemented", getName()));
 }