Coder Social home page Coder Social logo

luar's Introduction

Luar: Lua reflection bindings for Go

Luar is designed to make using Lua from Go more convenient. Go structs, slices and maps can be automatically converted to Lua tables and vice-versa. The resulting conversion can either be a copy or a proxy. In the latter case, any change made to the result will reflect on the source.

Any Go function can be made available to Lua scripts, without having to write C-style wrappers.

Luar support cyclic structures (map[string]interface{}, lists, etc.).

User-defined types can be made available to Lua as well: their exported methods can be called and usual operations such as indexing or arithmetic can be performed.

See the documentation for usage instructions and examples.

Installation

Install with

go get <repo>/luar

Luar uses Alessandro Arzilli's golua. See golua's homepage for further installation details.

REPL

Version 1.x features an example REPL that is available in the cmd folder.

Changelog

Luar 2

This is a rewrite of 1.x with extended features and a cleaner API. The main differences with the previous version:

  • The function prototypes of GoToLua and LuaToGo are simpler and do not require the use of reflection from the callers. The dontproxify argument is gone, use GoToLuaProxy to control proxification.

  • The Copy* functions and GoLuaFunc are gone, use GoToLua and LuaToGo instead.

  • Use Register instead of RawRegister.

  • InitProxies is gone since it was not needed.

  • The LuaObject and LuaTableIter structure fields are unexported.

  • LuaObject methods not only work on Lua functions but also on anything with a __call metamethods. Idem for tables and the __index/__newindex metamethods.

  • Use NewLuaObjectFromName(L, "_G") instead of Global.

  • Lookup and Geti gone. Instead the Get and GetObject functions are variadic: each subfield argument can be any valid Lua key (string, integer...).

  • Use (*LuaObject) Call instead of (*LuaObject) Callf. The protoype of (*LuaObject) Call has changed in a fashion similar to GoToLua and LuaToGo. Types is gone as it is no longer needed.

  • Register ProxyIpairs and ProxyPairs instead of calling LuarSetup.

  • Register and use Unproxify instead of ArrayToTable, MapToTable, ProxyRaw, SliceToTable and StructToTable.

  • ComplexReal and ComplexImag have been replaced by the proxy attributes real and imag, respectively.

  • SliceSub and SliceAppend have been replaced by the proxy methods slice and append, respectively. Slice proxies have the cap metamethod alongside append and slice.

  • String proxies have a slice method just like slice proxies. They can be looped rune-by-rune over with ipairs.

The range of supported conversion has been extended:

  • LuaToGo can convert to interfaces and pointers with several levels of indirection.

  • LuaToGo can convert to non-empty maps and structs.

luar's People

Contributors

aarzilli avatar ambrevar avatar bitwalker avatar hirochachacha avatar jarcoal avatar kdar avatar stevedonovan avatar tasssadar avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

luar's Issues

bad import "unsafe"

I tried to run luar on an Go - Appengine project. However I encountered

"o-app-builder: Failed parsing input: parser: bad import "unsafe" in github.com/stevedonovan/luar/luar.go"

I searched and found that the package is trimmed on GAE. Does this mean I cannot use luar with golua on GAE?

Thank you.

Nested structure methods can not be found

type String string

func (self String) String() string {
	return string(self)
}

type Second struct {
	Name String
}
type Person struct {
	SecondName Second
	Age        int
}

func main() {
	const test = `
	print(user.SecondName.Name.String())
`

	L := luar.Init()
	defer L.Close()

	user := &Person{SecondName: Second{"lion"}, Age: 46}

	luar.Register(L, "", luar.Map{
		"user": user,
	})

	err := L.DoString(test)
	if err != nil {
		fmt.Println(err)
	}
}

run this , It show error:
[string "..."]:2: attempt to call field 'String' (a nil value)

go Memory leak

when i use luar in my project, i find the memory leak. i find the memery in lua collectgarbage("count") is normal, bug the process is not gc

