github.com/guardangely/gopher-lua@v0.0.0-20200324075529-f92e6f279f59/README.rst (about) 1 2 =============================================================================== 3 GopherLua: 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 22 GopherLua is a Lua5.1 VM and compiler written in Go. GopherLua has a same goal 23 with Lua: **Be a scripting language with extensible semantics** . It provides 24 Go APIs that allow you to easily embed a scripting language to your Go host 25 programs. 26 27 .. contents:: 28 :depth: 1 29 30 ---------------------------------------------------------------- 31 Design 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 ---------------------------------------------------------------- 43 How about performance? 44 ---------------------------------------------------------------- 45 GopherLua is not fast but not too slow, I think. 46 47 GopherLua has almost equivalent ( or little bit better ) performance as Python3 on micro benchmarks. 48 49 There are some benchmarks on the `wiki page <https://github.com/yuin/gopher-lua/wiki/Benchmarks>`_ . 50 51 ---------------------------------------------------------------- 52 Installation 53 ---------------------------------------------------------------- 54 55 .. code-block:: bash 56 57 go get github.com/yuin/gopher-lua 58 59 GopherLua supports >= Go1.9. 60 61 ---------------------------------------------------------------- 62 Usage 63 ---------------------------------------------------------------- 64 GopherLua APIs perform in much the same way as Lua, **but the stack is used only 65 for passing arguments and receiving returned values.** 66 67 GopherLua supports channel operations. See **"Goroutines"** section. 68 69 Import a package. 70 71 .. code-block:: go 72 73 import ( 74 "github.com/yuin/gopher-lua" 75 ) 76 77 Run 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 95 Refer 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 97 Note 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 100 Data model 101 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 102 All data in a GopherLua program is an ``LValue`` . ``LValue`` is an interface 103 type that has following methods. 104 105 - ``String() string`` 106 - ``Type() LValueType`` 107 108 109 Objects 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 125 You 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 146 Note that ``LBool`` , ``LNumber`` , ``LString`` is not a pointer. 147 148 To 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 160 In 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 171 Objects that based on go structs(``LFunction``. ``LUserData``, ``LTable``) 172 have some public methods and fields. You can use these methods and fields for 173 performance and debugging, but there are some limitations. 174 175 - Metatable does not work. 176 - No error handlings. 177 178 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 179 Callstack & Registry size 180 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 181 The size of an ``LState``'s callstack controls the maximum call depth for Lua functions within a script (Go function calls do not count). 182 183 The 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 185 Both the registry and the callstack can be set to either a fixed size or to auto size. 186 187 When 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 +++++++++ 190 Registry 191 +++++++++ 192 193 The 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 204 A 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). 205 Auto growing registries incur a small performance hit at the point they are resized but will not otherwise affect performance. 206 207 +++++++++ 208 Callstack 209 +++++++++ 210 211 The callstack can operate in two different modes, fixed or auto size. 212 A fixed size callstack has the highest performance and has a fixed memory overhead. 213 An 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. 214 By 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 ++++++++++++++++ 225 Option defaults 226 ++++++++++++++++ 227 228 The 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 230 An ``LState`` object that has been created by ``*LState#NewThread()`` inherits the callstack & registry size from the parent ``LState`` object. 231 232 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 233 Miscellaneous 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 244 API 245 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 246 247 Refer 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 +++++++++++++++++++++++++++++++++++++++++ 250 Calling 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 271 Any 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 277 Working 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 +++++++++++++++++++++++++++++++++++++++++ 302 Opening a subset of builtin modules 303 +++++++++++++++++++++++++++++++++++++++++ 304 305 The 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 307 main.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 +++++++++++++++++++++++++++++++++++++++++ 336 Creating a module by Go 337 +++++++++++++++++++++++++++++++++++++++++ 338 339 mymodule.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 368 mymain.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 388 main.lua 389 390 .. code-block:: lua 391 392 local m = require("mymodule") 393 m.myfunc() 394 print(m.name) 395 396 397 +++++++++++++++++++++++++++++++++++++++++ 398 Calling 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 418 If ``Protect`` is false, GopherLua will panic instead of returning an ``error`` value. 419 420 +++++++++++++++++++++++++++++++++++++++++ 421 User-Defined types 422 +++++++++++++++++++++++++++++++++++++++++ 423 You 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 +++++++++++++++++++++++++++++++++++++++++ 494 Terminating a running LState 495 +++++++++++++++++++++++++++++++++++++++++ 496 GopherLua 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 517 With 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 +++++++++++++++++++++++++++++++++++++++++ 559 Sharing Lua byte code between LStates 560 +++++++++++++++++++++++++++++++++++++++++ 561 Calling ``DoFile`` will load a Lua script, compile it to byte code and run the byte code in a ``LState``. 562 563 If you have multiple ``LStates`` which are all required to run the same script, you can share the byte code between them, 564 which will save on memory. 565 Sharing 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 +++++++++++++++++++++++++++++++++++++++++ 608 Goroutines 609 +++++++++++++++++++++++++++++++++++++++++ 610 The ``LState`` is not goroutine-safe. It is recommended to use one LState per goroutine and communicate between goroutines by using channels. 611 612 Channels are represented by ``channel`` objects in GopherLua. And a ``channel`` table provides functions for performing channel operations. 613 614 Some 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 621 You **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 ''''''''''''''' 679 Go API 680 ''''''''''''''' 681 682 ``ToChannel``, ``CheckChannel``, ``OptChannel`` are available. 683 684 Refer to `Go doc(LState methods) <http://godoc.org/github.com/yuin/gopher-lua>`_ for further information. 685 686 ''''''''''''''' 687 Lua 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 '''''''''''''''''''''''''''''' 739 The LState pool pattern 740 '''''''''''''''''''''''''''''' 741 To 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 786 Now, 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 ---------------------------------------------------------------- 805 Differences between Lua and GopherLua 806 ---------------------------------------------------------------- 807 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 808 Goroutines 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 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 816 Unsupported functions 817 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 818 819 - ``string.dump`` 820 - ``os.setlocale`` 821 - ``lua_Debug.namewhat`` 822 - ``package.loadlib`` 823 - debug hooks 824 825 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 826 Miscellaneous 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 ---------------------------------------------------------------- 835 Standalone interpreter 836 ---------------------------------------------------------------- 837 Lua 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 ---------------------------------------------------------------- 846 How to Contribute 847 ---------------------------------------------------------------- 848 See `Guidlines for contributors <https://github.com/yuin/gopher-lua/tree/master/.github/CONTRIBUTING.md>`_ . 849 850 ---------------------------------------------------------------- 851 Libraries 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 - `gluasocket <https://github.com/BixData/gluasocket>`_ : A LuaSocket library for the GopherLua VM 865 - `gluabit32 <https://github.com/BixData/gluabit32>`_ : A native Go implementation of bit32 for the GopherLua VM. 866 - `gmoonscript <https://github.com/rucuriousyet/gmoonscript>`_ : Moonscript Compiler for the Gopher Lua VM 867 - `loguago <https://github.com/rucuriousyet/loguago>`_ : Zerolog wrapper for Gopher-Lua 868 - `gluacrypto <https://github.com/tengattack/gluacrypto>`_ : A native Go implementation of crypto library for the GopherLua VM. 869 - `gluasql <https://github.com/tengattack/gluasql>`_ : A native Go implementation of SQL client for the GopherLua VM. 870 - `purr <https://github.com/leyafo/purr>`_ : A http mock testing tool. 871 - `vadv/gopher-lua-libs <https://github.com/vadv/gopher-lua-libs>`_ : Some usefull libraries for GopherLua VM. 872 - `gluaperiphery <https://github.com/BixData/gluaperiphery>`_ : A periphery library for the GopherLua VM (GPIO, SPI, I2C, MMIO, and Serial peripheral I/O for Linux). 873 - `glua-async <https://github.com/CuberL/glua-async>`_ : An async/await implement for gopher-lua. 874 - `gopherlua-debugger <https://github.com/edolphin-ydf/gopherlua-debugger>`_ : A debugger for gopher-lua 875 ---------------------------------------------------------------- 876 Donation 877 ---------------------------------------------------------------- 878 879 BTC: 1NEDSyUmo4SMTDP83JJQSWi1MvQUGGNMZB 880 881 ---------------------------------------------------------------- 882 License 883 ---------------------------------------------------------------- 884 MIT 885 886 ---------------------------------------------------------------- 887 Author 888 ---------------------------------------------------------------- 889 Yusuke Inuzuka