1
2===============================================================================
3GopherLua: VM and compiler for Lua in Go.
4===============================================================================
5
6.. image:: https://godoc.org/github.com/yuin/gopher-lua?status.svg
7 :target: http://godoc.org/github.com/yuin/gopher-lua
8
9.. image:: https://travis-ci.org/yuin/gopher-lua.svg
10 :target: https://travis-ci.org/yuin/gopher-lua
11
12.. image:: https://coveralls.io/repos/yuin/gopher-lua/badge.svg
13 :target: https://coveralls.io/r/yuin/gopher-lua
14
15.. image:: https://badges.gitter.im/Join%20Chat.svg
16 :alt: Join the chat at https://gitter.im/yuin/gopher-lua
17 :target: https://gitter.im/yuin/gopher-lua?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
18
19|
20
21
22GopherLua is a Lua5.1 VM and compiler written in Go. GopherLua has a same goal
23with Lua: **Be a scripting language with extensible semantics** . It provides
24Go APIs that allow you to easily embed a scripting language to your Go host
25programs.
26
27.. contents::
28 :depth: 1
29
30----------------------------------------------------------------
31Design principle
32----------------------------------------------------------------
33
34- Be a scripting language with extensible semantics.
35- User-friendly Go API
36 - The stack based API like the one used in the original Lua
37 implementation will cause a performance improvements in GopherLua
38 (It will reduce memory allocations and concrete type <-> interface conversions).
39 GopherLua API is **not** the stack based API.
40 GopherLua give preference to the user-friendliness over the performance.
41
42----------------------------------------------------------------
43How about performance?
44----------------------------------------------------------------
45GopherLua is not fast but not too slow, I think.
46
47GopherLua has almost equivalent ( or little bit better ) performance as Python3 on micro benchmarks.
48
49There are some benchmarks on the `wiki page <https://github.com/yuin/gopher-lua/wiki/Benchmarks>`_ .
50
51----------------------------------------------------------------
52Installation
53----------------------------------------------------------------
54
55.. code-block:: bash
56
57 go get github.com/yuin/gopher-lua
58
59GopherLua supports >= Go1.9.
60
61----------------------------------------------------------------
62Usage
63----------------------------------------------------------------
64GopherLua APIs perform in much the same way as Lua, **but the stack is used only
65for passing arguments and receiving returned values.**
66
67GopherLua supports channel operations. See **"Goroutines"** section.
68
69Import a package.
70
71.. code-block:: go
72
73 import (
74 "github.com/yuin/gopher-lua"
75 )
76
77Run scripts in the VM.
78
79.. code-block:: go
80
81 L := lua.NewState()
82 defer L.Close()
83 if err := L.DoString(`print("hello")`); err != nil {
84 panic(err)
85 }
86
87.. code-block:: go
88
89 L := lua.NewState()
90 defer L.Close()
91 if err := L.DoFile("hello.lua"); err != nil {
92 panic(err)
93 }
94
95Refer to `Lua Reference Manual <http://www.lua.org/manual/5.1/>`_ and `Go doc <http://godoc.org/github.com/yuin/gopher-lua>`_ for further information.
96
97Note that elements that are not commented in `Go doc <http://godoc.org/github.com/yuin/gopher-lua>`_ equivalent to `Lua Reference Manual <http://www.lua.org/manual/5.1/>`_ , except GopherLua uses objects instead of Lua stack indices.
98
99~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
100Data model
101~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
102All data in a GopherLua program is an ``LValue`` . ``LValue`` is an interface
103type that has following methods.
104
105- ``String() string``
106- ``Type() LValueType``
107
108
109Objects implement an LValue interface are
110
111================ ========================= ================== =======================
112 Type name Go type Type() value Constants
113================ ========================= ================== =======================
114 ``LNilType`` (constants) ``LTNil`` ``LNil``
115 ``LBool`` (constants) ``LTBool`` ``LTrue``, ``LFalse``
116 ``LNumber`` float64 ``LTNumber`` ``-``
117 ``LString`` string ``LTString`` ``-``
118 ``LFunction`` struct pointer ``LTFunction`` ``-``
119 ``LUserData`` struct pointer ``LTUserData`` ``-``
120 ``LState`` struct pointer ``LTThread`` ``-``
121 ``LTable`` struct pointer ``LTTable`` ``-``
122 ``LChannel`` chan LValue ``LTChannel`` ``-``
123================ ========================= ================== =======================
124
125You can test an object type in Go way(type assertion) or using a ``Type()`` value.
126
127.. code-block:: go
128
129 lv := L.Get(-1) // get the value at the top of the stack
130 if str, ok := lv.(lua.LString); ok {
131 // lv is LString
132 fmt.Println(string(str))
133 }
134 if lv.Type() != lua.LTString {
135 panic("string required.")
136 }
137
138.. code-block:: go
139
140 lv := L.Get(-1) // get the value at the top of the stack
141 if tbl, ok := lv.(*lua.LTable); ok {
142 // lv is LTable
143 fmt.Println(L.ObjLen(tbl))
144 }
145
146Note that ``LBool`` , ``LNumber`` , ``LString`` is not a pointer.
147
148To test ``LNilType`` and ``LBool``, You **must** use pre-defined constants.
149
150.. code-block:: go
151
152 lv := L.Get(-1) // get the value at the top of the stack
153
154 if lv == lua.LTrue { // correct
155 }
156
157 if bl, ok := lv.(lua.LBool); ok && bool(bl) { // wrong
158 }
159
160In Lua, both ``nil`` and ``false`` make a condition false. ``LVIsFalse`` and ``LVAsBool`` implement this specification.
161
162.. code-block:: go
163
164 lv := L.Get(-1) // get the value at the top of the stack
165 if lua.LVIsFalse(lv) { // lv is nil or false
166 }
167
168 if lua.LVAsBool(lv) { // lv is neither nil nor false
169 }
170
171Objects that based on go structs(``LFunction``. ``LUserData``, ``LTable``)
172have some public methods and fields. You can use these methods and fields for
173performance and debugging, but there are some limitations.
174
175- Metatable does not work.
176- No error handlings.
177
178~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
179Callstack & Registry size
180~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
181The size of an ``LState``'s callstack controls the maximum call depth for Lua functions within a script (Go function calls do not count).
182
183The registry of an ``LState`` implements stack storage for calling functions (both Lua and Go functions) and also for temporary variables in expressions. Its storage requirements will increase with callstack usage and also with code complexity.
184
185Both the registry and the callstack can be set to either a fixed size or to auto size.
186
187When you have a large number of ``LStates`` instantiated in a process, it's worth taking the time to tune the registry and callstack options.
188
189+++++++++
190Registry
191+++++++++
192
193The registry can have an initial size, a maximum size and a step size configured on a per ``LState`` basis. This will allow the registry to grow as needed. It will not shrink again after growing.
194
195.. code-block:: go
196
197 L := lua.NewState(lua.Options{
198 RegistrySize: 1024 * 20, // this is the initial size of the registry
199 RegistryMaxSize: 1024 * 80, // this is the maximum size that the registry can grow to. If set to `0` (the default) then the registry will not auto grow
200 RegistryGrowStep: 32, // this is how much to step up the registry by each time it runs out of space. The default is `32`.
201 })
202 defer L.Close()
203
204A registry which is too small for a given script will ultimately result in a panic. A registry which is too big will waste memory (which can be significant if many ``LStates`` are instantiated).
205Auto growing registries incur a small performance hit at the point they are resized but will not otherwise affect performance.
206
207+++++++++
208Callstack
209+++++++++
210
211The callstack can operate in two different modes, fixed or auto size.
212A fixed size callstack has the highest performance and has a fixed memory overhead.
213An auto sizing callstack will allocate and release callstack pages on demand which will ensure the minimum amount of memory is in use at any time. The downside is it will incur a small performance impact every time a new page of callframes is allocated.
214By default an ``LState`` will allocate and free callstack frames in pages of 8, so the allocation overhead is not incurred on every function call. It is very likely that the performance impact of an auto resizing callstack will be negligible for most use cases.
215
216.. code-block:: go
217
218 L := lua.NewState(lua.Options{
219 CallStackSize: 120, // this is the maximum callstack size of this LState
220 MinimizeStackMemory: true, // Defaults to `false` if not specified. If set, the callstack will auto grow and shrink as needed up to a max of `CallStackSize`. If not set, the callstack will be fixed at `CallStackSize`.
221 })
222 defer L.Close()
223
224++++++++++++++++
225Option defaults
226++++++++++++++++
227
228The above examples show how to customize the callstack and registry size on a per ``LState`` basis. You can also adjust some defaults for when options are not specified by altering the values of ``lua.RegistrySize``, ``lua.RegistryGrowStep`` and ``lua.CallStackSize``.
229
230An ``LState`` object that has been created by ``*LState#NewThread()`` inherits the callstack & registry size from the parent ``LState`` object.
231
232~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
233Miscellaneous lua.NewState options
234~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
235- **Options.SkipOpenLibs bool(default false)**
236 - By default, GopherLua opens all built-in libraries when new LState is created.
237 - You can skip this behaviour by setting this to ``true`` .
238 - Using the various `OpenXXX(L *LState) int` functions you can open only those libraries that you require, for an example see below.
239- **Options.IncludeGoStackTrace bool(default false)**
240 - By default, GopherLua does not show Go stack traces when panics occur.
241 - You can get Go stack traces by setting this to ``true`` .
242
243~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
244API
245~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
246
247Refer to `Lua Reference Manual <http://www.lua.org/manual/5.1/>`_ and `Go doc(LState methods) <http://godoc.org/github.com/yuin/gopher-lua>`_ for further information.
248
249+++++++++++++++++++++++++++++++++++++++++
250Calling Go from Lua
251+++++++++++++++++++++++++++++++++++++++++
252
253.. code-block:: go
254
255 func Double(L *lua.LState) int {
256 lv := L.ToInt(1) /* get argument */
257 L.Push(lua.LNumber(lv * 2)) /* push result */
258 return 1 /* number of results */
259 }
260
261 func main() {
262 L := lua.NewState()
263 defer L.Close()
264 L.SetGlobal("double", L.NewFunction(Double)) /* Original lua_setglobal uses stack... */
265 }
266
267.. code-block:: lua
268
269 print(double(20)) -- > "40"
270
271Any function registered with GopherLua is a ``lua.LGFunction``, defined in ``value.go``
272
273.. code-block:: go
274
275 type LGFunction func(*LState) int
276
277Working with coroutines.
278
279.. code-block:: go
280
281 co, _ := L.NewThread() /* create a new thread */
282 fn := L.GetGlobal("coro").(*lua.LFunction) /* get function from lua */
283 for {
284 st, err, values := L.Resume(co, fn)
285 if st == lua.ResumeError {
286 fmt.Println("yield break(error)")
287 fmt.Println(err.Error())
288 break
289 }
290
291 for i, lv := range values {
292 fmt.Printf("%v : %v\n", i, lv)
293 }
294
295 if st == lua.ResumeOK {
296 fmt.Println("yield break(ok)")
297 break
298 }
299 }
300
301+++++++++++++++++++++++++++++++++++++++++
302Opening a subset of builtin modules
303+++++++++++++++++++++++++++++++++++++++++
304
305The following demonstrates how to open a subset of the built-in modules in Lua, say for example to avoid enabling modules with access to local files or system calls.
306
307main.go
308
309.. code-block:: go
310
311 func main() {
312 L := lua.NewState(lua.Options{SkipOpenLibs: true})
313 defer L.Close()
314 for _, pair := range []struct {
315 n string
316 f lua.LGFunction
317 }{
318 {lua.LoadLibName, lua.OpenPackage}, // Must be first
319 {lua.BaseLibName, lua.OpenBase},
320 {lua.TabLibName, lua.OpenTable},
321 } {
322 if err := L.CallByParam(lua.P{
323 Fn: L.NewFunction(pair.f),
324 NRet: 0,
325 Protect: true,
326 }, lua.LString(pair.n)); err != nil {
327 panic(err)
328 }
329 }
330 if err := L.DoFile("main.lua"); err != nil {
331 panic(err)
332 }
333 }
334
335+++++++++++++++++++++++++++++++++++++++++
336Creating a module by Go
337+++++++++++++++++++++++++++++++++++++++++
338
339mymodule.go
340
341.. code-block:: go
342
343 package mymodule
344
345 import (
346 "github.com/yuin/gopher-lua"
347 )
348
349 func Loader(L *lua.LState) int {
350 // register functions to the table
351 mod := L.SetFuncs(L.NewTable(), exports)
352 // register other stuff
353 L.SetField(mod, "name", lua.LString("value"))
354
355 // returns the module
356 L.Push(mod)
357 return 1
358 }
359
360 var exports = map[string]lua.LGFunction{
361 "myfunc": myfunc,
362 }
363
364 func myfunc(L *lua.LState) int {
365 return 0
366 }
367
368mymain.go
369
370.. code-block:: go
371
372 package main
373
374 import (
375 "./mymodule"
376 "github.com/yuin/gopher-lua"
377 )
378
379 func main() {
380 L := lua.NewState()
381 defer L.Close()
382 L.PreloadModule("mymodule", mymodule.Loader)
383 if err := L.DoFile("main.lua"); err != nil {
384 panic(err)
385 }
386 }
387
388main.lua
389
390.. code-block:: lua
391
392 local m = require("mymodule")
393 m.myfunc()
394 print(m.name)
395
396
397+++++++++++++++++++++++++++++++++++++++++
398Calling Lua from Go
399+++++++++++++++++++++++++++++++++++++++++
400
401.. code-block:: go
402
403 L := lua.NewState()
404 defer L.Close()
405 if err := L.DoFile("double.lua"); err != nil {
406 panic(err)
407 }
408 if err := L.CallByParam(lua.P{
409 Fn: L.GetGlobal("double"),
410 NRet: 1,
411 Protect: true,
412 }, lua.LNumber(10)); err != nil {
413 panic(err)
414 }
415 ret := L.Get(-1) // returned value
416 L.Pop(1) // remove received value
417
418If ``Protect`` is false, GopherLua will panic instead of returning an ``error`` value.
419
420+++++++++++++++++++++++++++++++++++++++++
421User-Defined types
422+++++++++++++++++++++++++++++++++++++++++
423You can extend GopherLua with new types written in Go.
424``LUserData`` is provided for this purpose.
425
426.. code-block:: go
427
428 type Person struct {
429 Name string
430 }
431
432 const luaPersonTypeName = "person"
433
434 // Registers my person type to given L.
435 func registerPersonType(L *lua.LState) {
436 mt := L.NewTypeMetatable(luaPersonTypeName)
437 L.SetGlobal("person", mt)
438 // static attributes
439 L.SetField(mt, "new", L.NewFunction(newPerson))
440 // methods
441 L.SetField(mt, "__index", L.SetFuncs(L.NewTable(), personMethods))
442 }
443
444 // Constructor
445 func newPerson(L *lua.LState) int {
446 person := &Person{L.CheckString(1)}
447 ud := L.NewUserData()
448 ud.Value = person
449 L.SetMetatable(ud, L.GetTypeMetatable(luaPersonTypeName))
450 L.Push(ud)
451 return 1
452 }
453
454 // Checks whether the first lua argument is a *LUserData with *Person and returns this *Person.
455 func checkPerson(L *lua.LState) *Person {
456 ud := L.CheckUserData(1)
457 if v, ok := ud.Value.(*Person); ok {
458 return v
459 }
460 L.ArgError(1, "person expected")
461 return nil
462 }
463
464 var personMethods = map[string]lua.LGFunction{
465 "name": personGetSetName,
466 }
467
468 // Getter and setter for the Person#Name
469 func personGetSetName(L *lua.LState) int {
470 p := checkPerson(L)
471 if L.GetTop() == 2 {
472 p.Name = L.CheckString(2)
473 return 0
474 }
475 L.Push(lua.LString(p.Name))
476 return 1
477 }
478
479 func main() {
480 L := lua.NewState()
481 defer L.Close()
482 registerPersonType(L)
483 if err := L.DoString(`
484 p = person.new("Steeve")
485 print(p:name()) -- "Steeve"
486 p:name("Alice")
487 print(p:name()) -- "Alice"
488 `); err != nil {
489 panic(err)
490 }
491 }
492
493+++++++++++++++++++++++++++++++++++++++++
494Terminating a running LState
495+++++++++++++++++++++++++++++++++++++++++
496GopherLua supports the `Go Concurrency Patterns: Context <https://blog.golang.org/context>`_ .
497
498
499.. code-block:: go
500
501 L := lua.NewState()
502 defer L.Close()
503 ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
504 defer cancel()
505 // set the context to our LState
506 L.SetContext(ctx)
507 err := L.DoString(`
508 local clock = os.clock
509 function sleep(n) -- seconds
510 local t0 = clock()
511 while clock() - t0 <= n do end
512 end
513 sleep(3)
514 `)
515 // err.Error() contains "context deadline exceeded"
516
517With coroutines
518
519.. code-block:: go
520
521 L := lua.NewState()
522 defer L.Close()
523 ctx, cancel := context.WithCancel(context.Background())
524 L.SetContext(ctx)
525 defer cancel()
526 L.DoString(`
527 function coro()
528 local i = 0
529 while true do
530 coroutine.yield(i)
531 i = i+1
532 end
533 return i
534 end
535 `)
536 co, cocancel := L.NewThread()
537 defer cocancel()
538 fn := L.GetGlobal("coro").(*LFunction)
539
540 _, err, values := L.Resume(co, fn) // err is nil
541
542 cancel() // cancel the parent context
543
544 _, err, values = L.Resume(co, fn) // err is NOT nil : child context was canceled
545
546**Note that using a context causes performance degradation.**
547
548.. code-block::
549
550 time ./glua-with-context.exe fib.lua
551 9227465
552 0.01s user 0.11s system 1% cpu 7.505 total
553
554 time ./glua-without-context.exe fib.lua
555 9227465
556 0.01s user 0.01s system 0% cpu 5.306 total
557
558+++++++++++++++++++++++++++++++++++++++++
559Sharing Lua byte code between LStates
560+++++++++++++++++++++++++++++++++++++++++
561Calling ``DoFile`` will load a Lua script, compile it to byte code and run the byte code in a ``LState``.
562
563If you have multiple ``LStates`` which are all required to run the same script, you can share the byte code between them,
564which will save on memory.
565Sharing byte code is safe as it is read only and cannot be altered by lua scripts.
566
567.. code-block:: go
568
569 // CompileLua reads the passed lua file from disk and compiles it.
570 func CompileLua(filePath string) (*lua.FunctionProto, error) {
571 file, err := os.Open(filePath)
572 defer file.Close()
573 if err != nil {
574 return nil, err
575 }
576 reader := bufio.NewReader(file)
577 chunk, err := parse.Parse(reader, filePath)
578 if err != nil {
579 return nil, err
580 }
581 proto, err := lua.Compile(chunk, filePath)
582 if err != nil {
583 return nil, err
584 }
585 return proto, nil
586 }
587
588 // DoCompiledFile takes a FunctionProto, as returned by CompileLua, and runs it in the LState. It is equivalent
589 // to calling DoFile on the LState with the original source file.
590 func DoCompiledFile(L *lua.LState, proto *lua.FunctionProto) error {
591 lfunc := L.NewFunctionFromProto(proto)
592 L.Push(lfunc)
593 return L.PCall(0, lua.MultRet, nil)
594 }
595
596 // Example shows how to share the compiled byte code from a lua script between multiple VMs.
597 func Example() {
598 codeToShare := CompileLua("mylua.lua")
599 a := lua.NewState()
600 b := lua.NewState()
601 c := lua.NewState()
602 DoCompiledFile(a, codeToShare)
603 DoCompiledFile(b, codeToShare)
604 DoCompiledFile(c, codeToShare)
605 }
606
607+++++++++++++++++++++++++++++++++++++++++
608Goroutines
609+++++++++++++++++++++++++++++++++++++++++
610The ``LState`` is not goroutine-safe. It is recommended to use one LState per goroutine and communicate between goroutines by using channels.
611
612Channels are represented by ``channel`` objects in GopherLua. And a ``channel`` table provides functions for performing channel operations.
613
614Some objects can not be sent over channels due to having non-goroutine-safe objects inside itself.
615
616- a thread(state)
617- a function
618- an userdata
619- a table with a metatable
620
621You **must not** send these objects from Go APIs to channels.
622
623
624
625.. code-block:: go
626
627 func receiver(ch, quit chan lua.LValue) {
628 L := lua.NewState()
629 defer L.Close()
630 L.SetGlobal("ch", lua.LChannel(ch))
631 L.SetGlobal("quit", lua.LChannel(quit))
632 if err := L.DoString(`
633 local exit = false
634 while not exit do
635 channel.select(
636 {"|<-", ch, function(ok, v)
637 if not ok then
638 print("channel closed")
639 exit = true
640 else
641 print("received:", v)
642 end
643 end},
644 {"|<-", quit, function(ok, v)
645 print("quit")
646 exit = true
647 end}
648 )
649 end
650 `); err != nil {
651 panic(err)
652 }
653 }
654
655 func sender(ch, quit chan lua.LValue) {
656 L := lua.NewState()
657 defer L.Close()
658 L.SetGlobal("ch", lua.LChannel(ch))
659 L.SetGlobal("quit", lua.LChannel(quit))
660 if err := L.DoString(`
661 ch:send("1")
662 ch:send("2")
663 `); err != nil {
664 panic(err)
665 }
666 ch <- lua.LString("3")
667 quit <- lua.LTrue
668 }
669
670 func main() {
671 ch := make(chan lua.LValue)
672 quit := make(chan lua.LValue)
673 go receiver(ch, quit)
674 go sender(ch, quit)
675 time.Sleep(3 * time.Second)
676 }
677
678'''''''''''''''
679Go API
680'''''''''''''''
681
682``ToChannel``, ``CheckChannel``, ``OptChannel`` are available.
683
684Refer to `Go doc(LState methods) <http://godoc.org/github.com/yuin/gopher-lua>`_ for further information.
685
686'''''''''''''''
687Lua API
688'''''''''''''''
689
690- **channel.make([buf:int]) -> ch:channel**
691 - Create new channel that has a buffer size of ``buf``. By default, ``buf`` is 0.
692
693- **channel.select(case:table [, case:table, case:table ...]) -> {index:int, recv:any, ok}**
694 - Same as the ``select`` statement in Go. It returns the index of the chosen case and, if that
695 case was a receive operation, the value received and a boolean indicating whether the channel has been closed.
696 - ``case`` is a table that outlined below.
697 - receiving: `{"|<-", ch:channel [, handler:func(ok, data:any)]}`
698 - sending: `{"<-|", ch:channel, data:any [, handler:func(data:any)]}`
699 - default: `{"default" [, handler:func()]}`
700
701``channel.select`` examples:
702
703.. code-block:: lua
704
705 local idx, recv, ok = channel.select(
706 {"|<-", ch1},
707 {"|<-", ch2}
708 )
709 if not ok then
710 print("closed")
711 elseif idx == 1 then -- received from ch1
712 print(recv)
713 elseif idx == 2 then -- received from ch2
714 print(recv)
715 end
716
717.. code-block:: lua
718
719 channel.select(
720 {"|<-", ch1, function(ok, data)
721 print(ok, data)
722 end},
723 {"<-|", ch2, "value", function(data)
724 print(data)
725 end},
726 {"default", function()
727 print("default action")
728 end}
729 )
730
731- **channel:send(data:any)**
732 - Send ``data`` over the channel.
733- **channel:receive() -> ok:bool, data:any**
734 - Receive some data over the channel.
735- **channel:close()**
736 - Close the channel.
737
738''''''''''''''''''''''''''''''
739The LState pool pattern
740''''''''''''''''''''''''''''''
741To create per-thread LState instances, You can use the ``sync.Pool`` like mechanism.
742
743.. code-block:: go
744
745 type lStatePool struct {
746 m sync.Mutex
747 saved []*lua.LState
748 }
749
750 func (pl *lStatePool) Get() *lua.LState {
751 pl.m.Lock()
752 defer pl.m.Unlock()
753 n := len(pl.saved)
754 if n == 0 {
755 return pl.New()
756 }
757 x := pl.saved[n-1]
758 pl.saved = pl.saved[0 : n-1]
759 return x
760 }
761
762 func (pl *lStatePool) New() *lua.LState {
763 L := lua.NewState()
764 // setting the L up here.
765 // load scripts, set global variables, share channels, etc...
766 return L
767 }
768
769 func (pl *lStatePool) Put(L *lua.LState) {
770 pl.m.Lock()
771 defer pl.m.Unlock()
772 pl.saved = append(pl.saved, L)
773 }
774
775 func (pl *lStatePool) Shutdown() {
776 for _, L := range pl.saved {
777 L.Close()
778 }
779 }
780
781 // Global LState pool
782 var luaPool = &lStatePool{
783 saved: make([]*lua.LState, 0, 4),
784 }
785
786Now, you can get per-thread LState objects from the ``luaPool`` .
787
788.. code-block:: go
789
790 func MyWorker() {
791 L := luaPool.Get()
792 defer luaPool.Put(L)
793 /* your code here */
794 }
795
796 func main() {
797 defer luaPool.Shutdown()
798 go MyWorker()
799 go MyWorker()
800 /* etc... */
801 }
802
803
804----------------------------------------------------------------
805Differences between Lua and GopherLua
806----------------------------------------------------------------
807~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
808Goroutines
809~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
810
811- GopherLua supports channel operations.
812 - GopherLua has a type named ``channel``.
813 - The ``channel`` table provides functions for performing channel operations.
814
815~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
816Unsupported functions
817~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
818
819- ``string.dump``
820- ``os.setlocale``
821- ``lua_Debug.namewhat``
822- ``package.loadlib``
823- debug hooks
824
825~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
826Miscellaneous notes
827~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
828
829- ``collectgarbage`` does not take any arguments and runs the garbage collector for the entire Go program.
830- ``file:setvbuf`` does not support a line buffering.
831- Daylight saving time is not supported.
832- GopherLua has a function to set an environment variable : ``os.setenv(name, value)``
833
834----------------------------------------------------------------
835Standalone interpreter
836----------------------------------------------------------------
837Lua has an interpreter called ``lua`` . GopherLua has an interpreter called ``glua`` .
838
839.. code-block:: bash
840
841 go get github.com/yuin/gopher-lua/cmd/glua
842
843``glua`` has same options as ``lua`` .
844
845----------------------------------------------------------------
846How to Contribute
847----------------------------------------------------------------
848See `Guidlines for contributors <https://github.com/yuin/gopher-lua/tree/master/.github/CONTRIBUTING.md>`_ .
849
850----------------------------------------------------------------
851Libraries for GopherLua
852----------------------------------------------------------------
853
854- `gopher-luar <https://github.com/layeh/gopher-luar>`_ : Simplifies data passing to and from gopher-lua
855- `gluamapper <https://github.com/yuin/gluamapper>`_ : Mapping a Lua table to a Go struct
856- `gluare <https://github.com/yuin/gluare>`_ : Regular expressions for gopher-lua
857- `gluahttp <https://github.com/cjoudrey/gluahttp>`_ : HTTP request module for gopher-lua
858- `gopher-json <https://github.com/layeh/gopher-json>`_ : A simple JSON encoder/decoder for gopher-lua
859- `gluayaml <https://github.com/kohkimakimoto/gluayaml>`_ : Yaml parser for gopher-lua
860- `glua-lfs <https://github.com/layeh/gopher-lfs>`_ : Partially implements the luafilesystem module for gopher-lua
861- `gluaurl <https://github.com/cjoudrey/gluaurl>`_ : A url parser/builder module for gopher-lua
862- `gluahttpscrape <https://github.com/felipejfc/gluahttpscrape>`_ : A simple HTML scraper module for gopher-lua
863- `gluaxmlpath <https://github.com/ailncode/gluaxmlpath>`_ : An xmlpath module for gopher-lua
864- `gmoonscript <https://github.com/rucuriousyet/gmoonscript>`_ : Moonscript Compiler for the Gopher Lua VM
865- `loguago <https://github.com/rucuriousyet/loguago>`_ : Zerolog wrapper for Gopher-Lua
866- `gluacrypto <https://github.com/tengattack/gluacrypto>`_ : A native Go implementation of crypto library for the GopherLua VM.
867- `gluasql <https://github.com/tengattack/gluasql>`_ : A native Go implementation of SQL client for the GopherLua VM.
868- `purr <https://github.com/leyafo/purr>`_ : A http mock testing tool.
869- `vadv/gopher-lua-libs <https://github.com/vadv/gopher-lua-libs>`_ : Some usefull libraries for GopherLua VM.
870- `gluaperiphery <https://github.com/BixData/gluaperiphery>`_ : A periphery library for the GopherLua VM (GPIO, SPI, I2C, MMIO, and Serial peripheral I/O for Linux).
871- `glua-async <https://github.com/CuberL/glua-async>`_ : An async/await implement for gopher-lua.
872- `gopherlua-debugger <https://github.com/edolphin-ydf/gopherlua-debugger>`_ : A debugger for gopher-lua
873----------------------------------------------------------------
874Donation
875----------------------------------------------------------------
876
877BTC: 1NEDSyUmo4SMTDP83JJQSWi1MvQUGGNMZB
878
879----------------------------------------------------------------
880License
881----------------------------------------------------------------
882MIT
883
884----------------------------------------------------------------
885Author
886----------------------------------------------------------------
887Yusuke Inuzuka
888