Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Call LUA function from GO #124

Open
WillianBR opened this issue Mar 18, 2022 · 11 comments
Open

Call LUA function from GO #124

WillianBR opened this issue Mar 18, 2022 · 11 comments

Comments

@WillianBR
Copy link

Hi Folks,

I'm wondering if anybody was able to call a Lua function from GO, instead of just run all the file or a buffered script.

I'm aware of need to load all the file (and who any code outside a function will be executed), but I'm thinking about a way of load it and after it was done, We be able of call any function of the Lua script, any time with the desired arguments.

Without the need of recompile and than increasing the speed.

Does anyone here did it?

@fbogsany
Copy link
Member

The usual approach is to return a table from your Lua script containing all the exported functions of your "module". E.g.:

local _M = {}

function _M.foo()
  return 42
end

return _M

and then something like:

l := lua.NewState()
lua.LoadString(l, myLuaScript)
l.ProtectedCall(0, 1, 0) // Run the script, leaves the module at the top of stack
l.Field(-1, "foo")       // Lookup the function 'foo' in the module
l.ProtectedCall(0, 0, 0) // Call the function 'foo' from the module

@gabstv
Copy link

gabstv commented Jul 29, 2022

or you could do:

function hello()
  return 42
end
l := lua.NewState()
lua.LoadString(l, myLuaScript)
l.Global("hello")
l.ProtectedCall(0, 1, 0)
myInt, ok := l.ToInteger(-1)

@hschneider
Copy link

I tried to get a function result but instead of 42 it returns 0:

	l := lua.NewState()
	lua.OpenLibraries(l)

	lua.LoadString(l, "function hello()\n  return 42\nend\n")
	l.Global("hello")
	l.ProtectedCall(0, 1, 0)
	myInt, _ := l.ToInteger(-1)
	fmt.Printf("Lua says %d", myInt)

Any hints, what I do wrong?

@WillianBR
Copy link
Author

I tried to get a function result but instead of 42 it returns 0:

	l := lua.NewState()
	lua.OpenLibraries(l)

	lua.LoadString(l, "function hello()\n  return 42\nend\n")
	l.Global("hello")
	l.ProtectedCall(0, 1, 0)
	myInt, _ := l.ToInteger(-1)
	fmt.Printf("Lua says %d", myInt)

Any hints, what I do wrong?

@hschneider,

Please, change the call lua.LoadString() to lua.DoString() .

The demo file:

package main

import (
	"fmt"

	"github.com/Shopify/go-lua"
)

func main2() {
	l := lua.NewState()
	lua.OpenLibraries(l)

	// lua.LoadString(l, "function hello()\n  return 42\nend\n")
	lua.DoString(l, "function hello()\n  return 42\nend\n")
	l.Global("hello")
	l.ProtectedCall(0, 1, 0)
	myInt, errRet := l.ToInteger(-1)
	fmt.Printf("RC = %v\n", errRet)
	fmt.Printf("Lua says %d\n", myInt)
}

The output:

$ go run .
RC = true
Lua says 42

If you wanna test the error, comment the statement l.Global("hello"). The result will be 0:

$ go run .
RC = false
Lua says 0

And please, always save the error and use it. If the errRet is not true, the result cannot be trusted!

The End

@hschneider
Copy link

Perfect! THANKS :-)

@hschneider
Copy link

There is one more thing about calling a Lua function in an external script.

This code works fine:

	lua.DoFile(l, "script2.lua")
	l.Global("main")
	l.PushString("Hello World")
	l.ProtectedCall(1, 1, 0)
	res, err = l.ToString(-1)
	fmt.Printf("RC = %v\n", err)
	fmt.Printf("Lua says %s\n", res)

script2.lua:

function main(s)
    return s.." from script file!"
end

Output:

Lua says Hello World from script file!

While this one throws an error in json.lua:

	lua.DoFile(l, "script3.lua")
	l.Global("main")
	l.ProtectedCall(0, 1, 0)
	res, err = l.ToString(-1)
	fmt.Printf("RC = %v\n", err)
	fmt.Printf("Lua says %s\n", res)

script3.lua:

local json = require("json")

function main()
    local data = {
        name = "John Doe",
        age = 30,
        occupation = "Software Engineer"
    }

    local d = json.encode(data)
    return d
end

Output:

Lua says ./json.lua:102: attempt to call a nil value

json.lua is located in the same folder as the script.
Is there some special way to deal with requirements?

@WillianBR
Copy link
Author

Hello @hschneider, sorry for the delay. But the reported error is not in the shared code. It's inside the json package. The error message report the line 102, as the error point.

Lua says ./json.lua:102: attempt to call a nil value

Is this package proprietary or it can be shared?

The package was suceffuly imported?

There's a encode() method?

It seems the package only a converter of a Lua table into a JSON string representation. As I wrote befone, check if the conversion has an error status and check it before return the data. You should agree with a convention about the error. How to proceed if it fail!

Call me if you need!

@hschneider
Copy link

json.lua here:
https://gist.github.com/hschneider/63078163ed3a4c1563c9d259234baa8a

If I call lua script3.luait works perfectly and json.lua imports fine.
It only throws this error when I try to run it from Go.

Maybe the problem is, that the requirement is located in the same folder as the script?

@WillianBR
Copy link
Author

@hschneider Sorry for the delay!

Let me tell the bad news my friend! The package string of go-lua does not implement the gsub() or gmatch() methods!

You can see by ourself at go-lua/string.go.

If you wish to use this package json.lua with the go-lua, it must be change to replace this call, by something available or write from scratch! Good luck!

local function encode_string(val)
  return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
end

@hschneider
Copy link

OK - thanks you so much for looking into it!

@tluyben
Copy link

tluyben commented Sep 27, 2024

I implemented gsub/gmatch/match here tluyben@151c0f8#diff-2b61500b8c4093b9a24b8e54a62ef0276046f9df9a0f67abea61a96771e9ab2fR260 but I did not robustly test them; they work for all my cases, so maybe it'll help someone.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants