Compare commits

...

8 Commits
master ... dev

  1. 9
      .gitignore
  2. 31
      CMakeLists.txt
  3. 4
      includes/kst/disnomia.hpp
  4. 2
      includes/kst/dsn/dsn.hpp
  5. 2
      includes/kst/dsn/lib/lua.hpp
  6. 4
      includes/kst/dsn/lua.hpp
  7. 126
      includes/kst/dsn/state.hpp
  8. 254
      includes/kst/dsn/states/base.hpp
  9. 92
      includes/kst/dsn/states/context.hpp
  10. 68
      includes/kst/dsn/states/state.hpp
  11. 11
      includes/kst/dsn/status.hpp
  12. 150
      includes/kst/dsn/types.hpp
  13. 61
      includes/kst/dsn/types/base_type.hpp
  14. 27
      includes/kst/dsn/types/concepts/cpp.hpp
  15. 61
      includes/kst/dsn/types/concepts/dsn.hpp
  16. 13
      includes/kst/dsn/types/concepts/functions.hpp
  17. 33
      includes/kst/dsn/types/function.hpp
  18. 31
      includes/kst/dsn/types/table.hpp
  19. 16
      includes/kst/dsn/types/type_names.hpp
  20. 39
      includes/kst/dsn/types/types.hpp
  21. 324
      includes/kst/dsn/types/value.hpp
  22. 11
      tests/01_state/CMakeLists.txt
  23. 14
      tests/01_state/main.cpp
  24. 12
      tests/02_file/CMakeLists.txt
  25. 13
      tests/02_file/main.cpp
  26. 1
      tests/02_file/main.lua
  27. 10
      tests/04_reference/CMakeLists.txt
  28. 24
      tests/04_reference/main.cpp
  29. 10
      tests/05_table/CMakeLists.txt
  30. 26
      tests/05_table/main.cpp
  31. 10
      tests/06_functions/CMakeLists.txt
  32. 42
      tests/06_functions/main.cpp
  33. 13
      tests/CMakeLists.txt

9
.gitignore vendored

@ -0,0 +1,9 @@
.idea/
cmake-build-debug/
*.make
*.cmake
CMakeFiles
*.cbp
Makefile
DartConfiguration.tcl
Testing

31
CMakeLists.txt

@ -1,22 +1,35 @@
cmake_minimum_required(VERSION 3.20)
set(CMAKE_CXX_STANDARD 20)
project(kst_disnomia)
project(kst_dsn)
include(CTest)
enable_testing()
find_package(Lua 5.3 REQUIRED)
add_library(
${PROJECT_NAME}
includes/kst/dsn/lua.hpp
includes/kst/disnomia.hpp
includes/kst/dsn/types.hpp
includes/kst/dsn/status.hpp
includes/kst/dsn/state.hpp
${PROJECT_NAME} INTERFACE
includes/kst/dsn/lib/lua.hpp
includes/kst/dsn/dsn.hpp
includes/kst/dsn/types/types.hpp
includes/kst/dsn/states/state.hpp
includes/kst/dsn/states/base.hpp
includes/kst/dsn/states/context.hpp
includes/kst/dsn/types/value.hpp
includes/kst/dsn/types/base_type.hpp
includes/kst/dsn/types/concepts/dsn.hpp
includes/kst/dsn/types/concepts/cpp.hpp
includes/kst/dsn/types/table.hpp
includes/kst/dsn/types/type_names.hpp
includes/kst/dsn/types/concepts/functions.hpp
includes/kst/dsn/types/function.hpp
)
set_target_properties(${PROJECT_NAME} PROPERTIES LINKER_LANGUAGE CXX)
target_include_directories(${PROJECT_NAME} PUBLIC includes/)
target_include_directories(${PROJECT_NAME} INTERFACE includes/)
target_link_libraries(${PROJECT_NAME} INTERFACE lua)
target_link_libraries(${PROJECT_NAME} lua)
add_subdirectory(tests)

4
includes/kst/disnomia.hpp

@ -1,4 +0,0 @@
#ifndef KST_DISNOMIA_HPP
#define KST_DISNOMIA_HPP
#include "dsn/state.hpp"
#endif //KST_DISNOMIA_HPP

2
includes/kst/dsn/dsn.hpp

@ -0,0 +1,2 @@
#pragma once
#include <kst/dsn/states/state.hpp>

