All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.bloodshura.x.venus.expression.FunctionCall Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright (c) 2013-2018, João Vitor Verona Biazibetti - All Rights Reserved
 *
 * 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 should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see .
 *
 * https://www.github.com/BloodShura
 */

package com.github.bloodshura.x.venus.expression;

import com.github.bloodshura.x.collection.list.XList;
import com.github.bloodshura.x.collection.list.impl.XArrayList;
import com.github.bloodshura.x.collection.view.XArrayView;
import com.github.bloodshura.x.collection.view.XBasicView;
import com.github.bloodshura.x.collection.view.XView;
import com.github.bloodshura.x.venus.exception.runtime.InvalidFunctionParameterException;
import com.github.bloodshura.x.venus.exception.runtime.ScriptRuntimeException;
import com.github.bloodshura.x.venus.executor.Context;
import com.github.bloodshura.x.venus.function.Function;
import com.github.bloodshura.x.venus.function.FunctionCallDescriptor;
import com.github.bloodshura.x.venus.type.PrimitiveType;
import com.github.bloodshura.x.venus.type.Type;
import com.github.bloodshura.x.venus.value.DecimalValue;
import com.github.bloodshura.x.venus.value.IntegerValue;
import com.github.bloodshura.x.venus.value.Value;

public class FunctionCall implements Expression {
	private final Expression[] arguments;
	private final String functionName;

	public FunctionCall(String functionName, Expression... arguments) {
		this.arguments = arguments;
		this.functionName = functionName;
	}

	public XView getArguments() {
		return new XArrayView<>(arguments);
	}

	public String getFunctionName() {
		return functionName;
	}

	@Override
	public Value resolve(Context context) throws ScriptRuntimeException {
		XView values = getArguments().mapExceptional(expression -> expression.resolve(context));
		XView types = values.map(Value::getType);
		Function function = context.getOwner().findFunction(context, getFunctionName(), types);
		XList list = new XArrayList<>();
		int i = 0;

		// This check is necessary because of function references being untyped (issue #9).
		if (!function.isVarArgs() && types.size() != function.getArgumentTypes().size()) {
			throw new InvalidFunctionParameterException(context, "Function \"" + function + "\" expected " + function.getArgumentTypes().size() + " arguments; received " + types.size());
		}

		for (Value value : values) {
			if (!function.isVarArgs()) {
				Type required = function.getArgumentTypes().get(i);

				if (value.getType() == PrimitiveType.INTEGER && required == PrimitiveType.DECIMAL) {
					value = new DecimalValue(((IntegerValue) value).value());
				}

				// This check is necessary because of function references being untyped (issue #9).
				if (!required.accepts(value.getType())) {
					throw new InvalidFunctionParameterException(context, "Function \"" + function + "\" expected " + required + " as " + (i + 1) + (i == 0 ? "st" : i == 1 ? "nd" : i == 2 ? "rd" : "th") + " argument; received " + value.getType());
				}
			}

			list.add(value);
			i++;
		}

		return function.call(context, new FunctionCallDescriptor(this, getArguments(), new XBasicView<>(list)));
	}

	@Override
	public String toString() {
		return "functioncall(" + getFunctionName() + " <-- [" + getArguments().toString(", ") + "])";
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy