/****************************************************************************** * File - wren_state.cpp * Author - Joey Pollack * Date - 2022/10/25 (y/m/d) * Mod Date - 2022/10/25 (y/m/d) * Description - Manages the wren vm, runs scripts. This is the main * interface for wren. ******************************************************************************/ #include "wren_state.h" #include "wren_script.h" #include "coreAPI.h" #include #include namespace lunarium { std::vector WrenState::mFMBinders; WrenState::~WrenState() { Shutdown(); } void WrenState::Shutdown() { wrenFreeVM(mpVM); mpVM = nullptr; } u32 WrenState::mLogCat = Logger::RegisterCategory("SCRIPT"); OpRes WrenState::Initialize() { WrenConfiguration config; wrenInitConfiguration(&config); config.writeFn = WrenState::WriteFN; config.errorFn = WrenState::ErrorFN; config.bindForeignMethodFn = WrenState::BindForeignMethodFN; mpVM = wrenNewVM(&config); CoreAPI::GetInstance().Initialize(*this); return OpRes::OK(); } u32 WrenState::GetLogCat() const { return mLogCat; } void WrenState::RegisterForeignMethodBinder(FMBinder* binder_method) { mFMBinders.push_back(binder_method); } ///////////////////////////////////////////////////////////////////// // HANDLES ///////////////////////////////////////////////////////////////////// WrenHandle* WrenState::GetWrenClassHandle(std::string from_module, std::string class_name) { // Load the class into slot 0. wrenEnsureSlots(mpVM, 1); wrenGetVariable(mpVM, from_module.c_str(), class_name.c_str(), 0); WrenHandle* handle = wrenGetSlotHandle(mpVM, 0); return handle; } WrenHandle* WrenState::GetWrenMethodHandle(std::string method_signature) { WrenHandle* handle = wrenMakeCallHandle(mpVM, method_signature.c_str()); return handle; } void WrenState::CallWrenMethod(WrenHandle* method, WrenHandle* receiver, std::vector params, std::string name_tag) { wrenEnsureSlots(mpVM, params.size() + 1); for (int i = 0; i < params.size(); i++) { switch (params[i].Type) { case WrenParamType::WPT_DOUBLE: wrenSetSlotDouble(mpVM, i + 1, params[i].As.Double); break; case WrenParamType::WPT_BOOL: wrenSetSlotBool(mpVM, i + 1, params[i].As.Bool); break; case WrenParamType::WPT_STR: wrenSetSlotString(mpVM, i + 1, params[i].As.String); break; default: Logger::Warn(mLogCat, "Unknown wren parameter type: %d", (int)params[i].Type); } } wrenSetSlotHandle(mpVM, 0, receiver); WrenInterpretResult result = wrenCall(mpVM, method); switch (result) { case WREN_RESULT_COMPILE_ERROR: Logger::Trace(mLogCat, "Call compile error in module: %s", name_tag.c_str()); break; case WREN_RESULT_RUNTIME_ERROR: Logger::Trace(mLogCat, "Call runtime error in module: %s", name_tag.c_str()); break; case WREN_RESULT_SUCCESS: Logger::Trace(mLogCat, "Call %s run successfully", name_tag.c_str()); break; } } void WrenState::ReleaseWrenHandle(WrenHandle* handle) { wrenReleaseHandle(mpVM, handle); } ///////////////////////////////////////////////////////////////////// // CODE PROCESSING ///////////////////////////////////////////////////////////////////// void WrenState::RunScript(WrenScript* script) { if (!mpVM) { Logger::Error(mLogCat, "Could not run script - the VM is nullptr"); return; } WrenInterpretResult result = wrenInterpret(mpVM, script->GetModuleName().c_str(), script->GetScriptCode().c_str()); switch (result) { case WREN_RESULT_COMPILE_ERROR: Logger::Trace(mLogCat, "Script compile error in module: %s", script->GetModuleName().c_str()); break; case WREN_RESULT_RUNTIME_ERROR: Logger::Trace(mLogCat, "Script runtime error in module: %s", script->GetModuleName().c_str()); break; case WREN_RESULT_SUCCESS: Logger::Trace(mLogCat, "Script %s run successfully", script->GetModuleName().c_str()); break; } } void WrenState::RunSnippet(std::string name, std::string code) { if (!mpVM) { Logger::Error(mLogCat, "Could not run script - the VM is nullptr"); return; } WrenInterpretResult result = wrenInterpret(mpVM, name.c_str(), code.c_str()); switch (result) { case WREN_RESULT_COMPILE_ERROR: Logger::Trace(mLogCat, "Snippet compile error in module: %s", name.c_str()); break; case WREN_RESULT_RUNTIME_ERROR: Logger::Trace(mLogCat, "Snippet runtime error in module: %s", name.c_str()); break; case WREN_RESULT_SUCCESS: Logger::Trace(mLogCat, "Snippet %s run successfully", name.c_str()); break; } } ///////////////////////////////////////////////////////////////////// // VM CALLBACK METHODS ///////////////////////////////////////////////////////////////////// void WrenState::WriteFN(WrenVM* vm, const char* text) { std::string final = String::TrimEnd(text, "\n"); if (final.size() < 1) return; Logger::Info(mLogCat, final.c_str()); } void WrenState::ErrorFN(WrenVM* vm, WrenErrorType type, const char* module, int line, const char* message) { switch (type) { case WREN_ERROR_COMPILE: Logger::Error(mLogCat, "Script compile error: [%s line %d] %s\n", module, line, message); break; case WREN_ERROR_STACK_TRACE: Logger::Error(mLogCat, "[%s line %d] in %s\n", module, line, message); break; case WREN_ERROR_RUNTIME: Logger::Error(mLogCat, "Script Runtime Error: %s\n", message); break; } } WrenForeignMethodFn WrenState::BindForeignMethodFN(WrenVM* vm, const char* module, const char* className, bool isStatic, const char* signature) { // Bind methods // If method not recognized, call any registered FMBinder methods for (auto iter = mFMBinders.begin(); iter != mFMBinders.end(); iter++) { auto FN = ((FMBinder)(*iter))(vm, module, className, isStatic, signature); if (FN) { return FN; } } Logger::Error(mLogCat, "Failed to bind foreign method: %s::%s", className, signature); return nullptr; } }