2
includes/kst/dsn/lib/lua.hpp

@ -0,0 +1,2 @@
#pragma once
#include <lua5.3/lua.hpp>

4
includes/kst/dsn/lua.hpp

@ -1,4 +0,0 @@
#ifndef KST_DISNOMIA_LUA_HPP
#define KST_DISNOMIA_LUA_HPP
#include <lua5.3/lua.hpp>
#endif //KST_DISNOMIA_LUA_HPP

126
includes/kst/dsn/state.hpp

@ -1,126 +0,0 @@
#ifndef KST_DISNOMIA_STATE_HPP
#define KST_DISNOMIA_STATE_HPP
#include "kst/dsn/states/base.hpp"
#include "kst/dsn/states/context.hpp"
#include "kst/dsn/status.hpp"
namespace kst::dsn {
class state : public states::base {
using DisnomiaFunction = void (*)();
using DisnomiaCtxFunction = void (*)(states::context&);
template<types::any::Type...ATypes>
using DisnomiaAnyArgsFunction = void (*)(ATypes...);
template<types::any::Type...ATypes>
using DisnomiaAnyCtxArgsFunction = void (*)(states::context&, ATypes...);
public:
state()
:states::base(luaL_newstate()) {
luaL_openlibs(_state);
}
~state() {
lua_close(_state);
}
public:
auto load_file(char const* filename) {
auto status = luaL_loadfile(_state, filename);
if (status==LUA_OK)
return dsn::status::okay;
return dsn::status::error;
}
auto run_file(char const* filename) {
auto status = luaL_dofile(_state, filename);
if (status==LUA_OK)
return dsn::status::okay;
return dsn::status::error;
}
auto get_error() {
auto message = lua_tostring(_state, -1);
lua_pop(_state, 1);
return message;
}
auto call() {
auto status = lua_pcall(_state, 0, LUA_MULTRET, 0);
if (status==LUA_OK)
return dsn::status::okay;
return dsn::status::error;
}
auto register_function(const char* name, DisnomiaFunction function) {
lua_pushlightuserdata(_state, reinterpret_cast<void*>(function));
lua_pushcclosure(_state, [](lua_State* s) -> int
{
auto ctx = states::context(s, 0);
auto fn = ctx.get_closure<DisnomiaFunction>();
fn();
return 0;
}, 1);
lua_setglobal(_state, name);
}
auto register_function(const char* name, DisnomiaCtxFunction function) {
lua_pushlightuserdata(_state, reinterpret_cast<void*>(function));
lua_pushcclosure(_state, [](lua_State* s) -> int
{
auto ctx = states::context(s, 0);
auto fn = ctx.get_closure<DisnomiaCtxFunction>();
fn(ctx);
return ctx.get_return_argc();
}, 1);
lua_setglobal(_state, name);
}
template<types::any::Type...Args>
auto register_function(const char* name, DisnomiaAnyArgsFunction<Args...> function) {
lua_pushlightuserdata(_state, reinterpret_cast<void*>(function));
lua_pushcclosure(_state, [](lua_State* s) -> int
{
auto ctx = states::context(s, sizeof...(Args));
if (auto error = ctx.validate_argc())
{
return error;
}
int argc = 0;
(ctx.validate_type<Args>(++argc), ...);
argc = sizeof...(Args);
auto fn = ctx.get_closure<DisnomiaAnyArgsFunction<Args...>>();
fn(ctx.get_type<Args>(argc--)...);
return 0;
}, 1);
lua_setglobal(_state, name);
}
template<types::any::Type...Args>
auto register_function(const char* name, DisnomiaAnyCtxArgsFunction<Args...> function) {
lua_pushlightuserdata(_state, reinterpret_cast<void*>(function));
lua_pushcclosure(_state, [](lua_State* s) -> int
{
auto ctx = states::context(s, sizeof...(Args));
if (auto error = ctx.validate_argc())
{
return error;
}
int argc = 0;
(ctx.validate_type<Args>(++argc), ...);
argc = sizeof...(Args);
auto fn = ctx.get_closure<DisnomiaAnyCtxArgsFunction<Args...>>();
fn(ctx, ctx.get_type<Args>(argc--)...);
if (auto error = ctx.get_error_c())
{
return error;
}
return ctx.get_return_argc();
}, 1);
lua_setglobal(_state, name);
}
};
}
#endif //KST_DISNOMIA_STATE_HPP

