The complete source code of IdealIRC
http://www.idealirc.org/
445 lines
12 KiB
445 lines
12 KiB
/*
|
|
* IdealIRC Script Engine - Scripting tailored for IRC clients.
|
|
* Copyright (C) 2021 Tom-Andre Barstad.
|
|
* This software is licensed under the Software Attribution License.
|
|
* See LICENSE for more information.
|
|
*/
|
|
|
|
#include "Mathematics.h"
|
|
#include "Error.h"
|
|
#include "Script/ValueExtract.h"
|
|
#include "Script/ScriptException.h"
|
|
#include <random>
|
|
#include <math.h>
|
|
|
|
using namespace Builtin::Error;
|
|
|
|
namespace Builtin::Mathematics {
|
|
|
|
ValueHolder pow(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 2)
|
|
throwInsufficientParameters("pow", args.size(), 2);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("pow", 1);
|
|
|
|
if (args[1].getType() != ValueHolder::Type::Integer && args[1].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("pow", 2);
|
|
|
|
if (args[0] == 0 && args[1] == 0)
|
|
throw ScriptException("pow: 0^0 is undefined");
|
|
|
|
if (args[1] < 0)
|
|
throw ScriptException("pow: Cannot represent negative exponents");
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real
|
|
|| args[1].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
auto P = ValueExtract(args[1]).toReal();
|
|
return std::pow(N, P);
|
|
}
|
|
else {
|
|
auto N = ValueExtract(args[0]).toInt();
|
|
auto P = ValueExtract(args[1]).toInt();
|
|
return static_cast<int>(std::pow(N, P));
|
|
}
|
|
}
|
|
|
|
ValueHolder sqrt(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("sqrt", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("sqrt", 1);
|
|
|
|
if (args[0] < 0)
|
|
throw ScriptException("sqrt: Root of " + args[0].toStdString() + " is an imaginary number, not supported.");
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
return std::sqrt(N);
|
|
}
|
|
else {
|
|
auto N = ValueExtract(args[0]).toInt();
|
|
return std::sqrt(N);
|
|
}
|
|
}
|
|
|
|
ValueHolder cbrt(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("cbrt", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("cbrt", 1);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
return std::cbrt(N);
|
|
}
|
|
else {
|
|
auto N = ValueExtract(args[0]).toInt();
|
|
return std::cbrt(N);
|
|
}
|
|
}
|
|
|
|
ValueHolder floor(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("floor", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("floor", 1);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
return static_cast<int>(std::floor(N));
|
|
}
|
|
else {
|
|
return args[0];
|
|
}
|
|
}
|
|
|
|
ValueHolder ceil(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("ceil", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("ceil", 1);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
return static_cast<int>(std::ceil(N));
|
|
}
|
|
else {
|
|
return args[0];
|
|
}
|
|
}
|
|
|
|
ValueHolder round(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("round", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("round", 1);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
return static_cast<int>(std::round(N));
|
|
}
|
|
else {
|
|
return args[0];
|
|
}
|
|
}
|
|
|
|
ValueHolder abs(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("abs", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("abs", 1);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
return static_cast<int>(std::abs(N));
|
|
}
|
|
else {
|
|
auto N = ValueExtract(args[0]).toInt();
|
|
return static_cast<int>(std::abs(N));
|
|
}
|
|
}
|
|
|
|
ValueHolder clamp(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 3)
|
|
throwInsufficientParameters("clamp", args.size(), 3);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("clamp", 1);
|
|
|
|
if (args[1].getType() != ValueHolder::Type::Integer && args[1].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("clamp", 2);
|
|
|
|
if (args[2].getType() != ValueHolder::Type::Integer && args[2].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("clamp", 3);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real
|
|
|| args[1].getType() == ValueHolder::Type::Real
|
|
|| args[2].getType() == ValueHolder::Type::Real) {
|
|
auto low = ValueExtract(args[1]).toReal();
|
|
auto high = ValueExtract(args[2]).toReal();
|
|
if (low > high)
|
|
throw ScriptException("clamp: low > high");
|
|
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
|
|
if (N < low)
|
|
return low;
|
|
else if (N > high)
|
|
return high;
|
|
else
|
|
return N;
|
|
}
|
|
else {
|
|
auto low = ValueExtract(args[1]).toInt();
|
|
auto high = ValueExtract(args[2]).toInt();
|
|
if (low > high)
|
|
throw ScriptException("clamp: low > high");
|
|
|
|
auto N = ValueExtract(args[0]).toInt();
|
|
|
|
if (N < low)
|
|
return low;
|
|
else if (N > high)
|
|
return high;
|
|
else
|
|
return N;
|
|
}
|
|
}
|
|
|
|
ValueHolder clamp01(Script& script, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("clamp01", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("clamp01", 1);
|
|
|
|
std::vector<ValueHolder> clampArgs { args[0], 0, 1 };
|
|
return clamp(script, clampArgs);
|
|
}
|
|
|
|
ValueHolder rand(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 2)
|
|
throwInsufficientParameters("rand", args.size(), 2);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("rand", 1);
|
|
|
|
if (args[1].getType() != ValueHolder::Type::Integer && args[1].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("rand", 2);
|
|
|
|
std::random_device rd;
|
|
std::mt19937 mt(rd());
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real || args[1].getType() == ValueHolder::Type::Real) {
|
|
auto low = ValueExtract(args[0]).toReal();
|
|
auto high = ValueExtract(args[1]).toReal();
|
|
if (low > high)
|
|
throw ScriptException("rand: low > high");
|
|
std::uniform_real_distribution<double> uniform_dist(low, high);
|
|
return uniform_dist(mt);
|
|
}
|
|
else {
|
|
auto low = ValueExtract(args[0]).toInt();
|
|
auto high = ValueExtract(args[1]).toInt();
|
|
if (low > high)
|
|
throw ScriptException("rand: low > high");
|
|
std::uniform_int_distribution<int> uniform_dist(low, high);
|
|
return uniform_dist(mt);
|
|
}
|
|
}
|
|
|
|
ValueHolder scale(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 5)
|
|
throwInsufficientParameters("scale", args.size(), 5);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("scale", 1);
|
|
|
|
if (args[1].getType() != ValueHolder::Type::Integer && args[1].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("scale", 2);
|
|
|
|
if (args[2].getType() != ValueHolder::Type::Integer && args[2].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("scale", 3);
|
|
|
|
if (args[3].getType() != ValueHolder::Type::Integer && args[3].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("scale", 4);
|
|
|
|
if (args[4].getType() != ValueHolder::Type::Integer && args[4].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("scale", 5);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real
|
|
|| args[1].getType() == ValueHolder::Type::Real
|
|
|| args[2].getType() == ValueHolder::Type::Real
|
|
|| args[3].getType() == ValueHolder::Type::Real
|
|
|| args[4].getType() == ValueHolder::Type::Real) {
|
|
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
auto oldMin = ValueExtract(args[1]).toReal();
|
|
auto oldMax = ValueExtract(args[2]).toReal();
|
|
auto newMin = ValueExtract(args[3]).toReal();
|
|
auto newMax = ValueExtract(args[4]).toReal();
|
|
return newMin + (N - oldMin) * (newMax - newMin) / (oldMax - oldMin);
|
|
}
|
|
else {
|
|
auto N = ValueExtract(args[0]).toInt();
|
|
auto oldMin = ValueExtract(args[1]).toInt();
|
|
auto oldMax = ValueExtract(args[2]).toInt();
|
|
auto newMin = ValueExtract(args[3]).toInt();
|
|
auto newMax = ValueExtract(args[4]).toInt();
|
|
return newMin + (N - oldMin) * (newMax - newMin) / (oldMax - oldMin);
|
|
}
|
|
}
|
|
|
|
ValueHolder log(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("log", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("log", 1);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
if (N < 0)
|
|
throwNegativeInputUndefined("log");
|
|
return std::log(N);
|
|
}
|
|
else {
|
|
auto N = ValueExtract(args[0]).toInt();
|
|
if (N < 0)
|
|
throwNegativeInputUndefined("log");
|
|
return std::log(N);
|
|
}
|
|
}
|
|
|
|
ValueHolder log10(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("log10", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("log10", 1);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
if (N < 0)
|
|
throwNegativeInputUndefined("log10");
|
|
return std::log10(N);
|
|
}
|
|
else {
|
|
auto N = ValueExtract(args[0]).toInt();
|
|
if (N < 0)
|
|
throwNegativeInputUndefined("log10");
|
|
return std::log10(N);
|
|
}
|
|
}
|
|
|
|
ValueHolder sin(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("sin", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("sin", 1);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
return std::sin(N);
|
|
}
|
|
else {
|
|
auto N = ValueExtract(args[0]).toInt();
|
|
return std::sin(N);
|
|
}
|
|
}
|
|
|
|
ValueHolder asin(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("asin", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("asin", 1);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
return std::asin(N);
|
|
}
|
|
else {
|
|
auto N = ValueExtract(args[0]).toInt();
|
|
return std::asin(N);
|
|
}
|
|
}
|
|
|
|
ValueHolder cos(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("cos", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("cos", 1);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
return std::cos(N);
|
|
}
|
|
else {
|
|
auto N = ValueExtract(args[0]).toInt();
|
|
return std::cos(N);
|
|
}
|
|
}
|
|
|
|
ValueHolder acos(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("acos", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("acos", 1);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
return std::acos(N);
|
|
}
|
|
else {
|
|
auto N = ValueExtract(args[0]).toInt();
|
|
return std::acos(N);
|
|
}
|
|
}
|
|
|
|
ValueHolder tan(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("tan", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("tan", 1);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
return std::tan(N);
|
|
}
|
|
else {
|
|
auto N = ValueExtract(args[0]).toInt();
|
|
return std::tan(N);
|
|
}
|
|
}
|
|
|
|
ValueHolder atan(Script&, std::vector<ValueHolder>& args)
|
|
{
|
|
if (args.size() != 1)
|
|
throwInsufficientParameters("atan", args.size(), 1);
|
|
|
|
if (args[0].getType() != ValueHolder::Type::Integer && args[0].getType() != ValueHolder::Type::Real)
|
|
throwNotANumber("atan", 1);
|
|
|
|
if (args[0].getType() == ValueHolder::Type::Real) {
|
|
auto N = ValueExtract(args[0]).toReal();
|
|
return std::atan(N);
|
|
}
|
|
else {
|
|
auto N = ValueExtract(args[0]).toInt();
|
|
return std::atan(N);
|
|
}
|
|
}
|
|
|
|
} // namespace Builtin::Mathematics
|
|
|
|
|