Closed joelpinheiro closed 8 years ago
Yes you can. Get a function from javascript, and then call it.
e.g
js.global.console:log("hello via JS console.log")
The function can come in via any means, e.g.
Using js.global
L = require("./lua.vm.js").L;
L.execute('js.global.console:log("hello via JS console.log")')
or passed as an argument
L = require("./lua.vm.js").L;
L.execute('local console = ...; console:log("hello from lua")', console)
or via setting a lua global
L = require("./lua.vm.js").L;
L._G.set("console", console); // Add console global to lua
L.execute('console:log("hello")')
==> there are tonnes of ways to pass variables+functions back and forth.
In Lua code I did a require where I have my executeJQuery function:
JQ = require("executeJQuery.js")
When I do L.execute I receive the following:
e:Lua.Error: [string "?"]:5: module 'executeJQuery' not found:
no field package.preload['executeJQuery']
no file '/usr/local/share/lua/5.2/executeJQuery.lua'
no file '/usr/local/share/lua/5.2/executeJQuery/init.lua'
no file '/usr/local/lib/lua/5.2/executeJQuery.lua'
no file '/usr/local/lib/lua/5.2/executeJQuery/init.lua'
no file './executeJQuery.lua'
no file '/usr/local/lib/lua/5.2/executeJQuery.so'
no file '/usr/local/lib/lua/5.2/loadall.so'
no file './executeJQuery.so'
It seems like my import executeJQuery should be a Lua file but it isn't. In fact it is a simple JS function. Where should I put my function file? Am I doing it properly to call a JS function from lua.vm.js in node.js side?
Thanks in advance.
My purpose is to after that, be able to call:
JQ.executeJQuery(url)
Where url
is the data of the HTTP Request.
My executionJQuery code:
module.exports = {
executeJQuery : function(x) {
console.log("executeJQuery");
require("jsdom").env("", function(err, window) {
if (err) {
console.error(err);
return;
}
var $ = require("jquery")(window);
console.log("x: " + x);
console.log("Resultado: \n\n")
$.ajax({
type: "POST",
url: x,
success: function (result) {
console.log(result.message)
}
});
});
}
};
My purpose is to after that, be able to call:
JQ.executeJQuery(url)
Assuming you saved your code above as "JQ.js" you could do in lua:
local JQ = js.global:require"./JQ.js"
JQ:executeJQuery("http://example.com")
I updated my node_module from NPM:
npm install lua.vm.js
My code:
local JQ = js.global:require"./executeJQuery.js"
JQ:executeJQuery(url)
Ex:
e:Lua.Error: [string "?"]:5: attempt to call method 'require' (a nil value)
I had the same problem. Apparently while all the JS globals are available using js.global, the function 'require' is not available.
In my case I just needed to access the filesystem with a require("fs")
, so I just defined a global function in JS to read the file:
myReadFile = function(fileName) {
return require("fs").readFileSync(fileName, "utf8");
}
Then from LUA I call myReadFile
as:
...
myFile.data = js.global:myReadFile(filename)
..
You can do a similar trick, where you can wrap your executeJQuery.js
inside a global function.
Apparently while all the JS globals are available using js.global, the function 'require' is not available.
I don't get the same behaviour locally:
$ node
> L = require("./dist/lua.vm.js").L;
{ _L: 5263368,
_G:
{ [Function: self]
L: [Circular],
ref: 2,
invoke: [Function],
push: [Function],
free: [Function],
toString: [Function],
get: [Function],
set: [Function] } }
> L.execute('for k, v in pairs(js.global:require"./package.json") do print(k,v) end')
name lua.vm.js
version 0.0.1
description The Lua VM, on the Web
main dist/lua.vm.js
scripts [object Object]
repository [object Object]
keywords lua,emscripten
contributors Alon Zakai,daurnimator <quae@daurnimator.com>
license MIT
bugs [object Object]
homepage http://kripken.github.io/lua.vm.js/lua.vm.js.html
Ok, I might have identified my problem although it's not clear to me why. My problem is that at this point I don't understand what is the right object to use for the execute
function.
In your case you use the L from this:
L = require("./dist/lua.vm.js").L;
But in my case I have been doing:
luavm=require("./dist/lua.vm.js");
L=new temp.Lua.State();
Now the value of L appears to be the same in both cases (only the number of _L is different):
{ _L: 5295832,
_G:
{ [Function: self]
L: [Circular],
ref: 2,
invoke: [Function],
push: [Function],
free: [Function],
toString: [Function],
get: [Function],
set: [Function] } }
Unfortunately now in my case when I try to use require, here is what I get:
> L.execute('print(type(js.global:require))')
Lua.Error
at /home/fabrizio/working/git/lua.vm.js/dist/lua.vm.js:16:18422
at /home/fabrizio/working/git/lua.vm.js/dist/lua.vm.js:16:27153
at Object.<anonymous> (/home/fabrizio/working/git/lua.vm.js/dist/lua.vm.js:21:35)
at Module._compile (module.js:460:26)
at Object.Module._extensions..js (module.js:478:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Module.require (module.js:365:17)
at require (module.js:384:17)
at repl:1:9
Ok, I might have identified my problem although it's not clear to me why. My problem is that I don't have it clear what is the right handle to use for the execute function. In your case you use the L from this:
L = require("./dist/lua.vm.js").L;
lua.vm.js currently creates an arbitrarily "main" state called L
.
It makes more sense in the browser than when run in node....
But in my case I have:
luavm=require("./dist/lua.vm.js"); L=new temp.Lua.State();
I guess you meant luavm
not temp
in this code sample?
Also keep in mind that if you create your own lua state you need to run js.lua manually. (I should probably fix this?)
Now the value of L appears to be the same in both cases (only the number of _L is different)
Ignore the value of _L for anything but equivalence; it's an address to inside emscripten.
> L.execute('print(type(js.global:require))')
Lua.Error
type(js.global:require)
isn't valid syntax. You probably wanted type(js.global.require)
.
node doesn't strinify error messages well; do it yourself to get more information:
> try { L.execute('print(type(js.global:require))') } catch(e) { console.error(e.name, e.message) }
Lua.Error [string "?"]:1: function arguments expected near ')'
I guess you meant luavm not temp in this code sample? Also keep in mind that if you create your own lua state you need to run js.lua manually. (I should probably fix this?)
Yes, I meant luavm, not temp... copy & paste after numerous tests...
type(js.global:require) isn't valid syntax. You probably wanted type(js.global.require).
Correct, that's another error that has nothing to do with this problem. I just wanted to print the type of the require
object:
> L.execute('print(type(js.global.require))')
userdata
But bottom line is that my version of "L" any attempt to call require
fails.
> L.execute('for k, v in pairs(js.global:require"./package.json") do print(k,v) end')
Lua.Error
...
So in conclusion yes, I think the problem was that I did not know what was the correct way to get that L value.
Thanks!
But bottom line is that my version of "L" any attempt to call requirefails.
> L.execute('for k, v in pairs(js.global:require"./package.json") do print(k,v) end') Lua.Error
I actually think that's pairs
failing (without running js.lua
proxy objects don't get a __pairs metamethod)
You should use the try
/catch
I showed above to get the error message.
Yes, it is pairs
that is failing because it does not know how to iterate over a userdata object:
try { L.execute('for k, v in pairs(js.global:require"./package.json") do print(k,v) end') } catch(e) { console.error(e.name, e.message) }
Lua.Error [string "?"]:1: bad argument #1 to 'pairs' (table expected, got userdata)
So after those tests I went back to my project, and I have replaced my:
var luavm = require('lua.vm.js');
L = new luavm.Lua.State();
with:
L = require('lua.vm.js').L
And tried to use again require in my code, but it still fail.
Now, I think the problem might be somewhere else. My real use case is a bit different than just executing require
from inside a L.execute() call.
In my case, I have some legacy LUA code that performs io.open to read a file. In my JS wrapper I re-define the LUA's io.open
to read the file (through filesystem in JS) and return to LUA a table with a read
and close
function:
L.execute(" \
io.open = function(filename, mode) \
if (mode ~= 'r') then \
print('Error: non-read mode not supported in io.open wrapper') \
return nil \
end \
local myFile = {} \
myFile.read = function() \
return myFile.data \
end \
myFile.close = function() \
myFile.data = nil \
end \
myFile.data = js.global:require('fs').readFileSync(filename, 'utf8') \
return myFile \
end");
That code is executed before invoking my LUA's function that need to access the local filesystem. In this scenario, I am always getting this error:
Error executing LUA code: Lua.Error: [string "?"]:1: attempt to call method 'require' (a nil value)
no matter how I get L
.
But if define a JS global function to read a file:
myReadFile = function(fileName) {
return require("fs").readFileSync(fileName, "utf8");
}
then I invoke it from my io.open
wrapper:
...
myFile.close = function() \
myFile.data = nil \
end \
myFile.data = js.global:myReadFile(filename) \
return myFile \
end");
everything works well.
Hi,
I had tried as daurnimator said:
var L = require("lua.vm.js").L;
try {
L.execute(code);
} catch(e) {
console.log("e:" + e)
}
local JQ = js.global:require"./executeJQuery.js"
JQ:executeJQuery(url)
Same code of executeJQuery (see above).
And I'm receiving the same error again:
e:Lua.Error: [string "?"]:XX: attempt to call method 'require' (a nil value)
If it put like you said fabriziobertocci:
js.global:executeJQuery(url)
I receive:
e:Lua.Error: [string "?"]:XX: attempt to call method 'executeJQuery' (a nil value)
For both cases, I'm not sure If I am putting the executeJQuery.js file in the correct path. I have it on the same path I'm running L.execute and inside the node_module lua.vm.js.
For both cases, my executeJQuery.js (with an executeJQuery global) is the following:
module.exports = {
executeJQuery : function(x) {
console.log("executeJQuery");
require("jsdom").env("", function(err, window) {
if (err) {
console.error(err);
return;
}
var $ = require("jquery")(window);
console.log("x: " + x);
console.log("Resultado: \n\n")
$.ajax({
type: "POST",
url: x,
success: function (result) {
console.log(result.message)
//if (result.isOk == false) console.log(result.message);
}
});
});
}
};
@joelpinheiro it works for me:
$ mkdir tmp
$ cd tmp
$ npm install lua.vm.js
/home/daurnimator/tmp
└── lua.vm.js@0.0.1
npm WARN enoent ENOENT: no such file or directory, open '/home/daurnimator/tmp/package.json'
npm WARN tmp No description
npm WARN tmp No repository field.
npm WARN tmp No README data
npm WARN tmp No license field.
$ cat > test.js << EOF
> console.log("loaded");
> module.exports = { foo: function() { return "bar" } };
> EOF
$ node
> var luavm = require("./lua.vm.js");
undefined
> luavm.L.execute("return type(js.global.require)")
[ 'userdata' ]
> luavm.L.execute("local test = js.global:require('./test.js'); return test:foo()")
loaded
[ 'bar' ]
@daurnimator your code worked for me in my node.js version:
4.2.1
But, I'm using electron (atom shell) that used its own node.js version:
4.2.2
JS:
var luavm = require("lua.vm.js"); -- this comes from node_modules (am I using the correct import?)
luavm.L.execute("print('type: ' .. type(js.global.require))")
luavm.L.execute("local test = js.global:require('./test.js'); print('foo: ' .. test:foo())")
Output:
type: nil
/Users/joelpinheiro/Dropbox/iTrading/electron_app/node_modules/lua.vm.js/dist/lua.vm.js:2
var Module;if(typeof Module==="undefined")Module={};if(!Module.expectedDataFileDownloads){Module.expectedDataFileDownloads=0;Module.finishedDataFileDownloads=0}Module.expectedDataFileDownloads++;((function(){var loadPackage=(function(metadata){function runWithFS(){var fileData0=[];fileData0.push.apply(fileData0,[45,45,32,77,97,107,101,32,119,105,110,100,111,119,32,111,98,106,101,99,116,32,97,32,103,108,111,98,97,108,10,119,105,110,100,111,119,32,61,32,106,115,46,103,108,111,98,97,108,59,10,10,100,111,32,45,45,32,67,114,101,97,116,101,32,106,115,46,105,112,97,105,114,115,32,97,110,100,32,106,115,46,112,97,105,114,115,32,102,117,110,99,116,105,111,110,115,46,32,97,116,116,97,99,104,32,97,115,32,95,95,112,97,105,114,115,32,97,110,100,32,95,95,105,112,97,105,114,115,32,111,110,32,74,83,32,117,115,101,114,100,97,116,97,32,111,98,106,101,99,116,115,46,10,9,108,111,99,97,108,32,95,80,82,79,88,89,95,77,84,32,61,32,100,101,98,1
Lua.Error
at /Users/joelpinheiro/Dropbox/iTrading/electron_app/node_modules/lua.vm.js/dist/lua.vm.js:16:18422
at /Users/joelpinheiro/Dropbox/iTrading/electron_app/node_modules/lua.vm.js/dist/lua.vm.js:16:27153
at Object.<anonymous> (/Users/joelpinheiro/Dropbox/iTrading/electron_app/node_modules/lua.vm.js/dist/lua.vm.js:21:35)
at Module._compile (module.js:434:26)
at Object.Module._extensions..js (module.js:452:10)
at Module.load (module.js:355:32)
at Function.Module._load (module.js:310:12)
at Module.require (module.js:365:17)
at require (module.js:384:17)
at EventEmitter.<anonymous> (/Users/joelpinheiro/Dropbox/iTrading/electron_app/main.js:79:17)
Any reason for the different behaviour?
@daurnimator your code worked for me in my node.js version: 4.2.1
But, I'm using electron (atom shell) that used its own node.js version: 4.2.2
I tested in 5.9.0, so I doubt it's the version that's the issue.
Any reason for the different behaviour?
I assume that electron doesn't have a global.require
for some reason. You'll have to ask the electron devs.
I didn't have any solution from them.
@daurnimator there is another way to invoke HTTP Request from lua.vm.js?
I didn't have any solution from them.
Where did you ask?
@daurnimator there is another way to invoke HTTP Request from lua.vm.js?
You can get a js value into lua using any of the options in https://github.com/kripken/lua.vm.js/issues/48#issuecomment-194073741
Where did you ask?
https://github.com/electron/electron/issues/4935#issuecomment-203883719
You can get a js value into lua using any of the options in #48 (comment)
The thing is, I need to require my js file executeJQuery.js and pass an argument to it on Lua. Since I can't require I'm not able to call my function on Lua.
Do you suggest another approach?
The thing is, I need to require my js file executeJQuery.js and pass an argument to it on Lua. Since I can't require I'm not able to call my function on Lua.
Do you suggest another approach?
Please try some of the other options I linked.
Hi all,
Anyone know if it is possible to call a node.js function from lua.vm? If anyone, can you please put an example?
Thank you