254
includes/kst/dsn/states/base.hpp

@ -1,135 +1,121 @@
#ifndef KST_DISNOMIA_STATES_BASE_HPP
#define KST_DISNOMIA_STATES_BASE_HPP
#include "../lua.hpp"
#include "../types.hpp"
namespace kst::dsn::states {
class base {
protected:
lua_State* _state;
explicit base(lua_State* state)
:_state(state) { }
public:
void push(bool x) {
lua_pushboolean(_state, x);
}
void push(std::integral auto x) {
lua_pushinteger(_state, lua_Integer(x));
}
void push(std::floating_point auto x) {
lua_pushnumber(_state, lua_Number(x));
}
void push(char const* x) {
lua_pushstring(_state, x);
}
template<typename...Args>
void push_args(Args...args) {
(push(args), ...);
}
template<types::Type T>
auto get_field(types::table& t, const char* key) {
lua_getfield(_state, t.value, key);
auto field = get_type<T>(-1);
return field;
}
template<types::Type T>
auto get_value(types::table& t, const char* key) {
lua_getfield(_state, t.value, key);
auto value = get_value<T>(-1);
return value;
}
template<types::Type T>
auto get_field(int index, const char* key) {
lua_getfield(_state, index, key);
auto field = get_type<T>(-1);
return field;
}
types::value get_any(int index) {
switch (lua_type(_state, index))
{
case LUA_TSTRING:
return types::string(lua_tostring(_state, index));
case LUA_TNUMBER:
if (lua_isinteger(_state, index))
return types::integer(lua_tointeger(_state, index));
return types::number(lua_tonumber(_state, index));
case LUA_TBOOLEAN:
return types::boolean(lua_toboolean(_state, index));
case LUA_TTABLE:
return types::table(index);
default:
return types::nil();
}
}
template<types::Type T>
auto get_value(const types::value& v) {
return std::get<T>(v).value;
}
template<types::any::String T>
auto get_type(int index) {
return T(lua_tostring(_state, index));
}
template<types::any::Boolean T>
auto get_type(int index) {
return T(lua_toboolean(_state, index));
}
template<types::Table T>
auto get_type(int index) {
return T(lua_absindex(_state, index));
}
template<types::any::Number T>
auto get_type(int index) {
return T(lua_tonumber(_state, index));
}
template<types::any::Integer T>
auto get_type(int index) {
return T(lua_tointeger(_state, index));
}
template<types::cpp::Integer T>
auto get_value(int index) {
return T(lua_tointeger(_state, index));
}
template<types::cpp::Number T>
auto get_value(int index) {
return T(lua_tonumber(_state, index));
}
template<types::cpp::String T>
auto get_value(int index) {
return T(lua_tostring(_state, index));
}
template<types::cpp::Boolean T>
auto get_value(int index) {
return T(lua_toboolean(_state, index));
}
template<types::Type T>
auto get_value(int index) {
return get_type<T>(index).value;
}
template<types::Type T>
auto get_type(const types::value& v) {
return std::get<T>(v);
}
};
#pragma once
#include <kst/dsn/lib/lua.hpp>
#include <kst/dsn/types/concepts/dsn.hpp>
#include <stdexcept>
namespace kst::dsn {
class table;
namespace states {
class base {
lua_State* _state{};
public:
base() = default;
explicit base(lua_State* state)
:_state(state) { }
operator lua_State*() {
return _state;
}
void push(table& t);
void push(function& f);
void push(types::cpp::Boolean auto x) {
lua_pushboolean(_state, x);
}
void push(nullptr_t) {
lua_pushnil(_state);
}
void push(bool v) {
lua_pushboolean(_state, v);
}
void push(nullptr_t&) {
lua_pushnil(_state);
}
void push(std::integral auto x) {
lua_pushinteger(_state, lua_Integer(x));
}
void push(std::floating_point auto x) {
lua_pushnumber(_state, lua_Number(x));
}
void push(const std::string& x) {
lua_pushstring(_state, x.c_str());
}
void push(const char* x) {
lua_pushstring(_state, x);
}
template<types::all::String T>
auto get(int index) {
return T(lua_tostring(_state, index));
}
template<types::all::Boolean T>
auto get(int index) {
return T(lua_toboolean(_state, index));
}
template<types::all::Number T>
auto get(int index) {
return T(lua_tonumber(_state, index));
}
template<types::all::Integer T>
auto get(int index) {
return T(lua_tointeger(_state, index));
}
auto get_error() {
auto message = lua_tostring(_state, -1);
lua_pop(_state, 1);
return message;
}
auto get_top() {
return lua_gettop(_state);
}
auto call(int argc) {
auto status = lua_pcall(_state, argc, LUA_MULTRET, 0);
if (status!=LUA_OK)
throw std::runtime_error(get_error());
}
auto eval(const std::string& script) {
luaL_dostring(_state, script.c_str());
};
void push_global(){
get_field(LUA_RIDX_GLOBALS,LUA_REGISTRYINDEX);
}
void get_global(variant_cpp& id){
push_global();
get_field(id,-1);
lua_remove(_state,-2);
}
void set_global(variant_cpp& id){
push_global();
lua_rotate(_state,-2,1);
set_field(id,-3);
lua_pop(_state,1);
}
void set_field(variant_cpp& v, int index);
void get_field(variant_cpp& v, int index);
void get_field(int field, int index);
};
}
}
#endif //KST_DISNOMIA_STATES_BASE_HPP

92
includes/kst/dsn/states/context.hpp

@ -1,30 +1,35 @@
#ifndef KST_DISNOMIA_STATES_CONTEXT_HPP
#define KST_DISNOMIA_STATES_CONTEXT_HPP
#pragma once
#include "base.hpp"
#include <array>
#include <kst/dsn/states/base.hpp>
#include <kst/dsn/types/concepts/dsn.hpp>
namespace kst::dsn::states {
class context : public states::base { ;
class context {
states::base _state;
int _argc;
int _return_argc = 0;
int _error_c = 0;
public:
explicit context(lua_State* state, int argc)
:base(state), _argc(argc) { }
:_state(state), _argc(argc) { }
template<typename T>
void return_arg(T arg) {
++_return_argc;
push(arg);
auto return_arg(T arg) {
_state.push(arg);
return ++_return_argc;
}
auto get_argc() {
return _argc;
template<typename T>
auto get(int index) {
return _state.get<T>(index);
}
auto validate_argc() {
if (_argc!=lua_gettop(_state))
return luaL_error(_state, "Disnomia: wrong number of arguments to function call: required %d", _argc);
return luaL_error(_state, "Disnomia: wrong number of arguments to function call: expected "+_argc);
return 0;
}
template<typename T>
@ -32,87 +37,34 @@ namespace kst::dsn::states {
return reinterpret_cast<T>(lua_touserdata(_state, lua_upvalueindex(index)));
}
template<typename...Args>
void return_args(Args...args) {
(return_arg(args), ...);
}
[[nodiscard]] auto get_return_argc() const {
return _return_argc;
};
template<types::any::String>
template<types::all::String>
auto validate_type(int index) {
if (!lua_isstring(_state, index))
_error_c = luaL_error(_state, "Disnomia -> wrong type: expected string");
}
template<types::Table>
auto validate_type(int index) {
if (!lua_istable(_state, index))
_error_c = luaL_error(_state, "Disnomia -> wrong type: expected table");
}
template<types::any::Number>
template<types::all::Number>
auto validate_type(int index) {
if (!lua_isnumber(_state, index))
_error_c = luaL_error(_state, "Disnomia -> wrong type: expected number");
}
template<types::any::Integer>
template<types::all::Integer>
auto validate_type(int index) {
if (!lua_isinteger(_state, index))
_error_c = luaL_error(_state, "Disnomia -> wrong type: expected integer");
}
template<types::any::Boolean>
template<types::all::Boolean>
auto validate_type(int index) {
if (!lua_isinteger(_state, index))
_error_c = luaL_error(_state, "Disnomia -> wrong type: expected boolean");
}
template<types::Type T>
template<types::Any T>
auto validate(int index) {
validate_type<T>(index);
return _error_c;
}
template<types::Type T>
auto get_opt_field(types::table& t, const char* key) {
if (!validate<types::table>(t.value))
{
lua_getfield(_state, t.value, key);
if (!validate<T>(-1))
return std::make_optional(get_type<T>(-1));
}
};
template<types::Type T>
auto get_opt_type(int index) {
if (!validate<T>(index))
return std::make_optional(get_type<T>(index));
};
template<types::Type T>
auto get_opt_value(types::table& t, const char* key) {
if (!validate<types::table>(t.value))
{
lua_getfield(_state, t.value, key);
if (!validate<T>(-1))
return std::make_optional(get_value<T>(-1));
}
};
template<types::Type T>
auto get_opt_value(int index) {
if (!validate<T>(index))
return std::make_optional(get_value<T>(index));
};
[[nodiscard]] auto get_error_c() const {
return _error_c;
}
};
}
#endif //KST_DISNOMIA_STATES_CONTEXT_HPP
}

68
includes/kst/dsn/states/state.hpp

@ -0,0 +1,68 @@
#ifndef KST_DISNOMIA_STATE_HPP
#define KST_DISNOMIA_STATE_HPP
#include <string>
#include <kst/dsn/states/base.hpp>
#include <kst/dsn/states/context.hpp>
#include <kst/dsn/types/value.hpp>
#include <stdexcept>
namespace kst::dsn {
class state {
private:
states::base _state;
public:
state()
:_state(luaL_newstate()) {
luaL_openlibs(_state);
}
public:
auto get_top() {
return _state.get_top();
}
auto load_file(char const* filename) {
auto status = luaL_loadfile(_state, filename);
if (status!=LUA_OK)
throw std::runtime_error(_state.get_error());
}
auto run_file(char const* filename) {
auto status = luaL_dofile(_state, filename);
if (status!=LUA_OK)
throw std::runtime_error(_state.get_error());
}
auto eval(const std::string& script) {
if (luaL_dostring(_state, script.c_str())==LUA_OK)
return value(_state).get(-1);
throw std::runtime_error(_state.get_error());
};
auto eval_file(const std::string& name) {
if (luaL_dofile(_state, name.c_str())==LUA_OK)
return value(_state).get(-1);
throw std::runtime_error(_state.get_error());
};
auto call() {
auto status = lua_pcall(_state, 0, LUA_MULTRET, 0);
if (status!=LUA_OK)
throw std::runtime_error(_state.get_error());
}
auto operator[](variant_cpp id) {
_state.get_global(id);
value v(_state);
v._name = id;
v.get(-1);
lua_pop(_state,-1);
return v;
}
};
}
#endif //KST_DISNOMIA_STATE_HPP

11
includes/kst/dsn/status.hpp

@ -1,11 +0,0 @@
#ifndef KST_DISNOMIA_STATUS_HPP
#define KST_DISNOMIA_STATUS_HPP
namespace kst::dsn {
enum class status {
okay,
error,
};
}
#endif //KST_DISNOMIA_STATUS_HPP

150
includes/kst/dsn/types.hpp

@ -1,150 +0,0 @@
#ifndef KST_DISNOMIA_TYPES_HPP
#define KST_DISNOMIA_TYPES_HPP
#include <variant>
#include <string>
#include <concepts>
namespace kst::dsn::types {
enum class type {
nil,
boolean,
number,
integer,
string,
function,
userdata,
thread,
table,
};
struct nil {
int value = 0;
static auto type() {
return types::type::nil;
}
};
struct boolean {
bool value;
explicit boolean(bool v)
:value(v) { }
static auto type() {
return types::type::boolean;
}
};
struct number {
double value;
explicit number(double v)
:value(v) { }
static auto type() {
return types::type::number;
}
};
struct integer {
int value;
explicit integer(int v)
:value(v) { }
static auto type() {
return types::type::integer;
}
};
struct string {
std::string value;
explicit string(const char* v)
:value(v) { }
static auto type() {
return types::type::string;
}
};
struct function {
static auto type() {
return types::type::function;
}
};
struct userdata {
static auto type() {
return types::type::userdata;
}
};
struct thread {
static auto type() {
return types::type::thread;
}
};
struct table {
int value;
explicit table(int value)
:value(value) { };
static auto type() {
return types::type::table;
}
};
template<typename T>
concept String = std::is_same<T, string>::value;
template<typename T>
concept Number = std::is_same<T, number>::value;
template<typename T>
concept Integer = std::is_same<T, integer>::value;
template<typename T>
concept Table = std::is_same<T, table>::value;
template<typename T>
concept Boolean = std::is_same<T, boolean>::value;
template<typename T>
concept Type = String<T> || Number<T> || Integer<T> || Boolean<T> || Table<T>;
namespace cpp {
template<typename T>
concept String = std::is_same<T, std::string>::value;
template<typename T>
concept Number = std::is_same<T, double>::value;
template<typename T>
concept Integer = std::is_same<T, int>::value;
template<typename T>
concept Boolean = std::is_same<T, bool>::value;
template<typename T>
concept Type = cpp::String<T> || cpp::Number<T> || cpp::Integer<T> || cpp::Boolean<T>;
}
namespace any {
template<typename T>
concept String = cpp::String<T> || String<T>;
template<typename T>
concept Integer = cpp::Integer<T> || Integer<T>;
template<typename T>
concept Number = cpp::Number<T> || Number<T>;
template<typename T>
concept Boolean = cpp::Boolean<T> || Boolean<T>;
template<typename T>
concept Type = cpp::Type<T> || Type<T>;
}
template<Type T>
auto& operator<<(std::ostream& os, const T& t) {
os << t.value;
return os;
}
using value = std::variant<nil, boolean, number, integer, string, function, userdata, thread, table>;
}
#endif //KST_DISNOMIA_TYPES_HPP

61
includes/kst/dsn/types/base_type.hpp

@ -0,0 +1,61 @@
#pragma once
#include <string>
#include <map>
#include <kst/dsn/lib/lua.hpp>
namespace kst::dsn {
class value;
namespace types {
template<typename CppType, const std::string* TypeName, typename SelfType>
class base_type {
protected:
CppType _value;
public:
constexpr static const std::string* type_name = TypeName;
explicit base_type(CppType value)
: _value{ value } { }
operator CppType() {
return _value;
}
auto operator<=>(SelfType v) {
if constexpr(std::is_same_v<CppType, nullptr_t> || std::is_same_v<CppType, lua_CFunction>)
return std::partial_ordering::equivalent;
else if constexpr (std::is_same_v<std::map<value,value>,CppType>)
return std::partial_ordering::equivalent;
else
return _value<=>v._value;
}
auto operator==(types::cpp::Any auto& v) {
if constexpr(std::is_convertible_v<typeof(v), CppType> && !std::is_null_pointer_v<typeof(v)>
&& !std::is_same_v<bool, CppType>)
return _value==v;
return false;
}
auto operator==(const SelfType& v) {
return _value==v._value;
}
auto operator==(const CppType& v) {
return _value==v;
}
auto operator==(SelfType& v) {
return _value==v._value;
}
auto operator==(CppType& v) {
return _value==v;
}
friend std::ostream& operator<<(std::ostream& output, const SelfType& v) {
return output << v._value;
}
friend class dsn::value;
};
}
}

27
includes/kst/dsn/types/concepts/cpp.hpp

@ -0,0 +1,27 @@
#pragma once
#include <concepts>
#include <string>
namespace kst::dsn::types::cpp {
template<typename T>
concept String = std::is_same_v<T, std::string> || std::is_same_v<T, const char*>;
template<typename T>
concept Number = std::floating_point<T>;
template<typename T>
concept Integer = std::integral<T>;
template<typename T>
concept Boolean = std::is_same_v<T, bool>;
template<typename T>
concept Function = std::is_function_v<T>;
template<typename T>
concept Null = std::is_void_v<T> || std::is_null_pointer_v<T>;
template<typename T>
concept Any = cpp::String<T> || cpp::Number<T> || cpp::Integer<T> || cpp::Boolean<T> || cpp::Function<T>
|| cpp::Null<T>;
}

61
includes/kst/dsn/types/concepts/dsn.hpp

@ -0,0 +1,61 @@
#pragma once
#include <concepts>
#include <variant>
#include <kst/dsn/types/concepts/cpp.hpp>
namespace kst::dsn {
class string;
class number;
class integer;
class boolean;
class table;
class nil;
class function;
using variant_t = std::variant<nil, boolean, number, integer, string, table, function>;
using variant_cpp = std::variant<bool, LUA_NUMBER, LUA_INTEGER, std::string>;
namespace types {
template<typename T>
concept String = std::is_same<T, string>::value;
template<typename T>
concept Number = std::is_same<T, number>::value;
template<typename T>
concept Integer = std::is_same<T, integer>::value;
template<typename T>
concept Boolean = std::is_same<T, boolean>::value;
template<typename T>
concept Table = std::is_same<T, table>::value;
template<typename T>
concept Null = std::is_same<T, nil>::value;
template<typename T>
concept Function = std::is_same<T, function>::value;
template<typename T>
concept Any = String<T> || Number<T> || Integer<T> || Boolean<T> || Table<T> || Null<T> || Function<T>;
namespace all {
template<typename T>
concept String = cpp::String<T> || String<T>;
template<typename T>
concept Integer = cpp::Integer<T> || Integer<T>;
template<typename T>
concept Number = cpp::Number<T> || Number<T>;
template<typename T>
concept Boolean = cpp::Boolean<T> || Boolean<T>;
template<typename T>
concept Any = cpp::Any<T> || Any<T>;
}
}
}

13
includes/kst/dsn/types/concepts/functions.hpp

@ -0,0 +1,13 @@
#pragma once
#include <kst/dsn/types/concepts/dsn.hpp>
namespace kst::dsn {
namespace states {
class context;
}
namespace types {
template<types::all::Any Ret, types::all::Any...ATypes>
using DisnomiaFunction = Ret (*)(ATypes...);
}
}

33
includes/kst/dsn/types/function.hpp

@ -0,0 +1,33 @@
#pragma once
#include <map>
#include <kst/dsn/types/type_names.hpp>
#include <kst/dsn/types/base_type.hpp>
#include <kst/dsn/types/concepts/dsn.hpp>
#include <kst/dsn/lib/lua.hpp>
namespace kst::dsn {
class value;
class function : public types::base_type<lua_CFunction, &type_names::function, function> {
int _closurec{};
int _argc{};
states::base _state;
std::string _name{};
public:
function(states::base& state, lua_CFunction value)
:base_type(value),_state(state) { }
function(states::base& state,lua_CFunction value, int n, int a)
:base_type(value), _closurec(n), _argc(a), _state(state) { }
friend void states::base::push(function& t);
template<types::all::Any...ATypes>
value operator()(ATypes...args);
};
void states::base::push(function& f) {
lua_pushcclosure(_state, f._value, f._closurec);
}
}

31
includes/kst/dsn/types/table.hpp

@ -0,0 +1,31 @@
#pragma once
#include <map>
#include <any>
#include <kst/dsn/types/type_names.hpp>
#include <kst/dsn/types/base_type.hpp>
#include <kst/dsn/lib/lua.hpp>
#include <kst/dsn/states/base.hpp>
namespace kst::dsn {
class value;
class table : public types::base_type<std::map<value, dsn::value>, &type_names::table, table> {
std::optional<variant_cpp> _id{};
states::base _state;
public:
table(states::base& state,variant_cpp& id);
dsn::value& operator[](variant_cpp & v);
friend void states::base::push(table& t);
friend std::ostream& operator<<(std::ostream& output, table& v) {
return output << "dsn::table[" << &v << "]";
}
friend class value;
};
void states::base::push(table& t) {
get_field(LUA_RIDX_GLOBALS,LUA_REGISTRYINDEX);
get_field(*t._id,-1);
}
}

16
includes/kst/dsn/types/type_names.hpp

@ -0,0 +1,16 @@
#pragma once
#include <string>
namespace kst::dsn {
namespace type_names {
const std::string nil = "nil";
const std::string boolean = "boolean";
const std::string number = "number";
const std::string integer = "integer";
const std::string string = "string";
const std::string function = "function";
const std::string userdata = "userdata";
const std::string thread = "thread";
const std::string table = "table";
};
}

39
includes/kst/dsn/types/types.hpp

@ -0,0 +1,39 @@
#pragma once
#include <variant>
#include <string>
#include <functional>
#include <kst/dsn/types/base_type.hpp>
#include <kst/dsn/types/type_names.hpp>
namespace kst::dsn {
class nil : public types::base_type<nullptr_t, &type_names::nil, nil> {
public:
nil()
:base_type(nullptr) { }
};
class boolean : public types::base_type<bool, &type_names::boolean, boolean> {
public:
boolean(bool value)
:base_type(value) { }
};
class number : public types::base_type<LUA_NUMBER, &type_names::number, number> {
public:
number(double value)
:base_type(value) { }
};
class integer : public types::base_type<LUA_INTEGER, &type_names::integer, integer> {
public:
integer( LUA_INTEGER value)
:base_type(value) { }
};
class string : public types::base_type<std::string, &type_names::string, string> {
public:
string(const std::string& value)
:base_type(value) {}
};
}

324
includes/kst/dsn/types/value.hpp

@ -0,0 +1,324 @@
#pragma once
#include <variant>
#include <optional>
#include <iostream>
#include <kst/dsn/types/concepts/functions.hpp>
#include <kst/dsn/types/types.hpp>
#include <kst/dsn/types/table.hpp>
#include <kst/dsn/types/function.hpp>
#include <kst/dsn/states/base.hpp>
#include <memory>
namespace kst::dsn {
class value {
states::base _base{ nullptr };
variant_t _variant{ dsn::nil() };
std::optional<variant_cpp> _name;
std::optional<table> _parent;
public:
friend class table;
friend class state;
value(const states::base& base, dsn::types::Any auto v)
:_base(base), _variant(v) { }
explicit value(const states::base& base)
:_base(base), _variant(nil()) { }
value(const value& v) = default;
value() = default;
value(lua_State* state, const std::string& name)
:_base(state), _variant(nil()), _name(name) { }
template<types::Any T>
auto& operator=(T v) {
if (_name)
{
bool set = false;
if constexpr(types::Table<T>){
set = true;
_base.push(v);
}
else if constexpr(types::Function<T>)
{
if (v._value!=nullptr)
{
set = true;
_base.push(v);
}
} else {
set = true;
_base.push(v);
}
if (_parent && set)
{
_base.push(*_parent);
lua_rotate(_base, -2, 1);
_base.set_field(*_name, -2);
lua_pop(_base, 1);
}
else if(set){
_base.set_global(*_name);
}
}
_variant = v;
return *this;
}
auto& operator=(std::integral auto value) {
*this = integer(value);
return *this;
}
auto& operator=(bool value) {
*this = boolean(value);
return *this;
}
auto& operator=(const std::string& value) {
*this = string(value);
return *this;
}
auto& operator=(const char* value) {
*this = string(value);
return *this;
}
template<dsn::types::Any T>
operator T() {
try
{
return std::get<T>(_variant);
}
catch (std::bad_variant_access& e)
{
std::string type;
std::visit([&type](auto arg)
{
type = *arg.type_name;
}, _variant);
throw std::runtime_error("Can't convert value of type <"+type+"> to <"+*T::type_name+">");
}
}
template<types::all::Any...ATypes>
auto operator()(ATypes... args) {
function* f = std::get_if<function>(&_variant);
if (auto& fn = *f; f)
{
_base.get_global(*_name);
return fn(args...);
}
throw std::runtime_error("Cannot call non function value");
}
template<typename T, types::all::Any...Args>
auto& operator=(types::DisnomiaFunction<T, Args...> fn) {
lua_pushlightuserdata(_base, reinterpret_cast<void*>(fn));
auto lua_function = [](lua_State* s) -> int
{
auto ctx = states::context(s, sizeof...(Args));
ctx.validate_argc();
int argc = 0;
(ctx.validate_type<Args>(++argc), ...);
auto fn = ctx.get_closure<types::DisnomiaFunction<T, Args...>>();
if constexpr(std::is_void_v<T>)
{
fn(ctx.get<Args>(argc--)...);
return 0;
}
else
{
auto res = fn(ctx.get<Args>(argc--)...);
return ctx.return_arg(res);
}
};
int argc;
if constexpr(std::is_void_v<T>)
argc = 0;
else if (types::all::Any<T>)
argc = 1;
*this = function(_base, lua_function, 1, argc);
return *this;
}
template<std::integral T>
operator T() {
return std::get<integer>(_variant);
}
auto& operator[](variant_cpp id) {
table* t = std::get_if<table>(&_variant);
if (auto& tb = *t; t)
{
_base.push(tb);
std::visit([this](auto& arg)
{
_base.push(arg);
}, id);
return tb[id];
}
throw std::runtime_error("Cannot index non table value");
}
bool operator==(auto v) {
bool res;
std::visit([&res, &v](auto arg)
{
res = arg==v;
}, _variant);
return res;
}
auto operator<=>(value v) {
auto res = std::partial_ordering::equivalent;
std::visit([&res, &v](auto arg)
{
res = arg<=>v;