GoLuaFunc and RawRegister

@stevedonovan What is the point of the separation Register / RawRegister? As far as I get it, RawRegister panics when the prototype is not Lua friendly, that's the only use I see.

Moreover, I'm wondering why GoLuaFunc isn't part of GoToLua: it would make the API simpler. Any good reason for that?

license?

luago seems to be MIT licensed, but I don't see anything for this project. Is it reasonable to assume this is MIT licensed as well?

luajit

Is luajit supported/workable with luar, or only lua?

Thanks!

Jason

Extend __type metamethod for proxies

See: bitwalker@9747fcd
This allows for type() to return something more interesting about proxies.
The aforementioned commit returns table. I like the idea of making the distinction between real Lua tables and proxy tables. What about returning

  • userdata(map)
  • proxy(map).
  • goluadata(map).
  • luardata(map).

Comments?

Best way to use Luar across multiple goroutines?

(Aside: I'm not entirely sure this is the best title because I'm not convinced I know exactly what it is I'm running into.)

I've been toying with Luar in conjunction with the net/http package and it works very well. I'm imagining it as a sort of scriptable instrumentation system or the likes. However, if a less scrupulous individual changes GOMAXPROCS (so far, the only idiot to do such a heinous thing is me), the application outright dies with a number of inconsistent, mysterious errors ranging from "segmentation violations" to a more instructive double-free/corruption plus backtrace.

I suspect this is due to contention issues among multiple goroutines, but I don't know enough about Golang internals to even know where to begin (it doesn't help that I just picked up the language about two months ago, rendering me even more clueless).

The following sample code illustrates the problem that is triggered only if GOMAXPROCS is set to something greater than 1:

package main

import (
    "fmt"
    "net/http"
    "github.com/stevedonovan/luar"
    "github.com/aarzilli/golua/lua" // For lua.State.
)

const script = `
function requester(r)
    print("Request from "..r.RemoteAddr)
end
`

var context *lua.State = luar.Init()
var requester *luar.LuaObject

func rootHandler (rw http.ResponseWriter, r *http.Request) {
    _, err := requester.Call(r)
    if err != nil {
        fmt.Println("requester died with:", err)
    }
}

func main() {
    luar.Init()
    context.DoString(script)
    requester = luar.NewLuaObjectFromName(context, "requester")
    http.HandleFunc("/", rootHandler)
    http.ListenAndServe(":8112", nil)
}

Next, running something akin to ab -c 10 -n 1000 http://localhost:8112/ will kill the application after some number of requests.

Now, it seems to work without GOMAXPROCS set (or rather, set to the default), so I'm actually convinced that I'm doing something horribly, horribly wrong. I've tried different incantations of the same code, including initializing Luar (luar.Init()) from within the individual requests inside rootHandler. Obviously, I want to avoid doing something like that because the overhead of VM initialization will affect each request.

