Initial commit

This commit is contained in:
mid 2026-02-23 19:18:09 +02:00
commit 285a141825
7 changed files with 286 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.o
*.a
/goci
/goci.exe

32
glua/cglua.c Normal file
View File

@ -0,0 +1,32 @@
#include<lua.h>
#include<lualib.h>
#include<lauxlib.h>
#include<stdint.h>
extern int glua_go_call_func(uint64_t);
extern int glua_go_remove_func(uint64_t);
int glua_metatable_call(lua_State *L) {
uint64_t id = *(uint64_t*) lua_touserdata(L, 1);
int result = glua_go_call_func(id);
if(result < 0) {
lua_error(L);
}
return result;
}
int glua_metatable_gc(lua_State *L) {
uint64_t id = *(uint64_t*) lua_touserdata(L, 1);
glua_go_remove_func(id);
return 0;
}
int glua_metatable_tostring(lua_State *L) {
uint64_t id = *(uint64_t*) lua_touserdata(L, 1);
char buf[64];
snprintf(buf, sizeof(buf), "gofunc: 0x%X", id);
lua_pushstring(L, buf);
return 1;
}

196
glua/glua.go Normal file
View File

@ -0,0 +1,196 @@
package glua
/*
* Self-contained Go-Lua binding, which handles inter-FFI errors seamlessly unlike others.
* */
// #cgo pkg-config: lua
// #cgo LDFLAGS: -L./ -lcglua
// #include<lua.h>
// #include<lualib.h>
// #include<lauxlib.h>
// #include<stdlib.h>
// extern int glua_metatable_call(lua_State*);
// extern int glua_metatable_gc(lua_State*);
// extern int glua_metatable_tostring(lua_State*);
import "C"
import "fmt"
import "unsafe"
type Function func(l *Lua) int
type FuncStatePair struct {
fn Function
l *Lua
}
var FuncIDs map[uint64]FuncStatePair = make(map[uint64]FuncStatePair)
var NextFuncID uint64 = 0
//export glua_go_call_func
func glua_go_call_func(id C.uint64_t) (ret C.int) {
pair := FuncIDs[uint64(id)]
defer func() {
if r := recover(); r != nil {
pair.l.PushString(fmt.Sprint(r))
ret = -1
}
}()
return C.int(pair.fn(pair.l))
}
//export glua_go_remove_func
func glua_go_remove_func(id C.uint64_t) {
delete(FuncIDs, uint64(id))
}
type Lua struct {
state *C.lua_State
}
func NewState() Lua {
l := Lua{C.luaL_newstate()}
C.luaL_newmetatable(l.state, C.CString("GLUA_FUNCTION"))
C.lua_pushcclosure(l.state, C.lua_CFunction(C.glua_metatable_call), 0)
l.SetField(-2, "__call")
C.lua_pushcclosure(l.state, C.lua_CFunction(C.glua_metatable_gc), 0)
l.SetField(-2, "__gc")
C.lua_pushcclosure(l.state, C.lua_CFunction(C.glua_metatable_tostring), 0)
l.SetField(-2, "__tostring")
l.Pop(1)
return l
}
func (l Lua) Close() {
C.lua_close(l.state)
}
func (l Lua) OpenLibs() {
C.luaL_openlibs(l.state)
}
func (l Lua) NewTable() {
C.lua_createtable(l.state, 0, 0)
}
func (l Lua) SetField(offset int, name string) {
cstr := C.CString(name)
C.lua_setfield(l.state, C.int(offset), cstr)
C.free(unsafe.Pointer(cstr))
}
func (l Lua) SetGlobal(name string) {
cstr := C.CString(name)
C.lua_setglobal(l.state, cstr)
C.free(unsafe.Pointer(cstr))
}
func (l Lua) GetGlobal(name string) {
cstr := C.CString(name)
C.lua_getglobal(l.state, cstr)
C.free(unsafe.Pointer(cstr))
}
func (l Lua) DoFile(filepath string) int {
cstr := C.CString(filepath)
defer C.free(unsafe.Pointer(cstr))
err := int(C.luaL_loadfilex(l.state, cstr, nil))
if err != 0 {
return err
}
err = int(C.lua_pcallk(l.state, 0, -1, 0, 0, nil))
if err != 0 {
return err
}
return 0
}
func (l Lua) ToInteger(offset int) int64 {
return int64(C.lua_tointegerx(l.state, C.int(offset), nil))
}
func (l Lua) ToNumber(offset int) float64 {
return float64(C.lua_tonumberx(l.state, C.int(offset), nil))
}
func (l Lua) ToBoolean(offset int) bool {
return C.lua_toboolean(l.state, C.int(offset)) != 0
}
func (l Lua) ToString(offset int) string {
var len C.size_t
cstr := C.lua_tolstring(l.state, C.int(offset), &len)
return C.GoStringN(cstr, C.int(len))
}
func (l Lua) PushInteger(i int64) {
C.lua_pushinteger(l.state, C.lua_Integer(i))
}
func (l Lua) PushNumber(f float64) {
C.lua_pushnumber(l.state, C.lua_Number(f))
}
func (l Lua) PushString(s string) {
cstr := C.CString(s)
C.lua_pushstring(l.state, cstr)
C.free(unsafe.Pointer(cstr))
}
func (l Lua) PushFunction(fn Function) {
i := NextFuncID
for true {
if _, exists := FuncIDs[i]; !exists {
break
}
i += 1
}
ud := C.lua_newuserdatauv(l.state, 8, 1)
*(*C.uint64_t)(ud) = C.uint64_t(i)
cstr := C.CString("GLUA_FUNCTION")
C.luaL_setmetatable(l.state, cstr)
C.free(unsafe.Pointer(cstr))
FuncIDs[i] = FuncStatePair{fn, &l};
}
func (l Lua) PushValue(offset int) {
C.lua_pushvalue(l.state, C.int(offset));
}
func (l Lua) Pop(count int) {
C.lua_settop(l.state, C.int(-count - 1));
}
func (l Lua) Call(nargs int, nresults int, msgh int) int {
err := int(C.lua_pcallk(l.state, C.int(nargs), C.int(nresults), C.int(msgh), 0, nil))
if err == 2 {
l.PushValue(-1)
why := l.ToString(-1)
l.Pop(1)
panic(why)
}
return err
}
func (l Lua) ProtectedCall(nargs int, nresults int, msgh int) int {
return int(C.lua_pcallk(l.state, C.int(nargs), C.int(nresults), C.int(msgh), 0, nil))
}
func (l Lua) UnsafeCall(nargs int, nresults int) {
C.lua_callk(l.state, C.int(nargs), C.int(nresults), 0, nil)
}

