#ifndef SCRIPT_FUNCTION_HPP #define SCRIPT_FUNCTION_HPP #include #include #include #include #include "ScriptExceptionMacros.h" #include "ScriptInterpreterHelpers.hpp" #include "Token.hpp" #include "Value.hpp" class ScriptInterpreter; using CallbackFunction = std::function &)>; using CallBackStorage = std::unordered_map; class BaseFunction { protected: std::string name; CallBackStorage functionMap; public: BaseFunction(const std::string & functionName) : name(functionName) {} virtual void addFunction(const std::string & name, std::function &)> callback) { functionMap[name] = std::move(callback); } virtual void validate(const std::vector & tokens, size_t & i, const std::unordered_map & variables) { size_t index = i; if (tokens[index].type != TokenType::Identifier) { THROW_UNEXPECTED_TOKEN_ERROR(tokens[index], "identifier"); } index++; // skip function name if (tokens[index].type != TokenType::LeftParenthesis) { THROW_UNEXPECTED_TOKEN_ERROR(tokens[index], "("); } index++; // skip '(' std::vector args; while (tokens[index].type != TokenType::RightParenthesis) { if (tokens[index].type == TokenType::Comma) { index++; continue; } if (tokens[index].type == TokenType::Variable && !variables.contains(tokens[index].lexeme)) { THROW_UNDEFINED_VARIABLE_ERROR(tokens[index].lexeme, tokens[index]); } args.push_back(tokens[index]); index++; } index++; // skip ')' if (tokens[index].type != TokenType::Semicolon) { THROW_UNEXPECTED_TOKEN_ERROR(tokens[index], ";"); } this->validateArgs(args, variables); ScriptInterpreterHelpers::expectSemicolon(tokens, index, "function call"); } virtual void validateArgs(const std::vector & args, const std::unordered_map & variables) = 0; virtual Value call(const std::vector & args, bool debug = false) const = 0; template void registerFunctionTo(ScriptInterpreter & interp) { FuncClass::registerTo(interp); } }; #endif // SCRIPT_FUNCTION_HPP