Giter Site home page Giter Site logo

gopher-lua's Issues

I want to write a web framework module that can be called by gopher-lua, but some problems are encountered.

  • [YES] GopherLua is a Lua5.1 implementation. You should be familiar with Lua programming language. Have you read Lua 5.1 reference manual carefully?
  • [YES] GopherLua is a Lua5.1 implementation. In Lua, to keep it simple, it is more important to remove functionalities rather than to add functionalities unlike other languages . If you are going to introduce some new cool functionalities into the GopherLua code base and the functionalities can be implemented by existing APIs, It should be implemented as a library.

Please answer the following before submitting your issue:

  1. What version of GopherLua are you using? :
    lastest version
  2. What version of Go are you using? :
    Go 1.7.3
  3. What operating system and processor architecture are you using? :
    Linux (Ubuntu 14.04) 64bit
  4. What did you do? :
    I want to write a web framework module that can be called by gopher-lua.
  5. What did you expect to see? :
    Web framework in the normal work of gopher-lua
  6. What did you see instead? :
    Long time access (Press F5) or wrk stress tests will die

This is the test code:

package main

import (
    "fmt"
    "sync"
    "github.com/hoisie/web"
    lua "github.com/yuin/gopher-lua"
)

type lStatePool struct {
    m     sync.Mutex
    saved []*lua.LState
}

func (pl *lStatePool) Get() *lua.LState {
    pl.m.Lock()
    defer pl.m.Unlock()
    n := len(pl.saved)
    if n == 0 {
        return pl.New()
    }
    x := pl.saved[n-1]
    pl.saved = pl.saved[0 : n-1]
    return x
}

func (pl *lStatePool) New() *lua.LState {
    L := lua.NewState(lua.Options{
        IncludeGoStackTrace: true,
    })
    // setting the L up here.
    // load scripts, set global variables, share channels, etc...
    L.PreloadModule("web", Loader)

    return L
}

func (pl *lStatePool) Put(L *lua.LState) {
    pl.m.Lock()
    defer pl.m.Unlock()
    pl.saved = append(pl.saved, L)
}

func (pl *lStatePool) Shutdown() {
    for _, L := range pl.saved {
        L.Close()
    }
}

// Global LState pool
var luaPool = &lStatePool{
    saved: make([]*lua.LState, 0, 4),
}

func main() {

    defer func() {
        luaPool.Shutdown()
    }()
    /*
        L := lua.NewState(lua.Options{
            IncludeGoStackTrace: true,
        })
        defer L.Close()

        L.PreloadModule("web", Loader)
    */
    go vm()

    for {}
}

func vm() {
    L := luaPool.Get()
    defer luaPool.Put(L)
    if err := L.DoString(`
local web = require("web")
print("lua>> web", web.version)

print("lua>> web.app()")
local app = web.app()
local hello = 0
print("lua>> web.app:get()")
app:get("/", function ()
    hello = hello + 1
    print("lua>print:",hello)
    return ctx.render(hello)
end)

print("lua>> web.app:listen()")
app:listen("0.0.0.0", "8000")
`); err != nil {
        panic(err)
    }
}

//----------------------------------------------------//

const (
    lContextTypeName = "context"
    lAppClassName    = "App"
)

var exports = map[string]lua.LGFunction{
    "app": app,
}

var appMethods = map[string]lua.LGFunction{
    "get":    get,
    "listen": listen,
}

func Loader(L *lua.LState) int {
    mod := L.SetFuncs(L.NewTable(), exports)
    L.SetField(mod, "version", lua.LString("0.0.1"))

    // returns the module
    L.Push(mod)

    mod2 := L.SetFuncs(L.NewTable(), selfMethods)
    L.SetGlobal("ctx", mod2)

    // returns the module
    L.Push(mod2)
    return 2
}

var selfMethods = map[string]lua.LGFunction{
    "render": render,
}

func render(L *lua.LState) int {
    s := L.CheckNumber(1)
    L.Push(lua.LNumber(s))
    return 1
}

