added an AngelScript log module

This commit is contained in:
faraphel 2024-08-22 12:51:24 +02:00
parent a5b4723ac1
commit d9ae04886f
15 changed files with 236 additions and 134 deletions

View file

@ -7,11 +7,28 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(Atlas-Launcher
source/main.cpp
# AngelScript
external/angelscript/add_on/scriptbuilder/scriptbuilder.cpp
external/angelscript/add_on/scriptstdstring/scriptstdstring.cpp
external/angelscript/add_on/scriptstdstring/scriptstdstring_utils.cpp
external/angelscript/add_on/datetime/datetime.cpp
external/angelscript/add_on/scriptany/scriptany.cpp
external/angelscript/add_on/scriptarray/scriptarray.cpp
external/angelscript/add_on/scriptgrid/scriptgrid.cpp
external/angelscript/add_on/scriptdictionary/scriptdictionary.cpp
external/angelscript/add_on/scripthandle/scripthandle.cpp
external/angelscript/add_on/weakref/weakref.cpp
external/angelscript/add_on/scriptmath/scriptmath.cpp
external/angelscript/add_on/scripthelper/scripthelper.cpp
# Source
source/main.cpp
source/script/module/debug/load.cpp
source/script/module/debug/load.hpp
source/script/module/debug/log.cpp
source/script/module/debug/log.hpp
source/script/engine/Engine.cpp
source/script/engine/Engine.hpp
)
target_include_directories(Atlas-Launcher PRIVATE
source/

View file

@ -1,17 +0,0 @@
#include "AtlasJsEngine.hpp"
AtlasJsEngine::AtlasJsEngine(QObject *parent) : QJSEngine(parent) {
// instanciate a new Atlas module
this->moduleAtlas = std::make_unique<AtlasJsModule>(this);
// convert it into a javascript object
const QJSValue jsModuleAtlas = this->newQObject(this->moduleAtlas.get());
// make it accessible as "atlas" in the javascript code
this->globalObject().setProperty("atlas", jsModuleAtlas);
}
vfs::VirtualFileSystem& AtlasJsEngine::getFileSystem() {
return this->fileSystem;
}

View file

@ -1,26 +0,0 @@
#pragma once
#include <QObject>
#include <QJSEngine>
#include <QTemporaryDir>
#include <VirtualFileSystem.hpp>
#include "javascript/module/AtlasJsModule.hpp"
/**
* This class represent a Qt JavaScript engine modified to support the Atlas framework.
*/
class AtlasJsEngine : public QJSEngine {
public:
explicit AtlasJsEngine(QObject* parent);
vfs::VirtualFileSystem& getFileSystem();
protected:
vfs::VirtualFileSystem fileSystem;
private:
std::shared_ptr<AtlasJsModule> moduleAtlas;
};

View file

@ -1,10 +0,0 @@
#include "DebugJsModule.hpp"
#include <QDebug>
DebugJsModule::DebugJsModule(AtlasJsEngine* engine) : BaseJsModule(engine) {}
void DebugJsModule::information(const QString& text) {
qDebug() << text;
}

View file

@ -1,19 +0,0 @@
#pragma once
#include "../_base/BaseJsModule.hpp"
/**
* This module implements useful feature to help with debugging
*/
class DebugJsModule : public BaseJsModule {
Q_OBJECT
public:
explicit DebugJsModule(AtlasJsEngine* engine);
/**
* Print an informational message
*/
Q_INVOKABLE static void information(const QString& text);
};

View file

@ -4,45 +4,35 @@
#include <vfspp/VirtualFileSystem.hpp>
#include <vfspp/MemoryFileSystem.hpp>
#include <angelscript.h>
#include <scriptstdstring/scriptstdstring.h>
#include <scriptbuilder/scriptbuilder.h>
void print(const std::string& in) {
std::cout << in;
}
#include "script/engine/Engine.hpp"
#include "script/module/debug/load.hpp"
int main(int argc, char* argv[]) {
int error;
// prepare a virtual file system
auto fileSystem = std::make_unique<vfspp::VirtualFileSystem>();
auto fileSystemTmp = std::make_shared<vfspp::MemoryFileSystem>();
fileSystemTmp->Initialize();
fileSystem->AddFileSystem("/tmp", fileSystemTmp);
// engine
asIScriptEngine* engine = asCreateScriptEngine();
if (engine == nullptr)
throw std::runtime_error("Could not create the AngelScript Engine.");
RegisterStdString(engine);
const auto atlasEngine = std::make_unique<atlas::script::engine::Engine>();
auto* asEngine = atlasEngine->getAsEngine();
// functions
error = engine->RegisterGlobalFunction("void print(const string& in)", asFUNCTION(print), asCALL_CDECL);
if (error < 0)
throw std::runtime_error("Could not register the print function.");
atlas::script::module::debug::load(atlasEngine.get());
// script
CScriptBuilder builder;
error = builder.StartNewModule(engine, "script");
error = builder.StartNewModule(asEngine, "script");
if (error < 0)
throw std::runtime_error("Could not start a new module.");
error = builder.AddSectionFromMemory("script", "void main() { print(\"hello world !\"); }");
error = builder.AddSectionFromMemory("script", R"(
void main() {
array<int> data(256);
atlas::debug::log("main", "hello world !");
}
)");
if (error < 0)
throw std::runtime_error("Could not add a section to the module.");
@ -51,7 +41,7 @@ int main(int argc, char* argv[]) {
throw std::runtime_error("Could not build the module.");
// execution
asIScriptModule *module = engine->GetModule("script");
asIScriptModule *module = asEngine->GetModule("script");
if (module == nullptr)
throw std::runtime_error("Could not get the module.");
@ -59,7 +49,7 @@ int main(int argc, char* argv[]) {
if (function == nullptr)
throw std::runtime_error("Could not get the main function.");
asIScriptContext *context = engine->CreateContext();
asIScriptContext *context = asEngine->CreateContext();
if (context == nullptr)
throw std::runtime_error("Could not create the context.");
@ -71,7 +61,6 @@ int main(int argc, char* argv[]) {
// clean up
context->Release();
engine->Release();
return error;
}

View file

@ -0,0 +1,91 @@
#include "Engine.hpp"
#include <angelscript.h>
#include <format>
#include <stdexcept>
#include <datetime/datetime.h>
#include <scriptany/scriptany.h>
#include <scriptstdstring/scriptstdstring.h>
#include <scriptarray/scriptarray.h>
#include <scriptdictionary/scriptdictionary.h>
#include <scriptgrid/scriptgrid.h>
#include <scripthandle/scripthandle.h>
#include <scripthelper/scripthelper.h>
#include <scriptmath/scriptmath.h>
#include <vfspp/MemoryFileSystem.hpp>
#include <weakref/weakref.h>
namespace atlas::script::engine {
Engine::Engine() {
// create a new AngelScript engine
this->asEngine = asCreateScriptEngine();
if (this->asEngine == nullptr)
throw std::runtime_error("Could not create the AngelScript Engine.");
this->asEngine->SetMessageCallback(asFUNCTION(this->asCallback), nullptr, asCALL_CDECL);
// AngelScript standard library
RegisterScriptArray(this->asEngine, true);
RegisterScriptGrid(this->asEngine);
RegisterStdString(this->asEngine);
RegisterStdStringUtils(this->asEngine);
RegisterScriptDictionary(this->asEngine);
RegisterScriptDateTime(this->asEngine);
RegisterScriptAny(this->asEngine);
RegisterScriptHandle(this->asEngine);
RegisterScriptWeakRef(this->asEngine);
RegisterExceptionRoutines(this->asEngine);
RegisterScriptMath(this->asEngine);
// initialise the file system
this->fileSystem = std::make_unique<vfspp::VirtualFileSystem>();
// TODO(Faraphel): is the memory fs
auto memoryFileSystem = std::make_unique<vfspp::MemoryFileSystem>();
memoryFileSystem->Initialize();
this->fileSystem->AddFileSystem("/tmp", std::move(memoryFileSystem));
}
void Engine::asCallback(const asSMessageInfo *message, void *args) {
std::string type = "UNKNOWN";
std::ostream* output = &std::cout;
// get a representation for the message type
switch (message->type) {
case asMSGTYPE_INFORMATION:
type = "INFO";
output = &std::cout;
case asMSGTYPE_WARNING:
type = "WARN";
output = &std::cerr;
case asMSGTYPE_ERROR:
type = "ERROR";
output = &std::cerr;
}
// display the message
*output << std::format(
"{} ({}, {}) [{}] {}",
message->section,
message->row,
message->col,
type,
message->message
) << std::endl;
}
Engine::~Engine() {
// release the engine
this->asEngine->ShutDownAndRelease();
}
asIScriptEngine *Engine::getAsEngine() const {
return this->asEngine;
}
}

View file

@ -0,0 +1,36 @@
#pragma once
#include <angelscript.h>
#include <vfspp/VirtualFileSystem.hpp>
namespace atlas::script::engine {
/**
* @brief The Atlas script engine
* @details a wrapper around the AngelScript engine
*/
class Engine {
public:
explicit Engine();
~Engine();
/**
* The AngelScript message handler
* @param message an AngelScript message
* @param args additionnal arguments
*/
static void asCallback(const asSMessageInfo *message, void *args);
/**
* get the AngelScript engine
* @return the AngelScript engine
*/
[[nodiscard]] asIScriptEngine* getAsEngine() const;
private:
asIScriptEngine* asEngine;
std::unique_ptr<vfspp::VirtualFileSystem> fileSystem;
};
}

View file

@ -0,0 +1,34 @@
#include "load.hpp"
#include <string>
#include "log.hpp"
namespace atlas::script::module::debug {
void load(const engine::Engine* atlasEngine) {
asIScriptEngine* asEngine = atlasEngine->getAsEngine();
int error;
// start namespace
error = asEngine->SetDefaultNamespace("atlas::debug");
if (error < 0)
throw std::runtime_error("Could not enter the \"atlas::debug\" namespace.");
// functions
error = asEngine->RegisterGlobalFunction(
"void log(const string& in, const string& in)",
asFUNCTION(log),
asCALL_CDECL
);
if (error < 0)
throw std::runtime_error("Could not register the \"load\" function.");
// end namespace
error = asEngine->SetDefaultNamespace("");
if (error < 0)
throw std::runtime_error("Could not reset the namespace.");
}
}

View file

@ -0,0 +1,10 @@
#pragma once
#include "script/engine/Engine.hpp"
namespace atlas::script::module::debug {
void load(const engine::Engine* atlasEngine);
}

View file

@ -0,0 +1,22 @@
#include "log.hpp"
#include <chrono>
#include <iostream>
namespace atlas::script::module::debug {
void log(const std::string& category, const std::string& message) {
// get the current time
auto now = std::chrono::system_clock::now();
// display it into the standard output
std::cout << std::format(
"[{:%Y-%m-%dT%H:%M:%S}] ({}) {}",
now,
category,
message
) << std::endl;
}
}

View file

@ -0,0 +1,10 @@
#pragma once
#include <string>
namespace atlas::script::module::debug {
void log(const std::string& category, const std::string& message);
}

View file

@ -1,24 +0,0 @@
#include "fileOpenMode.hpp"
QIODevice::OpenMode fileModeFromString(const QString& modeString) {
QIODevice::OpenMode modeFlags = QIODevice::NotOpen;
// if the mode don't contains a "b", set the text mode
if (!modeString.contains("b"))
modeFlags |= QIODevice::Text;
// if the mode contains a "r", set the read mode
if (modeString.contains("r"))
modeFlags |= QIODevice::ReadOnly;
// if the mode contains a "w", set the write mode
if (modeString.contains("w"))
modeFlags |= QIODevice::WriteOnly;
// if the mode contains a "a", set the append mode
if (modeString.contains("a"))
modeFlags |= QIODevice::Append;
return modeFlags;
}

View file

@ -1,11 +0,0 @@
#pragma once
#include <QIODevice>
/**
* convert a string representing a file mode to the corresponding Qt flags.
* @param modeString the mode as a string
* @return the mode as a flag
*/
QIODevice::OpenMode fileModeFromString(const QString& modeString);