Compare commits
9 Commits
1080adbde0
...
1d9fb74368
Author | SHA1 | Date | |
---|---|---|---|
1d9fb74368 | |||
7a5e51d948 | |||
40feab49a8 | |||
71c73f70f1 | |||
671a5e9903 | |||
72cf28cd14 | |||
c5d6dd996f | |||
99f3e039dc | |||
ff2b85184e |
cmake
core
thirdparty
23
cmake/imgui4lua.cmake
Normal file
23
cmake/imgui4lua.cmake
Normal file
@ -0,0 +1,23 @@
|
||||
function(_imgui4lua_main)
|
||||
set(dir "${CMAKE_CURRENT_BINARY_DIR}/generated")
|
||||
set(py "${PROJECT_SOURCE_DIR}/cmake/imgui4lua.py")
|
||||
set(src "${imgui_SOURCE_DIR}/imgui.h")
|
||||
set(dst "${dir}/imgui4lua.inc")
|
||||
|
||||
find_program(SH sh REQUIRED)
|
||||
find_program(PYTHON3 python3 REQUIRED)
|
||||
find_program(CLANGXX clang++ REQUIRED)
|
||||
|
||||
make_directory("${dir}")
|
||||
add_custom_command(
|
||||
COMMAND ${SH} -c "${PYTHON3} '${py}' '${src}' > '${dst}'"
|
||||
OUTPUT "${dst}"
|
||||
DEPENDS "${src}" "${py}"
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
add_library(imgui4lua INTERFACE)
|
||||
target_sources(imgui4lua PUBLIC "${dst}")
|
||||
target_include_directories(imgui4lua INTERFACE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endfunction()
|
||||
_imgui4lua_main()
|
208
cmake/imgui4lua.py
Executable file
208
cmake/imgui4lua.py
Executable file
@ -0,0 +1,208 @@
|
||||
import json
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
# ---- GENERATOR DEFINITIONS
|
||||
def gen_enum(item):
|
||||
name = item.get("name", "")
|
||||
if name not in kEnumWhitelist:
|
||||
return
|
||||
|
||||
short_name = name[5:-1]
|
||||
|
||||
print(f"{{ // {name}")
|
||||
for child in item.get("inner", []):
|
||||
member_name = child["name"]
|
||||
if not member_name.startswith(name): continue
|
||||
member_short_name = member_name[len(name):]
|
||||
print(f" lua_pushinteger(L, static_cast<lua_Integer>({member_name})); "+
|
||||
f"lua_setfield(L, -2, \"{short_name}_{member_short_name}\");")
|
||||
print(f"}} // {name}")
|
||||
print()
|
||||
|
||||
def gen_func(name, ovlds):
|
||||
ovld_root = (0, {}, None)
|
||||
for ovld in ovlds:
|
||||
ovld_node = ovld_root
|
||||
idx = 0
|
||||
for arg in ovld.get("inner", []):
|
||||
if "ParmVarDecl" != arg.get("kind"): continue
|
||||
tname = get_type_from_argument(arg)
|
||||
if tname not in kLuaTypeChecker:
|
||||
break
|
||||
ovld_node[1][tname] = (idx, {}, None)
|
||||
ovld_node = ovld_node[1][tname]
|
||||
idx += 1
|
||||
ovld_node[1]["$"] = (idx, {}, ovld)
|
||||
|
||||
def _output(ovld_node, depth=1):
|
||||
indent = " "*depth
|
||||
if 0 == len(ovld_node[1]):
|
||||
gen_single_func(ovld_node[2], indent=indent)
|
||||
elif 1 == len(ovld_node[1]):
|
||||
_output(*ovld_node[1].values(), depth=depth)
|
||||
else:
|
||||
for tname in ovld_node[1]:
|
||||
checker = kLuaTypeChecker[tname].replace("#", str(ovld_node[0]+1))
|
||||
print(f"{indent}if ({checker}) {{")
|
||||
_output(ovld_node[1][tname], depth=depth+1)
|
||||
print(f"{indent}}}")
|
||||
print(f"{indent}return luaL_error(L, \"unexpected type in param#{ovld_node[0]}\");")
|
||||
print("lua_pushcfunction(L, [](auto L) {")
|
||||
print(" (void) L;")
|
||||
_output(ovld_root)
|
||||
print("});")
|
||||
print(f"lua_setfield(L, -2, \"{name}\");")
|
||||
print()
|
||||
|
||||
def gen_single_func(item, indent=""):
|
||||
name = item["name"]
|
||||
pops = []
|
||||
params = []
|
||||
pcount = 0
|
||||
for arg in item.get("inner", []):
|
||||
if "ParmVarDecl" != arg.get("kind"): continue
|
||||
pop, param, push = gen_argument(pcount, arg)
|
||||
pcount += 1
|
||||
pops .extend(pop)
|
||||
params.extend(param)
|
||||
push .extend(push)
|
||||
|
||||
pushes = gen_return(item)
|
||||
use_ret = 0 < len(pushes)
|
||||
|
||||
# text output
|
||||
nl = "\n"+indent
|
||||
cm = ", "
|
||||
if 0 < len(pops):
|
||||
print(f"{indent}{nl.join(pops)}")
|
||||
if use_ret:
|
||||
print(f"{indent}const auto r = ImGui::{name}({cm.join(params)});")
|
||||
else:
|
||||
print(f"{indent}ImGui::{name}({cm.join(params)});")
|
||||
if 0 < len(pushes):
|
||||
print(f"{indent}{nl.join(pushes)}")
|
||||
print(f"{indent}return {len(pushes)};")
|
||||
|
||||
def gen_return(item):
|
||||
ftype = item["type"]["qualType"]
|
||||
type = ftype[0:ftype.find("(")-1]
|
||||
|
||||
if "void" == type:
|
||||
return []
|
||||
if "bool" == type:
|
||||
return ["lua_pushboolean(L, r);"]
|
||||
if "float" == type:
|
||||
return ["lua_pushnumber(L, static_cast<lua_Number>(r));"]
|
||||
if "ImVec2" == type:
|
||||
return [
|
||||
"lua_pushnumber(L, static_cast<lua_Number>(r.x));",
|
||||
"lua_pushnumber(L, static_cast<lua_Number>(r.y));",
|
||||
]
|
||||
|
||||
print(f"unknown return type: {type}", file=sys.stderr)
|
||||
return []
|
||||
|
||||
def gen_argument(pc, item):
|
||||
type = item["type"].get("desugaredQualType", item["type"]["qualType"])
|
||||
n = pc+1
|
||||
pn = f"p{pc}"
|
||||
|
||||
if type in ["int", "unsigned int"]:
|
||||
return ([f"const int {pn} = static_cast<{type}>(luaL_checkinteger(L, {n}));"], [pn], [])
|
||||
|
||||
if "bool" == type:
|
||||
return ([f"const bool {pn} = lua_toboolean(L, {n});"], [pn], [])
|
||||
|
||||
if "const char *" == type:
|
||||
return ([f"const char* {pn} = luaL_checkstring(L, {n});"], [pn], [])
|
||||
|
||||
if "const ImVec2 &" == type:
|
||||
return ([
|
||||
f"const float {pn}_1 = static_cast<float>(luaL_checknumber(L, {n}));",
|
||||
f"const float {pn}_2 = static_cast<float>(luaL_checknumber(L, {n}));",
|
||||
], [f"ImVec2 {{{pn}_1, {pn}_2}}"], [])
|
||||
|
||||
if "bool *" == type:
|
||||
return ([f"bool {pn};"], [f"&{pn}"], [f"lua_pushboolean(L, {pn});"])
|
||||
|
||||
print(f"unknown argument type: {type}", file=sys.stderr)
|
||||
return ([], [], [])
|
||||
|
||||
|
||||
# ---- GENERATOR UTILITIES
|
||||
def get_type_from_argument(item):
|
||||
return item["type"].get("desugaredQualType", item["type"]["qualType"])
|
||||
|
||||
|
||||
# ---- WALKER DEFINITIONS
|
||||
class Walker:
|
||||
def __init__(self):
|
||||
self._funcs = {}
|
||||
self._enums = {}
|
||||
|
||||
def emit(self):
|
||||
for x in self._enums: gen_enum(self._enums[x])
|
||||
for x in self._funcs: gen_func(x, self._funcs[x])
|
||||
|
||||
def walk(self, item):
|
||||
kind = item.get("kind")
|
||||
name = item.get("name")
|
||||
if "EnumDecl" == kind:
|
||||
if name in kEnumWhitelist:
|
||||
self._enums[name] = item
|
||||
else:
|
||||
w = self.walk
|
||||
if "NamespaceDecl" == kind:
|
||||
w = self._walk_ns
|
||||
for child in item.get("inner", []):
|
||||
w(child)
|
||||
|
||||
def _walk_ns(self, item):
|
||||
kind = item.get("kind")
|
||||
name = item.get("name")
|
||||
if "FunctionDecl" == kind:
|
||||
if name in kFuncWhitelist:
|
||||
if name not in self._funcs:
|
||||
self._funcs[name] = [item]
|
||||
else:
|
||||
self._funcs[name].append(item)
|
||||
else:
|
||||
self.walk(item)
|
||||
|
||||
|
||||
# ---- DATA DEFINITIONS
|
||||
kFuncWhitelist = [
|
||||
"Begin",
|
||||
"End",
|
||||
"BeginChild",
|
||||
"EndChild",
|
||||
"IsWindowAppearing",
|
||||
"IsWindowCollapsed",
|
||||
"IsWindowFocused",
|
||||
"IsWindowHovered",
|
||||
"GetWindowPos",
|
||||
"GetWindowSize",
|
||||
"GetWindowWidth",
|
||||
"GetWindowHeight",
|
||||
"Text",
|
||||
]
|
||||
kEnumWhitelist = [
|
||||
"ImGuiWindowFlags_",
|
||||
]
|
||||
kLuaTypeChecker = {
|
||||
"int": "LUA_TNUMBER == lua_type(L, #)",
|
||||
"const char *": "LUA_TSTRING == lua_type(L, #)",
|
||||
"$": "lua_isnone(L, #)",
|
||||
}
|
||||
|
||||
|
||||
# ---- ENTRYPOINT
|
||||
proc = subprocess.run(["clang++", "-x", "c++", "-std=c++2b", "-Xclang", "-ast-dump=json", "-fsyntax-only", sys.argv[1]], capture_output=True)
|
||||
if 0 == proc.returncode:
|
||||
walker = Walker()
|
||||
walker.walk(json.loads(proc.stdout))
|
||||
walker.emit()
|
||||
else:
|
||||
print(proc.stderr.decode("utf-8"))
|
||||
exit(1)
|
@ -3,6 +3,7 @@ target_link_libraries(nf7_core
|
||||
PUBLIC
|
||||
git_hash
|
||||
imgui
|
||||
imgui4lua
|
||||
luajit
|
||||
nf7_config
|
||||
nf7_iface
|
||||
|
@ -12,7 +12,15 @@ namespace nf7::core::imgui {
|
||||
|
||||
std::shared_ptr<luajit::Value> LuaJITDriver::MakeExtensionObject(
|
||||
luajit::TaskContext& lua) {
|
||||
lua_pushnil(*lua);
|
||||
auto L = *lua;
|
||||
|
||||
lua_newuserdata(L, 0);
|
||||
if (luaL_newmetatable(L, "nf7::core::imgui::LuaJITDriver::Extension")) {
|
||||
lua_createtable(L, 0, 0);
|
||||
# include "generated/imgui4lua.inc"
|
||||
lua_setfield(L, -2, "__index");
|
||||
}
|
||||
lua_setmetatable(L, -2);
|
||||
return lua.Register();
|
||||
}
|
||||
|
||||
|
@ -38,15 +38,17 @@ TEST_F(ImGuiLuaJITDriver, CompileAndInstall) {
|
||||
|
||||
auto fu = nf7::core::imgui::LuaJITDriver::CompileAndInstall(
|
||||
*subenv,
|
||||
toVector("local ctx = ...\nctx:trace(\"hello world\")"),
|
||||
toVector(
|
||||
"local ctx = ...\nctx:trace(\"hello world\")\n"
|
||||
"local imgui = ctx:recv():lua()\n"
|
||||
"imgui.Begin(\"helloworld\", true, imgui.WindowFlags_NoResize)\n"
|
||||
"imgui.End()"),
|
||||
"test chunk");
|
||||
|
||||
concurrency->Push(
|
||||
nf7::SyncTask {
|
||||
clock->now() + std::chrono::seconds {2},
|
||||
clock->now() + std::chrono::seconds {10},
|
||||
[&](auto&) { DropEnv(); },
|
||||
});
|
||||
ConsumeTasks();
|
||||
|
||||
// TODO FIXME fix leak
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
// No copyright
|
||||
#include "core/luajit/context.hh"
|
||||
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <vector>
|
||||
|
||||
@ -39,6 +40,17 @@ void TaskContext::Push(const nf7::Value& v) noexcept {
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(state_, -2, "type");
|
||||
|
||||
lua_pushcfunction(state_, [](auto L) {
|
||||
const nf7::Value& v = CheckUserData<nf7::Value>(L, 1, "nf7::Value");
|
||||
try {
|
||||
v.data<luajit::Value>()->Push(L);
|
||||
} catch (...) {
|
||||
lua_pushnil(L);
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
lua_setfield(state_, -2, "lua");
|
||||
}
|
||||
lua_setfield(state_, -2, "__index");
|
||||
|
||||
@ -84,13 +96,16 @@ class SyncContext final :
|
||||
}
|
||||
|
||||
void Push(Task&& task) noexcept override {
|
||||
++refcnt_;
|
||||
|
||||
auto self = std::dynamic_pointer_cast<SyncContext>(shared_from_this());
|
||||
concurrency_->Push({
|
||||
task.after(),
|
||||
[self, task = std::move(task)](auto&) mutable {
|
||||
[this, self, task = std::move(task)](auto&) mutable {
|
||||
TaskContext ctx {self, self->state()};
|
||||
lua_settop(*ctx, 0);
|
||||
task(ctx);
|
||||
if (0 == --refcnt_) { lua_gc(*ctx, LUA_GCCOLLECT, 0); }
|
||||
},
|
||||
task.location()
|
||||
});
|
||||
@ -100,7 +115,8 @@ class SyncContext final :
|
||||
using Context::shared_from_this;
|
||||
|
||||
private:
|
||||
std::shared_ptr<subsys::Concurrency> concurrency_;
|
||||
const std::shared_ptr<subsys::Concurrency> concurrency_;
|
||||
uint64_t refcnt_ {0};
|
||||
};
|
||||
|
||||
class AsyncContext final :
|
||||
@ -114,6 +130,8 @@ class AsyncContext final :
|
||||
}
|
||||
|
||||
void Push(Task&& task) noexcept override {
|
||||
++refcnt_;
|
||||
|
||||
std::unique_lock<std::mutex> k {mtx_};
|
||||
const auto first = tasks_.empty();
|
||||
tasks_.push_back(std::move(task));
|
||||
@ -142,7 +160,9 @@ class AsyncContext final :
|
||||
TaskContext ctx {self, state()};
|
||||
for (auto& task : tasks) {
|
||||
task(ctx);
|
||||
--refcnt_;
|
||||
}
|
||||
if (0 == refcnt_) { lua_gc(*ctx, LUA_GCCOLLECT, 0); }
|
||||
}
|
||||
|
||||
private:
|
||||
@ -150,6 +170,8 @@ class AsyncContext final :
|
||||
|
||||
std::mutex mtx_;
|
||||
std::vector<Task> tasks_;
|
||||
|
||||
std::atomic<uint64_t> refcnt_ {0};
|
||||
};
|
||||
} // namespace
|
||||
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <lua.hpp>
|
||||
|
||||
#include "iface/common/future.hh"
|
||||
#include "iface/common/leak_detector.hh"
|
||||
#include "iface/common/value.hh"
|
||||
@ -45,13 +47,17 @@ class Value final : public nf7::Value::Data, public LeakDetector<Value> {
|
||||
Value& operator=(const Value&) = delete;
|
||||
Value& operator=(Value&&) = delete;
|
||||
|
||||
void Push(lua_State* L) const noexcept {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, index_);
|
||||
}
|
||||
|
||||
public:
|
||||
const std::shared_ptr<Context>& context() const noexcept { return ctx_; }
|
||||
int index() const noexcept { return index_; }
|
||||
|
||||
private:
|
||||
std::shared_ptr<Context> ctx_;
|
||||
int index_;
|
||||
const std::shared_ptr<Context> ctx_;
|
||||
const int index_;
|
||||
};
|
||||
|
||||
} // namespace nf7::core::luajit
|
||||
|
1
thirdparty/CMakeLists.txt
vendored
1
thirdparty/CMakeLists.txt
vendored
@ -19,6 +19,7 @@ FetchContent_Declare(
|
||||
)
|
||||
FetchContent_Populate(imgui)
|
||||
include(imgui.cmake)
|
||||
include(../cmake/imgui4lua.cmake)
|
||||
|
||||
# ---- luajit (MIT)
|
||||
FetchContent_Declare(
|
||||
|
Loading…
x
Reference in New Issue
Block a user