func app(L *lua.LState) int {

    mt := L.NewTypeMetatable(lAppClassName)
    mt.RawSetString("__index", mt)
    L.SetFuncs(mt, appMethods)

    s := web.NewServer()
    ud := L.NewUserData()
    ud.Value = s
    L.SetMetatable(ud, L.GetTypeMetatable(lAppClassName))
    L.Push(ud)
    return 1

}

func checkServer(L *lua.LState) *web.Server {
    fmt.Println("L.GetTop():", L.GetTop())
    ud := L.CheckUserData(1)
    if v, ok := ud.Value.(*web.Server); ok {
        return v
    }
    L.ArgError(1, "*web.Server expected")
    return nil
}

func get(L *lua.LState) int {
    s := checkServer(L)

    path := L.CheckString(2)
    fn := L.CheckFunction(3)
    s.Get(path, func(self *web.Context) {
        L.Push(fn)
        L.Call(0, 1)
        hello := L.CheckNumber(L.GetTop())
        self.WriteString(hello.String())
    })
    return 0
}

func listen(L *lua.LState) int {

    s := checkServer(L)
    host := L.CheckString(2)
    port := L.CheckString(3)
    addr := fmt.Sprintf("%v:%v", host, port)

    s.Run(addr)
    return 0

}

Best way to set LUA_PATH?

Hi,
I love working with gopher-lua so far. The documentation is lacking tough.
What would be the best way to set the LUA_PATH? In order to load modules from subdirectories located relative to the executed .lua file, I need to set it to the directory of that .lua file.
I discovered that the Lua vm uses system env variables set via os.Setenv(). Is there a way to set / append to the LUA_PATH just for one vm (e.g. vm.Setenv())?

Thanks

Weird memory leak

Im currently running a simple LUA script with a module

func (c *CharacterModule) characterDeaths(L *lua.LState) int {
    name := L.ToString(1)
    deaths, err := models.GetCharacterDeaths(name)
    if err != nil {
        L.Push(lua.LString(err.Error()))
        L.Push(lua.LNil)
        return 2
    }
    death_list := &lua.LTable{}
    for _, val := range deaths {
        t := &lua.LTable{}
        t.RawSetString("time", lua.LNumber(val.Time))
        t.RawSetString("level", lua.LNumber(val.Level))
        t.RawSetString("killed_by", lua.LString(val.Killed_by))
        t.RawSetString("most_damage_by", lua.LString(val.Mostdamage_by))
        death_list.Append(t)
    }
    L.Push(lua.LBool(true))
    L.Push(death_list)
    return 2
}
local character_module = require("character")
local errorx, deaths = character_module.getCharacterDeaths("Kassem G")
if(errorx ~= true) then
    return false
end
local template = {}
template["list"] = {}
template["list"]["killed_by"] = "load test"
return template

Im using a http load test tool and at a certain points my app goes from 0-1% CPU usage to 50%
Im doing something wrong while creating the lua table?

Im sure the error is in the getCharacterDeaths function since removing it makes my CPU usage go quiet

Also im sure its not this part

models.GetCharacterDeaths(name)

Since I teste that one alone and nothing happened

So maybe im missing something while working with lua tables?

Golang packages

Hi,

I want integrate it on my project:
https://github.com/prsolucoes/goci

It is a continuous integration system that use script files to make the build steps. I want use LUA now. How i can export some Go packages to this implementation? How multiple return works in this LUA implementation?

Thanks.

Format error in baseLoadFile

The baseLoadFile function in baselib.go is using the incorrect Sprint version of the fmt package.

L.Push(LString(fmt.Sprint("can not open file: %v", chunkname)))

Should either be:

L.Push(LString(fmt.Sprintf("can not open file: %v", chunkname)))

or:

L.Push(LString(fmt.Sprint("can not open file:", chunkname)))

pcall doesn't work in conjection with coroutines.

It seems that coroutines and pcalls don't quite work right when nested. I'm not sure why it is, but pcalls and coroutine don't play nice together.

This is a complete example program, that reproduces the problem. It should be spitting out several Tick: lines, instead it's spitting nothing out at all.

If you comment out the pcall stuff, it functions as expected.

package main

import (
    "fmt"

    "github.com/yuin/gopher-lua"
)

