diff --git a/std/N8Library.hpp b/std/N8Library.hpp
new file mode 100644
index 0000000..4aa3afb
--- /dev/null
+++ b/std/N8Library.hpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2024 - Nathanne Isip
+ * This file is part of N8.
+ *
+ * N8 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * N8 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with N8. If not, see .
+ */
+
+#ifndef N8_STD_LIB_CC
+#define N8_STD_LIB_CC
+
+#include
+#include
+#include
+
+#include
+
+#define N8_LIB_START extern "C" {
+#define N8_LIB_END }
+
+#define N8_FUNC(funcName) \
+ DynamicObject funcName( \
+ std::shared_ptr address, \
+ SymbolTable& symtab, \
+ std::vector& args \
+ )
+
+#endif
diff --git a/std/n8std/IO.cc b/std/n8std/IO.cc
new file mode 100644
index 0000000..6287d51
--- /dev/null
+++ b/std/n8std/IO.cc
@@ -0,0 +1,492 @@
+/*
+ * Copyright (c) 2024 - Nathanne Isip
+ * This file is part of N8.
+ *
+ * N8 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * N8 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with N8. If not, see .
+ */
+
+#include "n8std/IO.hpp"
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifdef _WIN32
+# include
+#else
+# include
+# include
+#endif
+
+N8_FUNC(io_print) {
+ if(args.size() == 0)
+ return {};
+
+ for(size_t i = 0; i < args.size(); i++) {
+ DynamicObject arg = args.at(i);
+ std::cout << arg.toString();
+ }
+
+ return {};
+}
+
+N8_FUNC(io_printLine) {
+ if(args.size() == 0)
+ return {};
+
+ for(size_t i = 0; i < args.size(); i++) {
+ DynamicObject arg = args.at(i);
+ std::cout << arg.toString() << std::endl;
+ }
+
+ return {};
+}
+
+N8_FUNC(io_readString) {
+ std::string str;
+ std::getline(std::cin, str);
+
+ return DynamicObject(str);
+}
+
+N8_FUNC(io_readNumber) {
+ std::string str;
+ std::getline(std::cin, str);
+
+ return DynamicObject(::atof(str.c_str()));
+}
+
+N8_FUNC(io_readBoolean) {
+ std::string str;
+ std::getline(std::cin, str);
+
+ bool boolVal = false;
+ if(str == "true")
+ boolVal = true;
+
+ return DynamicObject(boolVal);
+}
+
+N8_FUNC(io_fileRead) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject fileName = args.at(0);
+ std::ifstream file(fileName.toString());
+ std::vector returnValues;
+
+ if(!file) {
+ returnValues.emplace_back(DynamicObject());
+ returnValues.emplace_back(
+ DynamicObject("Error: Could not open the file " + fileName.toString())
+ );
+
+ return DynamicObject(std::make_shared>(returnValues));
+ }
+
+ std::string content((std::istreambuf_iterator(file)), std::istreambuf_iterator());
+ returnValues.emplace_back(content);
+ returnValues.emplace_back(DynamicObject());
+
+ return DynamicObject(std::make_shared>(returnValues));
+}
+
+N8_FUNC(io_fileWrite) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 2 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject fileName = args.at(0),
+ fileContent = args.at(1);
+
+ std::ofstream file(fileName.toString());
+ if(!file)
+ return DynamicObject(false);
+
+ file << fileContent.toString();
+ return DynamicObject(true);
+}
+
+N8_FUNC(io_fileSize) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject fileName = args.at(0);
+ std::ifstream file(fileName.toString(), std::ios::binary | std::ios::ate);
+ std::vector returnValues;
+
+ if(!file) {
+ returnValues.emplace_back(DynamicObject(0.0));
+ returnValues.emplace_back(DynamicObject(false));
+
+ return DynamicObject(std::make_shared>(returnValues));
+ }
+
+ returnValues.emplace_back(DynamicObject(
+ static_cast(file.tellg())
+ ));
+ returnValues.emplace_back(DynamicObject(true));
+ return DynamicObject(std::make_shared>(returnValues));
+}
+
+N8_FUNC(io_filePerms) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject fileName = args.at(0);
+ std::vector returnValues;
+
+ #ifdef _WIN32
+
+ DWORD attributes = GetFileAttributes(fileName.toString().c_str());
+ if(attributes == INVALID_FILE_ATTRIBUTES) {
+ returnValues.emplace_back(DynamicObject(0.0));
+ returnValues.emplace_back(DynamicObject("Could not get file attributes"));
+
+ return DynamicObject(std::make_shared>(returnValues));
+ }
+
+ unsigned int permissions = 0;
+ if(attributes & FILE_ATTRIBUTE_READONLY)
+ permissions |= 0x01;
+ else permissions |= 0x02;
+
+ #else
+
+ struct stat fileStat;
+ if(stat(fileName.toString().c_str(), &fileStat) != 0) {
+ returnValues.emplace_back(DynamicObject(0.0));
+ returnValues.emplace_back(DynamicObject("Could not get file status"));
+
+ return DynamicObject(std::make_shared>(returnValues));
+ }
+
+ unsigned int permissions = 0;
+ permissions |= (fileStat.st_mode & S_IRUSR) ? 0x0100 : 0;
+ permissions |= (fileStat.st_mode & S_IWUSR) ? 0x0200 : 0;
+ permissions |= (fileStat.st_mode & S_IXUSR) ? 0x0400 : 0;
+ permissions |= (fileStat.st_mode & S_IRGRP) ? 0x0010 : 0;
+ permissions |= (fileStat.st_mode & S_IWGRP) ? 0x0020 : 0;
+ permissions |= (fileStat.st_mode & S_IXGRP) ? 0x0040 : 0;
+ permissions |= (fileStat.st_mode & S_IROTH) ? 0x0001 : 0;
+ permissions |= (fileStat.st_mode & S_IWOTH) ? 0x0002 : 0;
+ permissions |= (fileStat.st_mode & S_IXOTH) ? 0x0004 : 0;
+
+ #endif
+
+ returnValues.emplace_back(DynamicObject(static_cast(permissions)));
+ returnValues.emplace_back(DynamicObject());
+
+ return DynamicObject(std::make_shared>(returnValues));
+}
+
+N8_FUNC(io_fileCreationDate) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject fileName = args.at(0);
+ std::vector returnValues;
+ std::filesystem::path filePath(fileName.toString().c_str());
+
+ if(!std::filesystem::exists(filePath)) {
+ returnValues.emplace_back(DynamicObject(0.0));
+ returnValues.emplace_back(DynamicObject("File does not exist"));
+ }
+ else {
+ auto creationTime = std::filesystem::last_write_time(filePath);
+ auto sctp = std::chrono::time_point_cast(
+ creationTime - std::filesystem::file_time_type::clock::now() +
+ std::chrono::system_clock::now()
+ );
+ auto ctime = std::chrono::system_clock::to_time_t(sctp);
+
+ returnValues.emplace_back(DynamicObject(0.0));
+ returnValues.emplace_back(DynamicObject(
+ static_cast(ctime)
+ ));
+ }
+
+ return DynamicObject(std::make_shared>(
+ returnValues
+ ));
+}
+
+N8_FUNC(io_fileDelete) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject fileName = args.at(0);
+ std::vector returnValues;
+
+ #ifdef _WIN32
+
+ if(DeleteFile(fileName.toString().c_str())) {
+ returnValues.emplace_back(DynamicObject(true));
+ returnValues.emplace_back(DynamicObject());
+ }
+ else {
+ returnValues.emplace_back(DynamicObject(false));
+ returnValues.emplace_back(DynamicObject("Could not delete file"));
+ }
+
+ #else
+
+ struct stat buffer;
+ if(stat(fileName.toString().c_str(), &buffer) == 0) {
+ if(remove(fileName.toString().c_str()) == 0) {
+ returnValues.emplace_back(DynamicObject(true));
+ returnValues.emplace_back(DynamicObject());
+ }
+ else {
+ returnValues.emplace_back(DynamicObject(false));
+ returnValues.emplace_back(DynamicObject("Could not delete file"));
+ }
+ }
+ else {
+ returnValues.emplace_back(DynamicObject(false));
+ returnValues.emplace_back(DynamicObject("File does not exist"));
+ }
+
+ #endif
+
+ return DynamicObject(std::make_shared>(returnValues));
+}
+
+N8_FUNC(io_folderCreate) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject folderName = args.at(0);
+ std::vector returnValues;
+ std::filesystem::path folderPath(folderName.toString().c_str());
+
+ if(std::filesystem::exists(folderPath)) {
+ returnValues.emplace_back(DynamicObject(false));
+ returnValues.emplace_back(DynamicObject("Folder already exists"));
+
+ return DynamicObject(std::make_shared>(returnValues));
+ }
+
+ if(std::filesystem::create_directory(folderPath)) {
+ returnValues.emplace_back(DynamicObject(true));
+ returnValues.emplace_back(DynamicObject());
+
+ return DynamicObject(std::make_shared>(returnValues));
+ }
+
+ returnValues.emplace_back(DynamicObject(false));
+ returnValues.emplace_back(DynamicObject("Could not create folder"));
+
+ return DynamicObject(std::make_shared>(returnValues));
+}
+
+N8_FUNC(io_folderSize) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject folderName = args.at(0);
+ std::vector returnValues;
+ std::filesystem::path path(folderName.toString().c_str());
+ unsigned long long totalSize = 0;
+
+ if(!std::filesystem::exists(path) || !std::filesystem::is_directory(path)) {
+ returnValues.emplace_back(DynamicObject(0.0));
+ returnValues.emplace_back(DynamicObject(
+ "Provided path is not a directory or does not exist"
+ ));
+
+ return DynamicObject(std::make_shared>(returnValues));
+ }
+
+ #pragma omp parallel for
+ for(const auto& entry : std::filesystem::recursive_directory_iterator(path))
+ if(std::filesystem::is_regular_file(entry))
+ totalSize += std::filesystem::file_size(entry);
+
+ returnValues.emplace_back(DynamicObject(static_cast(totalSize)));
+ returnValues.emplace_back(DynamicObject());
+
+ return DynamicObject(std::make_shared>(returnValues));
+}
+
+N8_FUNC(io_folderCreationDate) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject folderName = args.at(0);
+ std::vector returnValues;
+ std::filesystem::path filePath(folderName.toString().c_str());
+
+ if(!std::filesystem::exists(filePath)) {
+ returnValues.emplace_back(DynamicObject(0.0));
+ returnValues.emplace_back(DynamicObject("File does not exist"));
+ }
+ else {
+ auto creationTime = std::filesystem::last_write_time(filePath);
+ auto sctp = std::chrono::time_point_cast(
+ creationTime - std::filesystem::file_time_type::clock::now() +
+ std::chrono::system_clock::now()
+ );
+ auto ctime = std::chrono::system_clock::to_time_t(sctp);
+
+ returnValues.emplace_back(DynamicObject(0.0));
+ returnValues.emplace_back(DynamicObject(
+ static_cast(ctime)
+ ));
+ }
+
+ return DynamicObject(std::make_shared>(returnValues));
+}
+
+N8_FUNC(io_folderDelete) {
+ if(args.empty() || args.size() >= 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 or 2 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject folderName = args.at(0);
+ std::vector returnValues;
+ std::filesystem::path filePath(folderName.toString().c_str());
+
+ bool isRecursize = false;
+ if(args.size() == 2) {
+ DynamicObject recArg = args.at(1);
+ isRecursize = recArg.booleanEquivalent();
+ }
+
+ if(!std::filesystem::exists(filePath) || !std::filesystem::is_directory(filePath))
+ return DynamicObject(false);
+
+ if(isRecursize)
+ std::filesystem::remove_all(filePath);
+ else std::filesystem::remove(filePath);
+
+ return DynamicObject(true);
+}
+
+N8_FUNC(io_isFile) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject fileName = args.at(0);
+ std::filesystem::path filePath(fileName.toString().c_str());
+
+ return DynamicObject(
+ std::filesystem::exists(filePath) &&
+ std::filesystem::is_regular_file(filePath)
+ );
+}
+
+N8_FUNC(io_isFolder) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject fileName = args.at(0);
+ std::filesystem::path filePath(fileName.toString().c_str());
+
+ return DynamicObject(
+ std::filesystem::exists(filePath) &&
+ std::filesystem::is_directory(filePath)
+ );
+}
+
+N8_FUNC(io_listAllFiles) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject fileName = args.at(0);
+ std::filesystem::path dirPath(fileName.toString().c_str());
+ std::vector returnValues;
+
+ if(!std::filesystem::exists(dirPath) || !std::filesystem::is_directory(dirPath))
+ return DynamicObject();
+
+ #pragma omp parallel for
+ for(const auto& entry : std::filesystem::directory_iterator(dirPath))
+ returnValues.emplace_back(DynamicObject(
+ entry.path().filename().string()
+ ));
+
+ return DynamicObject(std::make_shared>(returnValues));
+}
+
+N8_FUNC(io_exit) {
+ if(args.size() == 0)
+ exit(0);
+
+ DynamicObject exitCode = args.at(0);
+ if(!exitCode.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Exit code is not a number."
+ );
+
+ exit(static_cast(exitCode.getNumber()));
+ return {};
+}
diff --git a/std/n8std/IO.hpp b/std/n8std/IO.hpp
new file mode 100644
index 0000000..4e8fe3b
--- /dev/null
+++ b/std/n8std/IO.hpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2024 - Nathanne Isip
+ * This file is part of N8.
+ *
+ * N8 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * N8 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with N8. If not, see .
+ */
+
+#ifndef N8_STDLIB_IO_CC
+#define N8_STDLIB_IO_CC
+
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
+#endif
+
+#include "N8Library.hpp"
+
+N8_LIB_START
+
+N8_FUNC(io_print);
+N8_FUNC(io_printLine);
+
+N8_FUNC(io_readString);
+N8_FUNC(io_readNumber);
+N8_FUNC(io_readBoolean);
+
+N8_FUNC(io_fileRead);
+N8_FUNC(io_fileWrite);
+N8_FUNC(io_fileSize);
+N8_FUNC(io_filePerms);
+N8_FUNC(io_fileCreationDate);
+N8_FUNC(io_fileDelete);
+
+N8_FUNC(io_folderCreate);
+N8_FUNC(io_folderSize);
+N8_FUNC(io_folderCreationDate);
+N8_FUNC(io_folderDelete);
+
+N8_FUNC(io_isFile);
+N8_FUNC(io_isFolder);
+N8_FUNC(io_listAllFiles);
+
+N8_FUNC(io_exit);
+
+N8_LIB_END
+
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif
+
+#endif
diff --git a/std/n8std/ML.cc b/std/n8std/ML.cc
new file mode 100644
index 0000000..17b8b76
--- /dev/null
+++ b/std/n8std/ML.cc
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2024 - Nathanne Isip
+ * This file is part of N8.
+ *
+ * N8 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * N8 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with N8. If not, see .
+ */
+
+#include "n8std/ML.hpp"
+
+#include
+
+#include
+#include
+#include
+
+static inline std::vector arrayToDoubleVector(
+ std::shared_ptr address,
+ std::vector array
+) {
+ std::vector values(array.size());
+
+ #pragma omp parallel for
+ for(size_t i = 0; i < array.size(); i++) {
+ if(!array[i].isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Value from array is not a number"
+ );
+
+ values[i] = array[i].getNumber();
+ }
+
+ return values;
+}
+
+static inline double calculateMean(
+ std::shared_ptr address,
+ std::vector array
+) {
+ std::vector values = arrayToDoubleVector(
+ std::move(address),
+ array
+ );
+ size_t arraySize = array.size();
+ double sum = 0.0;
+
+ #pragma omp parallel for reduction(+:sum)
+ for(size_t i = 0; i < arraySize; i++)
+ sum += values[i];
+
+ return sum / arraySize;
+}
+
+N8_FUNC(ml_trendline_calculate) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 2 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject xObj = args.at(0),
+ yObj = args.at(1);
+
+ if(!xObj.isArray() || !yObj.isArray())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Parameter x and y must be both number array"
+ );
+
+ std::vector xObjArray = *xObj.getArray();
+ std::vector yObjArray = *yObj.getArray();
+
+ if(xObjArray.size() != yObjArray.size())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Data set size of x and y did not match"
+ );
+
+ double x = calculateMean(std::move(address), xObjArray),
+ y = calculateMean(std::move(address), yObjArray),
+ numerator = 0.0,
+ denominator = 0.0;
+
+ #pragma omp parallel for
+ for(size_t i = 0; i < xObjArray.size(); i++) {
+ numerator += (xObjArray[i].getNumber() - x) *
+ (yObjArray[i].getNumber() - y);
+
+ denominator += (xObjArray[i].getNumber() - x) *
+ (xObjArray[i].getNumber() - x);
+ }
+
+ double slope = numerator / denominator;
+ std::vector returnValues;
+
+ returnValues.emplace_back(DynamicObject(slope));
+ returnValues.emplace_back(DynamicObject(y - slope * x));
+
+ return DynamicObject(std::make_shared>(
+ returnValues
+ ));
+}
+
+N8_FUNC(ml_trendline_calculateRmse) {
+ if(args.size() != 3)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 3 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject xObj = args.at(0),
+ yObj = args.at(1),
+ model = args.at(2);
+ std::vector regModel = *model.getArray();
+
+ if(!model.isArray() || regModel.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Invalid linear regression model"
+ );
+
+ if(!xObj.isArray() || !yObj.isArray())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Parameter x and y must be both number array"
+ );
+
+ std::vector xObjArray = *xObj.getArray();
+ std::vector yObjArray = *yObj.getArray();
+
+ if(xObjArray.size() != yObjArray.size())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Data set size of x and y did not match"
+ );
+
+ double sumSquaredErrs = 0.0;
+ size_t paramSize = xObjArray.size();
+
+ #pragma omp parallel for
+ for(size_t i = 0; i < paramSize; i++) {
+ std::vector model;
+ model.emplace_back(regModel.at(0));
+ model.emplace_back(regModel.at(1));
+
+ std::vector params;
+ params.emplace_back(DynamicObject(
+ std::make_shared>(model)
+ ));
+ params.emplace_back(xObjArray[i]);
+
+ double yPred = ml_trendline_predict(
+ std::move(address),
+ symtab,
+ params
+ ).getNumber();
+ double error = yObjArray[i].getNumber() - yPred;
+
+ sumSquaredErrs += error * error;
+ }
+
+ return DynamicObject(std::sqrt(sumSquaredErrs / paramSize));
+}
+
+N8_FUNC(ml_trendline_predict) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 3 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject model = args.at(0),
+ value = args.at(1);
+ std::vector regModel = *model.getArray();
+
+ if(!model.isArray() || regModel.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Invalid linear regression model"
+ );
+
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Cannot predict linear regression value for non-numbers"
+ );
+
+ DynamicObject slope = regModel.at(0),
+ intercept = regModel.at(1);
+
+ if(!slope.isNumber() || !intercept.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Linear regression model's slope and intercept must be a number"
+ );
+
+ return DynamicObject(
+ slope.getNumber() *
+ value.getNumber() +
+ intercept.getNumber()
+ );
+}
diff --git a/std/n8std/ML.hpp b/std/n8std/ML.hpp
new file mode 100644
index 0000000..303e120
--- /dev/null
+++ b/std/n8std/ML.hpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2024 - Nathanne Isip
+ * This file is part of N8.
+ *
+ * N8 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * N8 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with N8. If not, see .
+ */
+
+#ifndef N8_STDLIB_ML_CC
+#define N8_STDLIB_ML_CC
+
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
+#endif
+
+#include "N8Library.hpp"
+
+N8_LIB_START
+
+N8_FUNC(ml_trendline_calculate);
+N8_FUNC(ml_trendline_calculateRmse);
+N8_FUNC(ml_trendline_predict);
+
+N8_LIB_END
+
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif
+
+#endif
diff --git a/std/n8std/Math.cc b/std/n8std/Math.cc
new file mode 100644
index 0000000..cd27191
--- /dev/null
+++ b/std/n8std/Math.cc
@@ -0,0 +1,909 @@
+/*
+ * Copyright (c) 2024 - Nathanne Isip
+ * This file is part of N8.
+ *
+ * N8 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * N8 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with N8. If not, see .
+ */
+
+#include "n8std/Math.hpp"
+
+#include
+
+#include
+#include
+#include
+
+N8_FUNC(math_cos) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(cos(value.getNumber()));
+}
+
+N8_FUNC(math_cosh) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(cosh(value.getNumber()));
+}
+
+N8_FUNC(math_sin) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(sin(value.getNumber()));
+}
+
+N8_FUNC(math_sinh) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(sinh(value.getNumber()));
+}
+
+N8_FUNC(math_tan) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(tan(value.getNumber()));
+}
+
+N8_FUNC(math_tanh) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(tanh(value.getNumber()));
+}
+
+N8_FUNC(math_acos) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(acos(value.getNumber()));
+}
+
+N8_FUNC(math_acosh) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(acosh(value.getNumber()));
+}
+
+N8_FUNC(math_asin) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(asin(value.getNumber()));
+}
+
+N8_FUNC(math_asinh) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(asinh(value.getNumber()));
+}
+
+N8_FUNC(math_atan) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(atan(value.getNumber()));
+}
+
+N8_FUNC(math_atan2) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 2 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject y = args.at(0),
+ x = args.at(1);
+ if(!y.isNumber() || !x.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "One of the argument type is not of number."
+ );
+
+ return DynamicObject(atan2(y.getNumber(), x.getNumber()));
+}
+
+N8_FUNC(math_atanh) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(atanh(value.getNumber()));
+}
+
+N8_FUNC(math_rand) {
+ std::uniform_real_distribution<> dis(0.0, 1.0);
+ double value = 0.0f;
+
+ if(args.size() == 1) {
+ DynamicObject arg = args.at(0);
+ if(!arg.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting a number argument."
+ );
+
+ std::mt19937 gen(arg.getNumber());
+ value = dis(gen);
+ }
+ else {
+ std::random_device rd;
+ std::mt19937 gen(rd());
+
+ value = dis(gen);
+ }
+
+ return DynamicObject(value);
+}
+
+N8_FUNC(math_pow) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 2 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject x = args.at(0),
+ y = args.at(1);
+ if(!x.isNumber() || !y.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "One of the argument type is not of number."
+ );
+
+ return DynamicObject(pow(x.getNumber(), y.getNumber()));
+}
+
+N8_FUNC(math_pow2) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(exp2(value.getNumber()));
+}
+
+N8_FUNC(math_log) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(log(value.getNumber()));
+}
+
+N8_FUNC(math_log10) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(log10(value.getNumber()));
+}
+
+N8_FUNC(math_log1p) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(log1p(value.getNumber()));
+}
+
+N8_FUNC(math_log2) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(log2(value.getNumber()));
+}
+
+N8_FUNC(math_exp) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(exp(value.getNumber()));
+}
+
+N8_FUNC(math_splitExponent) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ int n;
+ double param = value.getNumber(),
+ result = frexp(param, &n);
+
+ std::vector returnValues;
+ returnValues.emplace_back(DynamicObject(result));
+ returnValues.emplace_back(DynamicObject(static_cast(n)));
+
+ return DynamicObject(std::make_shared>(
+ returnValues
+ ));
+}
+
+N8_FUNC(math_combineExponent) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 2 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject x = args.at(0),
+ y = args.at(1);
+ if(!x.isNumber() || !y.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "One of the argument type is not of number."
+ );
+
+ return DynamicObject(ldexp(
+ x.getNumber(),
+ static_cast(y.getNumber())
+ ));
+}
+
+N8_FUNC(math_extractExponent) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(logb(value.getNumber()));
+}
+
+N8_FUNC(math_scaleByExponent) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 2 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject x = args.at(0),
+ y = args.at(1);
+ if(!x.isNumber() || !y.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "One of the argument type is not of number."
+ );
+
+ return DynamicObject(scalbn(
+ x.getNumber(),
+ static_cast(y.getNumber())
+ ));
+}
+
+N8_FUNC(math_squareRoot) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(sqrt(value.getNumber()));
+}
+
+N8_FUNC(math_cubicRoot) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(cbrt(value.getNumber()));
+}
+
+N8_FUNC(math_inverseSqrt) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ // Based on the Quake III Fast Inversed Square Root Algorithm
+ union {
+ float f;
+ uint32_t i;
+ } conv;
+
+ float x2, number = value.getNumber();
+ const float threehalfs = 1.5F;
+
+ x2 = number * 0.5F;
+ conv.f = number;
+ conv.i = 0x5f3759df - (conv.i >> 1);
+ conv.f = conv.f * (threehalfs - (x2 * conv.f * conv.f));
+
+ return DynamicObject(conv.f);
+}
+
+N8_FUNC(math_hypotenuse) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 2 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject x = args.at(0),
+ y = args.at(1);
+ if(!x.isNumber() || !y.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "One of the argument type is not of number."
+ );
+
+ return DynamicObject(hypot(
+ x.getNumber(),
+ y.getNumber()
+ ));
+}
+
+N8_FUNC(math_ceil) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(ceil(value.getNumber()));
+}
+
+N8_FUNC(math_floor) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(floor(value.getNumber()));
+}
+
+N8_FUNC(math_round) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(round(value.getNumber()));
+}
+
+N8_FUNC(math_dim) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 2 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject x = args.at(0),
+ y = args.at(1);
+ if(!x.isNumber() || !y.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "One of the argument type is not of number."
+ );
+
+ return DynamicObject(fdim(
+ x.getNumber(),
+ y.getNumber()
+ ));
+}
+
+N8_FUNC(math_min) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 2 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject x = args.at(0),
+ y = args.at(1);
+ if(!x.isNumber() || !y.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "One of the argument type is not of number."
+ );
+
+ return DynamicObject(fmin(
+ x.getNumber(),
+ y.getNumber()
+ ));
+}
+
+N8_FUNC(math_max) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 2 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject x = args.at(0),
+ y = args.at(1);
+ if(!x.isNumber() || !y.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "One of the argument type is not of number."
+ );
+
+ return DynamicObject(fmax(
+ x.getNumber(),
+ y.getNumber()
+ ));
+}
+
+N8_FUNC(math_errorFunc) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(erf(value.getNumber()));
+}
+
+N8_FUNC(math_errorFuncComp) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(erfc(value.getNumber()));
+}
+
+N8_FUNC(math_remainder) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 2 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject x = args.at(0),
+ y = args.at(1);
+ if(!x.isNumber() || !y.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "One of the argument type is not of number."
+ );
+
+ return DynamicObject(remainder(
+ x.getNumber(),
+ y.getNumber()
+ ));
+}
+
+N8_FUNC(math_remQuotient) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject x = args.at(0),
+ y = args.at(1);
+ if(!x.isNumber() || !y.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "One of the argument type is not of number."
+ );
+
+ int n;
+ double xn = x.getNumber(),
+ yn = y.getNumber(),
+ result = remquo(xn, yn, &n);
+
+ std::vector returnValues;
+ returnValues.emplace_back(DynamicObject(result));
+ returnValues.emplace_back(DynamicObject(static_cast(n)));
+
+ return DynamicObject(std::make_shared>(
+ returnValues
+ ));
+}
+
+N8_FUNC(math_abs) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(fabs(value.getNumber()));
+}
+
+N8_FUNC(math_fusedMultiplyAdd) {
+ if(args.size() != 3)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 3 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject x = args.at(0),
+ y = args.at(1),
+ z = args.at(2);
+ if(!x.isNumber() || !y.isNumber() || !z.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "One of the argument type is not of number."
+ );
+
+ return DynamicObject(fma(
+ x.getNumber(),
+ y.getNumber(),
+ z.getNumber()
+ ));
+}
+
+N8_FUNC(math_sigmoid) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ return DynamicObject(1 / (1 + exp(-value.getNumber())));
+}
+
+N8_FUNC(math_sigmoidDerivative) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject value = args.at(0);
+ if(!value.isNumber())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Argument type is not of number."
+ );
+
+ double num = value.getNumber();
+ return DynamicObject(num * (1 - num));
+}
+
+N8_FUNC(math_step);
+
+N8_FUNC(math_relu);
+
+N8_FUNC(math_leakyRelu);
+
+N8_FUNC(math_elu);
+
+N8_FUNC(math_selu);
+
+N8_FUNC(math_softmax);
+
+N8_FUNC(math_swish);
+
+N8_FUNC(math_mish);
+
+N8_FUNC(math_hardSigmoid);
+
+N8_FUNC(math_hardTan);
+
+N8_FUNC(math_softplus);
+
+N8_FUNC(math_softsign);
+
+N8_FUNC(math_gaussian);
+
+N8_FUNC(math_bentIdentity);
+
+N8_FUNC(math_logLogistic);
diff --git a/std/n8std/Math.hpp b/std/n8std/Math.hpp
new file mode 100644
index 0000000..4a1a421
--- /dev/null
+++ b/std/n8std/Math.hpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2024 - Nathanne Isip
+ * This file is part of N8.
+ *
+ * N8 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * N8 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with N8. If not, see .
+ */
+
+#ifndef N8_STDLIB_MATH_CC
+#define N8_STDLIB_MATH_CC
+
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
+#endif
+
+#include "N8Library.hpp"
+
+N8_LIB_START
+
+N8_FUNC(math_cos);
+N8_FUNC(math_cosh);
+
+N8_FUNC(math_sin);
+N8_FUNC(math_sinh);
+
+N8_FUNC(math_tan);
+N8_FUNC(math_tanh);
+
+N8_FUNC(math_acos);
+N8_FUNC(math_acosh);
+
+N8_FUNC(math_asin);
+N8_FUNC(math_asinh);
+
+N8_FUNC(math_atan);
+N8_FUNC(math_atan2);
+N8_FUNC(math_atanh);
+
+N8_FUNC(math_rand);
+
+N8_FUNC(math_pow);
+N8_FUNC(math_pow2);
+
+N8_FUNC(math_log);
+N8_FUNC(math_log10);
+N8_FUNC(math_log1p);
+N8_FUNC(math_log2);
+
+N8_FUNC(math_exp);
+N8_FUNC(math_splitExponent);
+N8_FUNC(math_combineExponent);
+N8_FUNC(math_extractExponent);
+N8_FUNC(math_scaleByExponent);
+
+N8_FUNC(math_squareRoot);
+N8_FUNC(math_cubicRoot);
+N8_FUNC(math_inverseSqrt);
+N8_FUNC(math_hypotenuse);
+
+N8_FUNC(math_ceil);
+N8_FUNC(math_floor);
+N8_FUNC(math_round);
+
+N8_FUNC(math_dim);
+N8_FUNC(math_min);
+N8_FUNC(math_max);
+
+N8_FUNC(math_errorFunc);
+N8_FUNC(math_errorFuncComp);
+
+N8_FUNC(math_remainder);
+N8_FUNC(math_remQuotient);
+N8_FUNC(math_abs);
+N8_FUNC(math_fusedMultiplyAdd);
+
+N8_FUNC(math_sigmoid);
+N8_FUNC(math_sigmoidDerivative);
+N8_FUNC(math_step);
+N8_FUNC(math_relu);
+N8_FUNC(math_leakyRelu);
+N8_FUNC(math_elu);
+N8_FUNC(math_selu);
+N8_FUNC(math_softmax);
+N8_FUNC(math_swish);
+N8_FUNC(math_mish);
+N8_FUNC(math_hardSigmoid);
+N8_FUNC(math_hardTan);
+N8_FUNC(math_softplus);
+N8_FUNC(math_softsign);
+N8_FUNC(math_gaussian);
+N8_FUNC(math_bentIdentity);
+N8_FUNC(math_logLogistic);
+
+N8_LIB_END
+
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif
+
+#endif
diff --git a/std/n8std/Reflect.cc b/std/n8std/Reflect.cc
new file mode 100644
index 0000000..1c73f67
--- /dev/null
+++ b/std/n8std/Reflect.cc
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2024 - Nathanne Isip
+ * This file is part of N8.
+ *
+ * N8 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * N8 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with N8. If not, see .
+ */
+
+#include "n8std/Reflect.hpp"
+
+#include
+#include
+
+N8_FUNC(reflect_get) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject name = args.at(0);
+ const std::string symName = name.toString();
+
+ return symtab.getSymbol(
+ std::move(address),
+ symName
+ );
+}
+
+N8_FUNC(reflect_has) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject name = args.at(0);
+ const std::string symName = name.toString();
+
+ return DynamicObject(symtab.hasSymbol(symName));
+}
+
+N8_FUNC(reflect_type) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject name = args.at(0);
+ const std::string symName = name.toString();
+
+ return symtab.getSymbol(
+ std::move(address),
+ symName
+ ).objectType();
+}
+
+N8_FUNC(reflect_declare) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 2 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject name = args.at(0),
+ value = args.at(1);
+
+ std::string symName = name.toString();
+ if(Tokenizer::isValidIdentifier(symName))
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Invalid identifier string: " +
+ symName
+ );
+
+ symtab.setSymbol(symName, value);
+ return value;
+}
+
+N8_FUNC(reflect_delete) {
+ if(args.size() != 1)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 1 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject name = args.at(0);
+ symtab.removeSymbol(name.toString());
+
+ return DynamicObject();
+}
+
+N8_FUNC(reflect_invoke) {
+ if(args.size() != 2)
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Expecting 2 argument, got " +
+ std::to_string(args.size())
+ );
+
+ DynamicObject name = args.at(0),
+ params = args.at(1);
+
+ if(!params.isArray())
+ throw TerminativeThrowSignal(
+ std::move(address),
+ "Parameters must be of array type"
+ );
+
+ const std::string symName = name.toString();
+ DynamicObject callable = symtab.getSymbol(
+ std::move(address),
+ symName
+ );
+
+ return callable.callFromNative(
+ std::move(address),
+ symtab,
+ *params.getArray()
+ );
+}
diff --git a/std/n8std/Reflect.hpp b/std/n8std/Reflect.hpp
new file mode 100644
index 0000000..1259567
--- /dev/null
+++ b/std/n8std/Reflect.hpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2024 - Nathanne Isip
+ * This file is part of N8.
+ *
+ * N8 is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 3 of the License,
+ * or (at your option) any later version.
+ *
+ * N8 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with N8. If not, see .
+ */
+
+#ifndef N8_STDLIB_REFLECT_CC
+#define N8_STDLIB_REFLECT_CC
+
+#ifdef __clang__
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
+#endif
+
+#include "N8Library.hpp"
+
+N8_LIB_START
+
+N8_FUNC(reflect_get);
+N8_FUNC(reflect_has);
+N8_FUNC(reflect_type);
+
+N8_FUNC(reflect_declare);
+N8_FUNC(reflect_delete);
+N8_FUNC(reflect_invoke);
+
+N8_LIB_END
+
+#ifdef __clang__
+# pragma clang diagnostic pop
+#endif
+
+#endif