If it's recommended to simply avoid GOMAXPROCS, that's fine. I can leave a note in the documentation for possible future readers in projects I develop to avoid setting it at all costs. Even with the Lua initialization, Go's performance is so dramatically different than that of, say, Python that it's almost a non-issue (bandwidth constraints would affect hypothetical applications long before Go's performance comes into question). That said, I know there's a piece of this puzzle I'm missing, because I haven't convinced myself I'm using Luar correctly.

So I think in this case the best advice is to leave well enough alone?

API change

The GoToLua and LuaToGo functions are poorly designed:

func GoToLua(L *lua.State, t reflect.Type, val reflect.Value, dontproxify bool)
  • t is useless.
  • val should be an interface{}.
  • dontproxify is confusing and not convenient. We should use different function names like GoToLua and GoToLuaProxy.
func LuaToGo(L *lua.State, t reflect.Type, idx int) interface{}
  • t and interface{} force the use of reflection and type switching. We should store the result in the value pointed by the interface{} passed as argument, just like json.Unmarshal.

The new functions would be:

func GoToLua(L *lua.State, v interface{})

func GoToLuaProxy(L *lua.State, v interface{})

func LuaToGo(L *lua.State, v interface{}, idx int) error

This is an easy change but would break backward-compatibility.
This might not be such a big deal considering the low usage or Luar, but this is bad practice nonetheless.
Shall we move to a Luar2 repo?
Or shall we ignore this change?

Crash with go 1.8

The test suite (and my closed-source application that uses luar) crashes with go1.8:

tassadar@dorea:~/chadron-server/bin$ GODEBUG=gccheckmark=1  GOGC=1 GOROOT=/usr/local/go1.8/ /usr/local/go1.8/bin/go test github.com/stevedonovan/luar
runtime: marking free object 0xc420010800 found at *(0x0+0x0)
base=0x0 is not in the Go heap
obj=0xc420010800 k=0x6210008 s.base()=0xc420010000 s.limit=0xc420012000 s.sizeclass=2 s.elemsize=16 s.state=_MSpanInUse
 *(obj+0) = 0xc4200107f0
 *(obj+8) = 0x6
fatal error: marking free object

runtime stack:
runtime.throw(0x5b3d7c, 0x13)
        /usr/local/go1.8/src/runtime/panic.go:596 +0x95
runtime.greyobject(0xc420010800, 0x0, 0x0, 0xc41ffff7bf, 0xc400000000, 0x7f74ff2ca2f8, 0xc420021228, 0x80)
        /usr/local/go1.8/src/runtime/mgcmark.go:1388 +0x497
runtime.shade(0xc420010800)
        /usr/local/go1.8/src/runtime/mgcmark.go:1342 +0xbd
runtime.gcmarkwb_m(0x14a2f60, 0xc420010728)
        /usr/local/go1.8/src/runtime/mbarrier.go:154 +0xea
runtime.writebarrierptr_prewrite1.func1()
        /usr/local/go1.8/src/runtime/mbarrier.go:188 +0x64
runtime.systemstack(0x7fffa875cd00)
        /usr/local/go1.8/src/runtime/asm_amd64.s:327 +0x79
runtime.mstart()
        /usr/local/go1.8/src/runtime/proc.go:1132

goroutine 67 [running, locked to thread]:
runtime.systemstack_switch()
        /usr/local/go1.8/src/runtime/asm_amd64.s:281 fp=0xc4200e9708 sp=0xc4200e9700
runtime.writebarrierptr_prewrite1(0x14a2f60, 0xc420010728)
        /usr/local/go1.8/src/runtime/mbarrier.go:189 +0xbf fp=0xc4200e9748 sp=0xc4200e9708
runtime.writebarrierptr(0x14a2f60, 0xc420010728)
        /usr/local/go1.8/src/runtime/mbarrier.go:211 +0x4d fp=0xc4200e9780 sp=0xc4200e9748
github.com/stevedonovan/luar.makeValueProxy(0xc420018680, 0x587980, 0xc420010728, 0x82, 0x5b13c1, 0x8)
        /home/tassadar/chadron-server/src/github.com/stevedonovan/luar/proxy.go:118 +0x31b fp=0xc4200e97e0 sp=0xc4200e9780
github.com/stevedonovan/luar.goToLua(0xc420018680, 0x0, 0x0, 0x587980, 0xc420010728, 0x82, 0x0, 0xc420018680, 0x1)
        /home/tassadar/chadron-server/src/github.com/stevedonovan/luar/luar.go:497 +0x2f5 fp=0xc4200e9888 sp=0xc4200e97e0
github.com/stevedonovan/luar.GoToLua(0xc420018680, 0x0, 0x0, 0x587980, 0xc420010728, 0x82, 0x0)
        /home/tassadar/chadron-server/src/github.com/stevedonovan/luar/luar.go:454 +0xaa fp=0xc4200e98f0 sp=0xc4200e9888
github.com/stevedonovan/luar.goLuaFunc.func1(0xc420018680, 0xc420018680)
        /home/tassadar/chadron-server/src/github.com/stevedonovan/luar/luar.go:858 +0x35f fp=0xc4200e9a40 sp=0xc4200e98f0
github.com/aarzilli/golua/lua.golua_callgofunction(0xc420018680, 0x22, 0xc4200183d8)
        /home/tassadar/chadron-server/src/github.com/aarzilli/golua/lua/golua.go:73 +0x6d fp=0xc4200e9a90 sp=0xc4200e9a40
github.com/aarzilli/golua/lua._cgoexpwrap_fb48268534f4_golua_callgofunction(0xc420018680, 0x22, 0x7f74feefd975)
        github.com/aarzilli/golua/lua/_obj/_cgo_gotypes.go:1575 +0x35 fp=0xc4200e9ab8 sp=0xc4200e9a90
runtime.call32(0x0, 0x7fffa875c8d8, 0x7fffa875c970, 0x18)
        /usr/local/go1.8/src/runtime/asm_amd64.s:514 +0x48 fp=0xc4200e9ae8 sp=0xc4200e9ab8
runtime.cgocallbackg1(0x0)
        /usr/local/go1.8/src/runtime/cgocall.go:301 +0x19d fp=0xc4200e9b60 sp=0xc4200e9ae8
runtime.cgocallbackg(0x0)
        /usr/local/go1.8/src/runtime/cgocall.go:184 +0x84 fp=0xc4200e9bc8 sp=0xc4200e9b60
runtime.cgocallback_gofunc(0x40655a, 0x558f80, 0xc4200e9c78, 0x40657c)
        /usr/local/go1.8/src/runtime/asm_amd64.s:767 +0x74 fp=0xc4200e9be8 sp=0xc4200e9bc8
runtime.asmcgocall(0x558f80, 0xc4200e9c78)
        /usr/local/go1.8/src/runtime/asm_amd64.s:614 +0x42 fp=0xc4200e9bf0 sp=0xc4200e9be8
runtime.cgocall(0x558f80, 0xc4200e9c78, 0x520100)
        /usr/local/go1.8/src/runtime/cgocall.go:132 +0xfa fp=0xc4200e9c30 sp=0xc4200e9bf0
github.com/aarzilli/golua/lua._Cfunc_lua_pcall(0x7f74f8006200, 0xffffffff00000000, 0x2, 0x0)
        github.com/aarzilli/golua/lua/_obj/_cgo_gotypes.go:1103 +0x4d fp=0xc4200e9c78 sp=0xc4200e9c30
github.com/aarzilli/golua/lua.(*State).pcall.func1(0x7f74f8006200, 0xffffffff00000000, 0x7f7400000002, 0x2)
        /home/tassadar/chadron-server/src/github.com/aarzilli/golua/lua/lua.go:179 +0x78 fp=0xc4200e9cb0 sp=0xc4200e9c78
github.com/aarzilli/golua/lua.(*State).pcall(0xc420018680, 0x0, 0xffffffffffffffff, 0x2, 0x558590)
        /home/tassadar/chadron-server/src/github.com/aarzilli/golua/lua/lua.go:179 +0x49 fp=0xc4200e9ce0 sp=0xc4200e9cb0
github.com/aarzilli/golua/lua.(*State).callEx(0xc420018680, 0x0, 0xffffffffffffffff, 0x14a2b01, 0x0, 0x0)
        /home/tassadar/chadron-server/src/github.com/aarzilli/golua/lua/lua.go:198 +0xe3 fp=0xc4200e9d58 sp=0xc4200e9ce0
github.com/aarzilli/golua/lua.(*State).Call(0xc420018680, 0x0, 0xffffffffffffffff, 0x0, 0x0)
        /home/tassadar/chadron-server/src/github.com/aarzilli/golua/lua/lua.go:211 +0x44 fp=0xc4200e9d98 sp=0xc4200e9d58
github.com/aarzilli/golua/lua.(*State).DoString(0xc420018680, 0x5bbc34, 0xb3, 0x0, 0x0)
        /home/tassadar/chadron-server/src/github.com/aarzilli/golua/lua/lauxlib.go:107 +0x190 fp=0xc4200e9e08 sp=0xc4200e9d98
github.com/stevedonovan/luar.TestTypeDiscipline(0xc4200a2410)
        /home/tassadar/chadron-server/src/github.com/stevedonovan/luar/luar_test.go:684 +0x339 fp=0xc4200e9fa8 sp=0xc4200e9e08
testing.tRunner(0xc4200a2410, 0x5bc978)
        /usr/local/go1.8/src/testing/testing.go:657 +0x96 fp=0xc4200e9fd0 sp=0xc4200e9fa8
runtime.goexit()
        /usr/local/go1.8/src/runtime/asm_amd64.s:2197 +0x1 fp=0xc4200e9fd8 sp=0xc4200e9fd0
created by testing.(*T).Run
        /usr/local/go1.8/src/testing/testing.go:697 +0x2ca

goroutine 1 [chan receive]:
testing.(*T).Run(0xc4200a2270, 0x5b3833, 0x12, 0x5bc978, 0x88a301)
        /usr/local/go1.8/src/testing/testing.go:698 +0x2f4
testing.runTests.func1(0xc4200a2270)
        /usr/local/go1.8/src/testing/testing.go:882 +0x67
testing.tRunner(0xc4200a2270, 0xc4200e9de0)
        /usr/local/go1.8/src/testing/testing.go:657 +0x96
testing.runTests(0xc42000cbe0, 0x877e20, 0x16, 0x16, 0xc42001c780)
        /usr/local/go1.8/src/testing/testing.go:888 +0x2c1
testing.(*M).Run(0xc42003df20, 0xc4200e9f20)
        /usr/local/go1.8/src/testing/testing.go:822 +0xfc
main.main()
        github.com/stevedonovan/luar/_test/_testmain.go:138 +0xf7

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
        /usr/local/go1.8/src/runtime/asm_amd64.s:2197 +0x1
FAIL    github.com/stevedonovan/luar    0.053s

This is likely due to reflect.Value containing pointers to Go-allocated values. With GODEBUG=cgocheck=2:

tassadar@dorea:~/chadron-server/bin$ GODEBUG=cgocheck=2  GOGC=1 GOROOT=/usr/local/go1.8/ /usr/local/go1.8/bin/go test github.com/stevedonovan/luar
write of Go pointer 0xc4200100e0 to non-Go memory 0x7f2b24008f70
fatal error: Go pointer stored into non-Go memory

runtime stack:
runtime.throw(0x5b83fb, 0x24)
        /usr/local/go1.8/src/runtime/panic.go:596 +0x95
runtime.cgoCheckWriteBarrier.func1()
        /usr/local/go1.8/src/runtime/cgocheck.go:44 +0xb8
runtime.systemstack(0xc420026000)
        /usr/local/go1.8/src/runtime/asm_amd64.s:327 +0x79
runtime.mstart()
        /usr/local/go1.8/src/runtime/proc.go:1132

goroutine 34 [running]:
runtime.systemstack_switch()
        /usr/local/go1.8/src/runtime/asm_amd64.s:281 fp=0xc420043ac8 sp=0xc420043ac0
runtime.cgoCheckWriteBarrier(0x7f2b24008f70, 0xc4200100e0)
        /usr/local/go1.8/src/runtime/cgocheck.go:45 +0xb6 fp=0xc420043b00 sp=0xc420043ac8
runtime.writebarrierptr(0x7f2b24008f70, 0xc4200100e0)
        /usr/local/go1.8/src/runtime/mbarrier.go:199 +0xcc fp=0xc420043b38 sp=0xc420043b00
github.com/stevedonovan/luar.makeValueProxy(0xc4200188c0, 0x5766a0, 0xc4200100e0, 0x82, 0x5b1fdc, 0xb)
        /home/tassadar/chadron-server/src/github.com/stevedonovan/luar/proxy.go:118 +0x31b fp=0xc420043b98 sp=0xc420043b38
github.com/stevedonovan/luar.goToLua(0xc4200188c0, 0x0, 0x0, 0x5766a0, 0xc4200100e0, 0x82, 0x52e300, 0xc4200188c0, 0x1)
        /home/tassadar/chadron-server/src/github.com/stevedonovan/luar/luar.go:484 +0xe9b fp=0xc420043c40 sp=0xc420043b98
github.com/stevedonovan/luar.GoToLua(0xc4200188c0, 0x0, 0x0, 0x5766a0, 0xc4200100e0, 0x82, 0xc420043d00)
        /home/tassadar/chadron-server/src/github.com/stevedonovan/luar/luar.go:454 +0xaa fp=0xc420043ca8 sp=0xc420043c40
github.com/stevedonovan/luar.Register(0xc4200188c0, 0x5b0827, 0x4, 0xc4200163c0)
        /home/tassadar/chadron-server/src/github.com/stevedonovan/luar/luar.go:901 +0x120 fp=0xc420043d68 sp=0xc420043ca8
github.com/stevedonovan/luar.Init(0xc420010278)
        /home/tassadar/chadron-server/src/github.com/stevedonovan/luar/luar.go:1194 +0x776 fp=0xc420043de0 sp=0xc420043d68
github.com/stevedonovan/luar.TestGoFunCall(0xc4200ae1a0)
        /home/tassadar/chadron-server/src/github.com/stevedonovan/luar/luar_test.go:80 +0xe3 fp=0xc420043fa8 sp=0xc420043de0
testing.tRunner(0xc4200ae1a0, 0x5bc8f8)
        /usr/local/go1.8/src/testing/testing.go:657 +0x96 fp=0xc420043fd0 sp=0xc420043fa8
runtime.goexit()
        /usr/local/go1.8/src/runtime/asm_amd64.s:2197 +0x1 fp=0xc420043fd8 sp=0xc420043fd0
created by testing.(*T).Run
        /usr/local/go1.8/src/testing/testing.go:697 +0x2ca

goroutine 1 [chan receive]:
testing.(*T).Run(0xc4200ae0d0, 0x5b263f, 0xd, 0x5bc8f8, 0x88a380)
        /usr/local/go1.8/src/testing/testing.go:698 +0x2f4
testing.runTests.func1(0xc4200ae0d0)
        /usr/local/go1.8/src/testing/testing.go:882 +0x67
testing.tRunner(0xc4200ae0d0, 0xc4200d5de0)
        /usr/local/go1.8/src/testing/testing.go:657 +0x96
testing.runTests(0xc42000c480, 0x877e20, 0x16, 0x16, 0xc42001c280)
        /usr/local/go1.8/src/testing/testing.go:888 +0x2c1
testing.(*M).Run(0xc4200d5f20, 0xc4200d5f20)
        /usr/local/go1.8/src/testing/testing.go:822 +0xfc
main.main()
        github.com/stevedonovan/luar/_test/_testmain.go:138 +0xf7

goroutine 17 [syscall, locked to thread]:
runtime.goexit()
        /usr/local/go1.8/src/runtime/asm_amd64.s:2197 +0x1
FAIL    github.com/stevedonovan/luar    0.012s

On the usefulness of 't', the type argument in GoToLua

I've been working on simplifying the GoToLua function which I've always found much too complex for what it does.
It turns out that the test suite passes when I set t = val.Type() at the beginning. In other words, none of the tests force the type.

What was the original intention? What does "forcing the type" even mean? The type switch does not seem to force anything.

Cannot install on mac 10.9?

Hi,
I'm trying to install luar on mac 10.9 using go get, but it fails with a clang error:

~$ go get github.com/stevedonovan/luar
# github.com/aarzilli/golua/lua
clang: error: argument unused during compilation: '-fno-eliminate-unused-debug-types'

However, I do see a bunch of relevant folders and files in my GOPATH folder.

I'm using 10.9 with clang 5.0 (LLVM 3.3):

~$ clang -v
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
Target: x86_64-apple-darwin13.0.0
Thread model: posix

Go and LUA are installed with homebrew:

~$ brew info go
go: stable 1.1.2, devel 1.2rc2, HEAD
http://golang.org
/usr/local/Cellar/go/1.1.2 (3897 files, 109M) *
[...]

~$ brew info lua
lua: stable 5.1.5
http://www.lua.org/
/usr/local/Cellar/lua/5.1.5 (15 files, 288K) *
[...]

Thanks!

proxyMap race

The:
var proxyMap = map[*valueProxy]reflect.Value{}
is used unprotected, so multiple concurrent Lua environments can corrupt it. I have submitted pull-request for that, but the ultimate solution is to Unite lua.State and proxyMap for that state in luar.State object, and passing around that object. Unfortunately functions like map__pairs, and slice__ipairs, doesn't make this straight forward to make. Since you are more familiar with the library, can you make the needed refactoring. Thank you for the wonderful project.

Non-exported fields in struct proxies

Luar allows for reading non-exported fields in struct proxies, but not for setting them (it will panic, that's Go's rule). I find this confusing and I think we should hide non-exported fields.

Any comment on that?

Need a `luar.null` value

Slices and Maps may contain nil values, but corresponding Lua tables cannot. So luar should use a unique placeholder and ensure that it is available to Lua as luar.null. This isn't a problem with proxies (which mostly behave like their Go counterparts) but when copying slices and maps to Lua tables.

Support cycle detection

In Go, a cycle within a linked list will yield an infinite loop when converted to Lua.
In Lua, a table containing a cycle will yield an infinite loop when converted to Go.

Can we perform cycle detection one way or another?

varargs -- from Lua, calling Go functions with variable argument count

Well Luar is pretty awesome. I'm really finding it fantastic.

One thing I'm puzzling over at the moment is how to call vararg functions.

For example, given

func SummerAny(a ...int) int {                                                                  
    tot := 0                                                                                    
    for i := range a {                                                                          
        tot += a[i]                                                                             
    }                                                                                           
    return tot                                                                                  
}  

... inside some Go code

    luar.Register(ic.vm, "fmt", luar.Map{                                                       
        "SummerAny": SummerAny,                                                                 
    })   

I've got a Go function, SummerAny that takes a variable number of arguments. I'm trying to call SummerAny from Lua (LuaJIT really, but they are binary compatible). So if I try to pass an array like this:

> print(fmt.SummerAny({1,2,3,4}))  

then luar complains

cannot convert Go function argument #1: cannot convert Lua value 'table: %!p(uintptr=75345376)' (table) to int

If anyone has any suggestions or ideas about how to make this work, I'm open.

pairs/ipairs proxies crash under non-main coroutine

minimized reproducer, under LuaJIT 2.1.0-beta3, on darwin OSX, amd64, go1.9.1

raw luajit gi> coroutine.resume(coroutine.create(function() for i,k in pairs({hello="world"}) do end; end))
error from Lua vm.Call(0,0): '[string "coroutine.resume(coroutine.create(function() ..."]:1: bad argument #1 to 'resume' (table expected, got thread)'. supplied lua with: 'coroutine.resume(coroutine.create(function() for i,k in pairs({hello="world"}) do end; end)'
lua stack:

========== begin DumpLuaStack: top = 1
DumpLuaStack: i=1, t= 4
 String :   [string "coroutine.resume(coroutine.create(function() ..."]:1: bad argument #1 to 'resume' (table expected, got thread)
========= end of DumpLuaStack

raw luajit gi>

if I turn off the pairs proxy, no problem:

raw luajit gi> coroutine.resume(coroutine.create(function() for i,k in pairs({hello="world"}) do end; end))

elapsed: '35.82µs'
raw luajit gi>

similary, with the ipairs proxy in place, crash:

raw luajit gi> coroutine.resume(coroutine.create(function() for i,k in ipairs({[1]="world"}) do end; end))
fatal error: unexpected signal during runtime execution
[signal SIGSEGV: segmentation violation code=0x1 addr=0x104ce5828 pc=0x44b8650]

runtime stack:
runtime.throw(0x4624309, 0x2a)
    /usr/local/go/src/runtime/panic.go:605 +0x95
runtime.sigpanic()
    /usr/local/go/src/runtime/signal_unix.go:351 +0x2b8

goroutine 1 [syscall, locked to thread]:
runtime.cgocall(0x44b5a00, 0xc42005bb20, 0x42a0100)
    /usr/local/go/src/runtime/cgocall.go:132 +0xe4 fp=0xc42005bad8 sp=0xc42005ba98 pc=0x4004414
github.com/gijit/gi/vendor/github.com/glycerine/golua/lua._Cfunc_lua_pcall(0x4c80378, 0x0, 0x1, 0x0)
    github.com/gijit/gi/vendor/github.com/glycerine/golua/lua/_obj/_cgo_gotypes.go:1191 +0x4d fp=0xc42005bb20 sp=0xc42005bad8 pc=0x42a585d
github.com/gijit/gi/vendor/github.com/glycerine/golua/lua.(*State).pcall.func1(0x4c80378, 0x0, 0x1, 0x1)
    /Users/jaten/go/src/github.com/gijit/gi/vendor/github.com/glycerine/golua/lua/lua.go:176 +0x78 fp=0xc42005bb58 sp=0xc42005bb20 pc=0x42af978
github.com/gijit/gi/vendor/github.com/glycerine/golua/lua.(*State).pcall(0xc420067800, 0x0, 0x0, 0x1, 0x44b4c10)
    /Users/jaten/go/src/github.com/gijit/gi/vendor/github.com/glycerine/golua/lua/lua.go:176 +0x49 fp=0xc42005bb88 sp=0xc42005bb58 pc=0x42aae19
...

without the ipairs proxy, no crash:

raw luajit gi> coroutine.resume(coroutine.create(function() for i,k in ipairs({[1]="world"}) do end; end))

elapsed: '30.906µs'
raw luajit gi>

example of how to receive on a channel

I see hints in the luar.go code that channels are supported, but I don't fully get how to do that in lua code. If it isn't too much trouble, a simple example of how to send from go on a channel and receive in lua (and vice-versa) would be super helpful.

Thanks!

Jason

Better proxy__tostring

Instead of type, print stringer value.

- L.PushString(obj.Type().String())
+ L.PushString(fmt.Sprintf("%v", obj))

See bitwalker@5d52c02

This seems better. Question is: why did we print the type in the first place?

Use of `luar.value`?

At the end of Init(), reflect.ValueOf gets registered to the luar.value function.
Any use for that? I cannot see the need for it.

Could move ProxyIpairs to luar table?

ProxyIpairs, ProxyPairs replace Lua original ipairs and pairs functions, it impact on performance so much. pairs and ipairs be invoked in Lua on high frequence.
so, ProxyIpairs, ProxyPairs move to luar table may be better?

Simple whitelisting?

My use-case (as I understand it's a common one) for go+lua is to let external users write their own code.

I'm pretty new to LUA but it looks like by default the engine exposes the OS & debug builtins, etc.

Is there a straightforward way to whitelist what's available?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.