func main() {
    state := lua.NewState()
    state.OpenLibs()

    main, err := state.LoadString(threadLua)
    if err != nil {
        panic(err)
    }

    thread := state.NewThread()

    s, err, _ := state.Resume(thread, main)
    if err != nil {
        panic(err)
    }

    for i := 0; i < 20; i++ {
        if s != lua.ResumeError {
            s, err, _ = state.Resume(thread, main, lua.LString("tick"), lua.LNumber(i))

            if err != nil {
                fmt.Println("Error: ", err)

                break
            }
        }
    }
}

var threadLua = `
local ok, err = pcall(
  function()
    local evt, n = coroutine.yield()

        print("Tick: " .. n)

    if n > 10 then
      error("N is > 10")
    end
  end)

if not ok then
  print("Got Error: " .. err)
  error("Dying.")
end
`

Table index 0 causes infinite loop

The following code causes an infinite loop for me on master/Go 1.7/Linux:

local tbl = {
        [-1] = "a",
        [0] = "b",
        [1] = "c",
}
for k, v in pairs(tbl) do
        print(k, v)
end

Output:

-1      a
0       b
1       c
-1      a
0       b
1       c
... and so on

It only happens with numeric zero (not string). I know Lua indexing starts with 1 instead of 0. But in some calculations a zero may be stored in tables, and this loop does not happen in reference Lua 5.1.

Minimal test case:

local tbl = { [0] = true }
assert(next(tbl, 0) == nil) -- should be nil, but is 0

Problem to Add nested LTable in LTable

When using RawSet function to add a LTable inside another LTable, I got error like

cannot use *llTable (type lua.LTable) as type lua.LValue in argument to ltable.RawSet: lua.LTable does not implement lua.LValue (String method has pointer receiver)

but I see lua.LTable do implement lua.LValue interface. any idea?

Does not work `LState.Close()` after `os.Exit()`

Hello yuin.

defer doesn't run when you use os.Exit() to terminate a process.
Therefore, LState.Close() doesn't run in some cases.

This behavior causes an issue. For instance. A temporary file that is created by io.tmpfile() is not deleted automatically by using glua. Please see the following steps.

Create test.lua

-- test.lua
local t = io.tmpfile()
t:write("This is a tempfile.")

Run the test.lua file by glua.

glua test.lua

Look for the file. At my environment(OSX 10.10.4), the temporary file generated under the /var/folders/bt/xwh9qmcj00dctz53_rxclgtr0000gn/T. It is not deleted.

ls -ltr /var/folders/bt/xwh9qmcj00dctz53_rxclgtr0000gn/T

...
-rw-------   1 kohkimakimoto  staff       6  8 19 13:41 311400111
-rw-------   1 kohkimakimoto  staff       6  8 19 13:42 445911440
-rw-------   1 kohkimakimoto  staff       6  8 19 13:44 305149766
-rw-------   1 kohkimakimoto  staff       6  8 19 13:45 960108122
-rw-------   1 kohkimakimoto  staff       6  8 19 13:45 607108666
-rw-------   1 kohkimakimoto  staff       6  8 19 13:45 731094900
-rw-------   1 kohkimakimoto  staff       6  8 19 13:45 166451425
-rw-------   1 kohkimakimoto  staff       8  8 19 13:48 977724667
-rw-r--r--   1 kohkimakimoto  staff     132  8 19 18:53 lsuseractivityd.log
drwx------@  3 kohkimakimoto  staff     102  8 19 19:59 com.apple.mail
drwx------@  2 kohkimakimoto  staff      68  8 20 06:08 com.apple.corerecents.recentsd
-rw-------   1 kohkimakimoto  staff    4011  8 20 06:12 xcrun_db
drwxr-xr-x   2 kohkimakimoto  staff      68  8 20 06:24 TemporaryItems
-rw-------   1 kohkimakimoto  staff      19  8 20 07:39 440567778

cat 440567778
This is a tempfile.

debug.traceback: does not support level argument

The debug.traceback function does not support the level argument as described in the reference manual.

This seems like it would be helpful for writing error handling functions (edit: specifically for use with PCall). As it is now, I think the error handling function is included in any stracktrace the error handling function produces.

coroutine can't yield after a require call

