#include "run_as.h" #include "angelscript/scriptsatdump/dump_predef.h" #include "logger.h" #include "angelscript/angelscript.h" #include "angelscript/scriptarray/scriptarray.h" #include "angelscript/scriptbuilder/scriptbuilder.h" #include "angelscript/scriptstdstring/scriptstdstring.h" #include "angelscript/scriptsatdump/bind_satdump.h" #include "nlohmann/json.hpp" #include // TODOREWORK, this is all temporary namespace satdump { struct JSONDiags { bool lint; int ndiags = 0; nlohmann::json all_diags; }; // Implement a simple message callback function void MessageCallback(const asSMessageInfo *msg, void *param) { JSONDiags *p = (JSONDiags *)param; if (p->lint) { nlohmann::json l; l["type"] = "error"; if (msg->type == asMSGTYPE_WARNING) l["type"] = "warn"; else if (msg->type == asMSGTYPE_INFORMATION) l["type"] = "info"; l["file"] = msg->section; l["line"] = msg->row; l["col"] = msg->col; l["msg"] = msg->message; p->all_diags["diags"][p->ndiags++] = l; } else { const char *type = "ERR"; if (msg->type == asMSGTYPE_WARNING) type = "WARN"; else if (msg->type == asMSGTYPE_INFORMATION) type = "INFO"; // printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message); if (msg->type == asMSGTYPE_INFORMATION) logger->info("[AngelScript] %s (%d, %d) : %s : %s", msg->section, msg->row, msg->col, type, msg->message); else if (msg->type == asMSGTYPE_WARNING) logger->warn("[AngelScript] %s (%d, %d) : %s : %s", msg->section, msg->row, msg->col, type, msg->message); else if (msg->type == asMSGTYPE_ERROR) logger->error("[AngelScript] %s (%d, %d) : %s : %s", msg->section, msg->row, msg->col, type, msg->message); } } namespace namelog { void trace(std::string &f) { logger->trace("[AngelScript] " + f); } void debug(std::string &f) { logger->debug("[AngelScript] " + f); } void info(std::string &f) { logger->info("[AngelScript] " + f); } void warn(std::string &f) { logger->warn("[AngelScript] " + f); } void error(std::string &f) { logger->error("[AngelScript] " + f); } void critical(std::string &f) { logger->critical("[AngelScript] " + f); } } // namespace namelog int runAngelScript(std::string file, bool lint, bool predef) { // Create the script engine asIScriptEngine *engine = asCreateScriptEngine(); // Set the message callback to receive information on errors in human readable form. JSONDiags diags; diags.lint = lint; diags.all_diags["file"] = file; int r = engine->SetMessageCallback(asFUNCTION(MessageCallback), &diags, asCALL_CDECL); // AngelScript doesn't have a built-in string type, as there is no definite standard // string type for C++ applications. Every developer is free to register its own string type. // The SDK do however provide a standard add-on for registering a string type, so it's not // necessary to implement the registration yourself if you don't want to. RegisterStdString(engine); RegisterScriptArray(engine, true); satdump::script::registerAll(engine); // Register logger engine->SetDefaultNamespace("logger"); engine->RegisterGlobalFunction("void trace(const string &in)", asFUNCTION(namelog::trace), asCALL_CDECL); engine->RegisterGlobalFunction("void debug(const string &in)", asFUNCTION(namelog::debug), asCALL_CDECL); engine->RegisterGlobalFunction("void info(const string &in)", asFUNCTION(namelog::info), asCALL_CDECL); engine->RegisterGlobalFunction("void warn(const string &in)", asFUNCTION(namelog::error), asCALL_CDECL); engine->RegisterGlobalFunction("void error(const string &in)", asFUNCTION(namelog::error), asCALL_CDECL); engine->RegisterGlobalFunction("void critical(const string &in)", asFUNCTION(namelog::critical), asCALL_CDECL); if (predef) script::GenerateScriptPredefined(engine, "../as.predefined"); // The CScriptBuilder helper is an add-on that loads the file, // performs a pre-processing pass if necessary, and then tells // the engine to build a script module. CScriptBuilder builder; r = builder.StartNewModule(engine, "MyModule"); if (r < 0) { // If the code fails here it is usually because there // is no more memory to allocate the module if (!lint) { printf("Unrecoverable error while starting a new module.\n"); return 1; } } r = builder.AddSectionFromFile(file.c_str()); if (r < 0) { // The builder wasn't able to load the file. Maybe the file // has been removed, or the wrong name was given, or some // preprocessing commands are incorrectly written. if (!lint) { printf("Please correct the errors in the script and try again.\n"); return 1; } } r = builder.BuildModule(); if (r < 0) { // An error occurred. Instruct the script writer to fix the // compilation errors that were listed in the output stream. if (!lint) { printf("Please correct the errors in the script and try again.\n"); return 1; } } ////////////// if (lint) { printf("%s\n", diags.all_diags.dump(4).c_str()); return 0; } // Find the function that is to be called. asIScriptModule *mod = engine->GetModule("MyModule"); asIScriptFunction *func = mod->GetFunctionByDecl("void main()"); if (func == 0) { // The function couldn't be found. Instruct the script writer // to include the expected function in the script. printf("The script must have the function 'void main()'. Please add it and try again.\n"); return 1; } // Create our context, prepare it, and then execute asIScriptContext *ctx = engine->CreateContext(); ctx->Prepare(func); r = ctx->Execute(); if (r != asEXECUTION_FINISHED) { // The execution didn't complete as expected. Determine what happened. if (r == asEXECUTION_EXCEPTION) { // An exception occurred, let the script writer know what happened so it can be corrected. printf("An exception '%s' occurred. Please correct the code and try again.\n", ctx->GetExceptionString()); } } // Clean up ctx->Release(); engine->ShutDownAndRelease(); return 0; } } // namespace satdump