8
go.mod Normal file
View File

@ -0,0 +1,8 @@
module mid.net.ua/git/mid/goci
go 1.25
require (
github.com/Shopify/go-lua v0.0.0-20250718183320-1e37f32ad7d0 // indirect
github.com/mappu/miqt v0.13.0 // indirect
)

4
go.sum Normal file
View File

@ -0,0 +1,4 @@
github.com/Shopify/go-lua v0.0.0-20250718183320-1e37f32ad7d0 h1:oGlw/+ndlFMn8KWLjEX5nULcDwOC4tJy3Kk1Pm84Cys=
github.com/Shopify/go-lua v0.0.0-20250718183320-1e37f32ad7d0/go.mod h1:M4CxjVc/1Nwka5atBv7G/sb7Ac2BDe3+FxbiT9iVNIQ=
github.com/mappu/miqt v0.13.0 h1:Dzvclso1BwAUVNem7giSYCmh4Rx08j2gqt6j4SCy098=
github.com/mappu/miqt v0.13.0/go.mod h1:xFg7ADaO1QSkmXPsPODoKe/bydJpRG9fgCYyIDl/h1U=

41
main.go Normal file
View File

@ -0,0 +1,41 @@
package main
import "os"
import "fmt"
import "github.com/mappu/miqt/qt6"
import "mid.net.ua/git/mid/goci/glua"
func InitUI() {
qt6.NewQApplication(os.Args)
mw := qt6.NewQMainWindow(nil)
{
dock := qt6.NewQDockWidget(mw.QWidget)
mw.AddDockWidget(qt6.DockWidgetArea(1), dock)
}
mw.Show()
}
var L glua.Lua
func InitLua() {
L := glua.NewState()
L.OpenLibs()
L.NewTable()
// Our interface functions go here
L.SetGlobal("UI")
L.DoFile("main.lua")
}
func main() {
fmt.Println("I'm printing dis to prevent unused package warning")
InitUI()
InitLua()
qt6.QApplication_Exec()
}

1
main.lua Normal file
View File

@ -0,0 +1 @@