I have a simple test:

--test.lua
local a,b

a = function ()
require "inityx_dtba"
print("a")
coroutine.yield()
b()
end

b = function ()
print("b")
end

local co = coroutine.create(a)
local ok = coroutine.resume(co)
while ok do
ok = coroutine.resume(co)
end

It's ok in clua5.1, but when run in glua, I got these error info
It's very important for me to load module in coroutine, how can solve this issue?

[G]: can not yield from outside of a coroutine
stack traceback:
[G]: in yield
test.lua:11: in main chunk
[G]: ?
goroutine 1 [running]:
github.com/yuin/gopher-lua.func·007()
e:/fei/go/src/github.com/yuin/gopher-lua/state.go:1365 +0x17e
github.com/yuin/gopher-lua.func·010()
e:/fei/go/src/github.com/yuin/gopher-lua/vm.go:118 +0x1a2
github.com/yuin/gopher-lua.func·002(0xc082014410)
e:/fei/go/src/github.com/yuin/gopher-lua/coroutinelib.go:75 +0x72
github.com/yuin/gopher-lua.(_LState).raiseError(0xc082014410, 0x1, 0x650570, 0x2
9, 0x0, 0x0, 0x0)
e:/fei/go/src/github.com/yuin/gopher-lua/state.go:354 +0x364
github.com/yuin/gopher-lua.(_LState).RaiseError(0xc082014410, 0x650570, 0x29, 0x
0, 0x0, 0x0)
e:/fei/go/src/github.com/yuin/gopher-lua/state.go:1065 +0x6a
github.com/yuin/gopher-lua.switchToParentThread(0xc082014410, 0x0, 0xc0820d0000)

    e:/fei/go/src/github.com/yuin/gopher-lua/vm.go:44 +0x71

github.com/yuin/gopher-lua.callGFunction(0xc082014410, 0x0, 0xc082006dc0)
e:/fei/go/src/github.com/yuin/gopher-lua/vm.go:74 +0xe6
github.com/yuin/gopher-lua.func·033(0xc082014410, 0xc070000201, 0x0, 0x0)
e:/fei/go/src/github.com/yuin/gopher-lua/vm.go:493 +0x22c
github.com/yuin/gopher-lua.mainLoop(0xc082014410, 0x0)
e:/fei/go/src/github.com/yuin/gopher-lua/vm.go:27 +0x119
github.com/yuin/gopher-lua.threadRun(0xc082014410)
e:/fei/go/src/github.com/yuin/gopher-lua/vm.go:122 +0x96
github.com/yuin/gopher-lua.coResume(0xc0820143c0, 0x0)
e:/fei/go/src/github.com/yuin/gopher-lua/coroutinelib.go:82 +0x450
github.com/yuin/gopher-lua.callGFunction(0xc0820143c0, 0x0, 0xc082006e00)
e:/fei/go/src/github.com/yuin/gopher-lua/vm.go:67 +0x40
github.com/yuin/gopher-lua.func·033(0xc0820143c0, 0xc0700c0402, 0x0, 0x0)
e:/fei/go/src/github.com/yuin/gopher-lua/vm.go:493 +0x22c
github.com/yuin/gopher-lua.mainLoop(0xc0820143c0, 0x0)
e:/fei/go/src/github.com/yuin/gopher-lua/vm.go:27 +0x119
github.com/yuin/gopher-lua.(_LState).callR(0xc0820143c0, 0x0, 0xffffffffffffffff
, 0x0)
e:/fei/go/src/github.com/yuin/gopher-lua/state.go:712 +0x21f
github.com/yuin/gopher-lua.(_LState).Call(0xc0820143c0, 0x0, 0xffffffffffffffff)

    e:/fei/go/src/github.com/yuin/gopher-lua/state.go:1348 +0x4c

github.com/yuin/gopher-lua.(_LState).PCall(0xc0820143c0, 0x0, 0xffffffffffffffff
, 0x0, 0x0, 0x0)
e:/fei/go/src/github.com/yuin/gopher-lua/state.go:1396 +0x15b
github.com/yuin/gopher-lua.(_LState).DoFile(0xc0820143c0, 0xc0820021f0, 0x8, 0x0
, 0x0)
e:/fei/go/src/github.com/yuin/gopher-lua/auxlib.go:385 +0xec
main.main()
e:/fei/go/src/github.com/yuin/gopher-lua/cmd/glua/glua.go:89 +0x769

table.remove does not return deleted element

From the Lua 5.1 manual (emphasis mine):

table.remove (table [, pos])

Removes from table the element at position pos, shifting down other elements to close the space, if necessary. Returns the value of the removed element. The default value for pos is n, where n is the length of the table, so that a call table.remove(t) removes the last element of table t.

This should probably be fixed for capability.

How to extend string builtins

How would I go about to implement the following Lua function in Go? I can't figure out how to extend the string global.

function string:split(sep, cb)
    local sep, fields = sep or ":", {}
    local pattern = string.format("([^%s]+)", sep)

    if cb then
        assert(type(cb) == "function")
        self:gsub(pattern, cb)
    end

    self:gsub(pattern, function(c) fields[#fields+1] = c end)

    i = 0
    n = table.getn(fields)
    return function()
        i = i + 1
        if i <= n then return fields[i] end
    end
end

Does not work `error` function in a loaded file by using `dofile`.

I tested the following 2 files code by using glua.

a.lua

dofile "b.lua"

b.lua

error("error!")

Run the command. Got a incorrect message: nil as the following.

$ glua a.lua
nil
stack traceback:
    [G]: in error
    b.lua:1: in <b.lua:0>
    [G]: in dofile
    a.lua:1: in function 'main chunk'
    [G]: ?

And I also tested running the original C lua5.1 in the same way. Got a correct error message.

$ lua5.1 a.lua
lua5.1: b.lua:1: error!
stack traceback:
    [C]: in function 'error'
    b.lua:1: in main chunk
    [C]: in function 'dofile'
    a.lua:1: in main chunk
    [C]: ?

gsub(".", ...) does not iterate over newlines

I was trying to iterate over a string's characters with gsub and found this particular implementation difference (which I assume is considered a bug):

Lua 5.1.5  Copyright (C) 1994-2012 Lua.org, PUC-Rio
> function newline(str) str:gsub(".", function(c) print(c == '\n') end) end
> newline("a\nb")
false
true
false

GopherLua 0.1 Copyright (C) 2015 Yusuke Inuzuka
> function newline(str) str:gsub(".", function(c) print(c == '\n') end) end
> newline("a\nb")
false
false

Turns out RE2 regular expressions do not match newlines by default - the s flag needs to be set. As far as I can tell, this is done by prepending (?s) to the regex string. In other words:

--- a/utils.go
+++ b/utils.go
@@ -286,7 +286,7 @@ func compileLuaRegex(pattern string) (*regexp.Regexp, error) {
-       gopattern := sc.String()
+       gopattern := "(?s)" + sc.String()

Pull request incoming.

README.rst issues

Two examples from the reference are wrong:
1、This example has two wrong. One is missing 'lua' package name for 'LTrue'. Another is 'bl,ok == ' should be ':='
lv := L.Get(-1) // get the value at the top of the stack

if lv == LTrue { // correct
}

if bl, ok == lv.(lua.LBool); ok && bool(bl) { // wrong
}
2、Missing 'lua' package again for the two functions.
lv := L.Get(-1) // get the value at the top of the stack
if LVIsFalse(lv) { // lv is nil or false
}

if LVAsBool(lv) { // lv is neither nil nor false
}

`os.execute` doesn't work.

I found a bug: os.execute doesn't work.

I created like the following lua file.

-- execute_test.lua
os.execute("echo OK")

And I tried to run it, but I got a error.

$ go build cmd/glua/glua.go
$ ./glua execute_test.lua
-c: echo OK: No such file or directory

NOTE:My go version is 1.4.2

$ go version
go version go1.4.2 darwin/amd64

How to limit access to filesystem?

If I wanted to "lockdown" the Lua thread running so that it only had access to a select number of files that are predetermined or determined by an outside source how would I go about doing so?

I can't seem to find any functions that would allow this behavior so the only course of action I can see is replacing loRequire with something else (reassigning that global) and removing the load* series and dofile methods.

Do you have a clean way to do this other than what my thoughts are?

Also, secondary, but you don't provide any examples of LUserData on the README, perhaps add some? As I become more familiar with this library, if you haven't done them already I'll see about doing it to help out.

inspect.lua doesn't work

Hi, I've just played with inspect.lua (https://github.com/kikito/inspect.lua) but it seems it doesn't work correctly.

for example)

macbook% ../bin/glua bug.lua

inspect.lua:300: attempt to index a non-table object(nil)
stack traceback:
inspect.lua:300: in inspect.lua:297
(tailcall): ?
bug.lua:2: in main chunk
[G]: ?
macbook% lua bug.lua
"hello"

https://gist.github.com/chobie/bcff5c74c915422a3075

also, I've tested above script with lua 5.1.5 and lua 5.2.3 and it works fine.
can you check this if you have a chance?

Thanks,

Wrong value/infinite loop in for-loop when using iterators with tail calls

Oh well, sorry, I ran into a second issue :)

When I use a coroutine together with a for-loop, the second value is wrong - the first value is duplicated. If I call the coroutine manually, everything is fine.

Example:

local cr = function()
        return coroutine.wrap(function()
                coroutine.yield(1, "a")
                coroutine.yield(2, "b")
        end)
end

for k, v in cr() do
        print("for:", k, v)
end

print("------")

local f = cr()
print("call:", f())
print("call:", f())

Output:

for:    1       1
for:    2       2
------
call:   1       a
call:   2       b

Thanks again!

Sandbox environment

Hi,

gopher-lua works great. I actually found out about it when Shopify announced its version (go-lua).
One thing I'd like to be able to do it to provide a sandbox environment for executing user scripts, e.g. preventing access to files and executing commands. Is this possible with gopher-lua?

Thanks!

Disallow nil table index

Currently, the following code runs without error:

local x = {}
x[nil] = "test"

To be consistent with Lua 5.1, it should raise a "table index is nil" error.

Debug hooks

Hi! Awesome work on this! I've been prototyping a project which uses gopher-lua to run user-defined scripts in a sandbox, and everything has been going pretty smoothly so far, however I would like to implement some resource constraints on scripts which are run, and based on previous experience, the way this is done is with debug hooks. Is there a specific reason why they are not exposed in gopher-lua? Is it possible to add them? I see that the shopify/go-lua project does implement them, but they are missing other things that gopher-lua has, and as far as I can tell, is not particularly active. Rather than cut over to using shopify/go-lua, I'm wondering if it's feasible to implement the debug hooks in gopher-lua, and wanted to get some background on why they were omitted before I started working on anything.

Thanks!

how do you think of supporting closure serialization of lua?

Closure serialization, which means code and it's context partly evaluated.
In my business, If a closure can be serialized, it can be passed to remote service to apply with the input provided by the remote service.

a closure(args1...N) -----> remote service( apply(closure,input) )

This feature is quite useful in distributed system, for example:

  1. Data broker
  2. Remote data warehouse analyze

Without this, I can only implement Context(some arguments provided) + Code Snippet String (not evaluated) to remote service and Apply(Context, Args, Code)

How do you think of this?

PS:
https://github.com/jeremeamia/super_closure

GopherLua does not support shebang.

Original Lua5.1 implementation supports shebang.
But GopherLua does not support it.

Example: example.lua

#!/path/to/glua
print("hoge")
$ ./example.lua
./example.lua line:1(column:1) near '#':   syntax error

my environment:

go version go1.6 darwin/amd64

Golua compatibillity?

Can gopher-lua be made API compatible with golua?
The reason I ask is that it would be very nice to have Luar working with this!

string.find, string.sub with 0 index

test case:

print(string.find('hello.world', '.', 0))
print('str = ' .. string.sub('hello.world', 0, 2))

Output of Lua:

1    1
str = he

Output of gopher-lua:

nil
str =

0 start index is 1 in Lua.
0 start index is the end(length) of the string in gopher-lua.

__call on module doesn't work

Hi, I'm trying to define a __call on a module like:

    mt := L.NewTypeMetatable("CUSTOM_MAP")

    L.SetGlobal("Map", mt)

    // static attributes
    L.SetField(mt, "__call", L.NewFunction(newLuaMap))
    L.SetField(mt, "create", L.NewFunction(newLuaMap))

If I call:

m = Map.create()

everything works as expected. But if I do

m = Map()

I get attempt to call a non-function object.

Is there a way I can get this to work?

FYI

Thanks for writing gopher-lua, I'm using in it algernon and it works great!

Best regards,
Alexander F Rødseth

thread-safety and convenience of `basePrint`

The basePrint function in baselib.go currently writes its output directly to os.Stdout through fmt.Print and friends. This will cause problems when calling print from multiple goroutines/Lua threads. Notably, that multiple Print calls can have their output interwoven on the console when they both run in parallel. For example:

fmt.Println("foo and bar")
go fmt.Println("bar and foo")

Can, under certain conditions, give output like this:

foo abar and foo
nd bar

Additionally, it would be nice if the host application could specify a different output target, aside from the default os.Stdout. For this reason, I'm wondering if it is not more convenient and safer to have it use Go's log package instead. This package takes care of both problems at once.

The changes to this package can be as simple as:

func basePrint(L *LState) int {
    var buf bytes.Buffer

    top := L.GetTop()
    for i := 1; i <= top; i++ {
        fmt.Fprint(&buf, L.Get(i).String(), " ")
    }

    log.Println(buf.String())
    return 0
}

The host now has the guarantee that logging stuff is thread safe and the output can be redirected to any target by calling log.SetOutput(io.Writer).

Allow installing some but not all of the standard modules.

Currently you can have all, or no standard modules. This produces problems when, for example, you need everything but os and io to be available.

The fix for this is trivial, just export the openXYZ functions so that users can install modules piecemeal if they wish.

Possible stack issue

I discovered this when I was integrating gopher-lua and I'm able to reproduce it with glua as well. To work around the issue I had to assign the string.format to a temporary variable and then do the var1 = var1 or var2 statement.

test.lua

function test(a, b, c)
    b = b or string.format("test %v", a)
    c = c or string.format("test %v", a)

    print("a:", a)
    print("b:", b)
    print("c:", c)
end

Run

glua test.lua hello

Expected result:

a:  hello
b:  test hello
c:  test hello

Actual result:

a:  hello
b:  test hello
c:  test %v

a large key of lua table not worked

local t = {
[123456789] = 'A',
}
if I set lua table key = 123456789, it is not worked

local t = {
[12345678] = 'A',
}
if i set lua table key = 12345678, it takes long time, almost 7 sec

how can i fix this problem??

Non-latin characters not working in regular expressions

I'm writing a plugin for Piepan which uses gopher-lua for its Go Lua plugins. I use string.match() in such a plugin with a regular expression to sanitize user input. However, this does not work with non-latin characters such as the Danish æ, ø and å. Regular expression implementations usually support this.

A trivial example:

print(string.match("abc", "abc"))
abc

print(string.match("æøå", "æøå"))
nil

Is this a bug in gopher-lua? Or do I need to do something special to be able to use these non-latin characters?

(I originally filed this bug against Piepan here: layeh/piepan#31. The author sent me here.)

Accessing comments through AST

I would like to annotate Lua code through comments, much like Go to generate documentation. However, I don't see the comments when I call parse.Dump.

How should I access the comments through the AST?

-- relase <var> [optionalVar]
function target.relase(var, optionalVar)

end

Is there a way to clone an LState?

I have an LState in which a user script has defined several functions. Is there a way to clone this LState in order to have two individual LStates that can get executed concurrently safely (they can eventually get killed individually, without affecting the other)?

Example:

L := lua.NewState()
L.DoString(script)

L2 := L.Clone()

go run(L)
go run(L2)
// "run()" is an arbitrary function that may call anything on L or L2 and also might crash

Readme - concurrency.

Could you write a readme heading describing how go routines interact with gopher-lua, and what is/isn't thread safe.

Changes for Lua 5.2/5.3 compliance?

Do you have any plan to make the changes necessary to be a compliant environment for newer (minor) versions of Lua? Of course Lua 5.3.2 being the latest version as of today. I don't really have a need for it. But I think it would be nice.

One thing I have noticed as a difference between the lua C programs is that the lua5.3 interactive interpreter (REPL) works much better than the lua5.1 repl. Surely more work has gone into it's presentation but, having implemented a simple REPL in 5.1 and seen the limitations, I wasn't sure if it was actually just easier to build a good REPL using the 5.3 C API.

From what I understand the Go API has some functions that correspond to functions added to the C API in Lua 5.2. But I'm not entirely sure about C API changes in Lua 5.3.

Is the existing Lua module API strictly compliant exactly with Lua 5.1? Or is in somewhere in-between versions?

io.read panic

I have the following code:

package main

import (
    "github.com/yuin/gopher-lua"
)

var luaProgram = `
    -- defines a factorial function
    function fact (n)
      if n == 0 then
        return 1
      else
        return n * fact(n-1)
      end
    end

    print("enter a number:")
    a = io.read("*number")        -- read a number
    print(fact(5))
`

func main() {
    L := lua.NewState()
    defer L.Close()

    if err := L.DoString(luaProgram); err != nil {
        panic(err)
    }
}

When I run it, I get the following error:

enter a number:
15
panic: <string>:12: bad argument #2 to read (invalid options:u)
stack traceback:
        [G]: in read
        <string>:12: in function 'main chunk'
        [G]: ?

goroutine 1 [running]:
main.main()
        C:/Users/Bruno.Panuto/Desktop/lua.go:27 +0xc7

By using the glua interpreter, I get the same panic.
Using Windows may be the case, but I am just wondering what went wrong.

Thanks!

Consistent, structured returned error value

Hi. Really loving gopher-lua so far and excited to keep using it! Thanks for making it.

I'm struggling with error handling at the moment. Basically, I'd like to do my own error reporting. The error returned from the Do functions could be a concrete type that has structured access to the line and column number and error message.

if err := L.DoString(luaCode); err != nil {
    // access to line and column number here would be awesome!
}

If you're too busy, I'm willing to make the changes but am not sure the best way to go about it. The DoString function could still return error type, but the underlying type (after a type assertion) would ideally expose the line, column numbers as well as the error message and maybe error type (syntax, etc.). Right now the error is like this:

&lua.ApiError{Type:0, Object:"<string> line:3(column:5) near 'if':   syntax error\n", StackTrace:""}

But I'd like to be able to do this:

if err := L.DoString(luaCode); err != nil {
    luaErr := err.(lua.Error) // or whatever
    fmt.Println("Error type:", luaErr.Type)
    fmt.Println("Line:", luaErr.Line)
    fmt.Println("Col:", luaErr.Column)
    fmt.Println("Message:", luaErr.Message)
}

What do you think?

os.clock should not use wall time

The current implementation of os.clock uses a simple "seconds since the app started" but the LUA reading material I'm seeing (e.g. http://www.lua.org/pil/22.1.html) says it should be CPU-seconds.

I don't know of a clean way to get this via the Go runtime, so this would require a kernel call to getrusage (http://linux.die.net/man/2/getrusage). For some reason getrusage returns wall clock time on Windows, so you'll need to use GetProcessTimes (https://msdn.microsoft.com/en-us/library/windows/desktop/ms683223.aspx).

Call Go from Lua

I started playing with this library, and have really liked it so far. Except for this annoying method of creating Go funcs that can be called from Lua. Its been constructed that you have to write these methods with the lua state in mind.

I have written a proof on concept function that essentially replaces LState.NewFunction with an interface{} that is typed checked to ensure it has been passed a function, then essentially does some reflection magic to automatically get all the required arguments from the state in their proper types, call the function with the arguments, and push any and all of the results back onto the stack in their respective orders.

Heres an example

func Double(i int) int {
    return i * 2
}

func main() { 
    L := lua.NewState()
    defer L.Close()
    L.SetGlobal("double", L.NewFunc(Double)) /* wraps Double and called newLFunction */
}

If this is something that you'd accept into the codebase I will finish my implementation, currently it only works with ints as arguments and returns (Not for any particular purpose, I just chose a type to test with)

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.