Permalink
Browse files

experimental jsffi concept; added test case from matt revealing upval…

…ue issue
  • Loading branch information...
1 parent 2332cc4 commit b523ce682dbd147e3cf4f0ea231794a62fc175f9 @humbletim committed Oct 25, 2011
Showing with 166 additions and 1 deletion.
  1. +72 −0 ffi.js
  2. +3 −1 lvm.js
  3. +64 −0 tests/fail/upvalue.lua
  4. +27 −0 tests/pass/jsffi.lua
View
72 ffi.js
@@ -0,0 +1,72 @@
+/*
+copyright(c) 2011 tim dedischew
+released under MIT license
+experimental "ffi" for ljs
+only handles pattern 'function <name>(<args>){<body>}' and primitive return values
+
+-- example:
+ local ffi = require'ffi'
+ ffi.jsdef[[
+ function alert(x) { window.alert(x); }
+ function escape(x) { return escape(x); }
+ function plusone(x) { return x+1; }
+ ]]
+ ffi.js.alert[[ 'hi' from "lua" !!! ]]
+ print("escaped 'a b!'", ffi.js.escape("'a b !'"))
+ print("1+1", ffi.js.plusone(1))
+
+*/
+init_jsffi=function(testvm, _G) {
+ jsffi = testvm.registerLib(_G, "ffi", {
+ os: typeof process == 'object' ? 'node' : typeof window == 'object' ? 'browser' : 'other',
+ jsdef: function(jscode)
+ {
+ var codes = jscode.toString().split('function');
+ for (var i=0; i < codes.length; i++) {
+ var code = codes[i]; /*console.warn("jsdef:"+code);*/
+ code.replace(
+ /\s+([_a-zA-Z$][_a-zA-Z0-9$]+)\s*\(([^\)]*)\)\s*\{([\s\S]*?)\}/,
+ function(_, name, args, body) {
+ var def = {};
+ jsffi._jsdefs = jsffi._jsdefs || {};
+ jsffi._jsdefs[name] = def;
+ args = args.replace(/\s+/g,'');
+ def.args = args;
+ def.body = body;
+ def.jseval = "1,function("+args+"){"+body+"}";
+ try {
+ def.func = eval(def.jseval);
+ } catch(e) {
+ console.error(e,def.jseval);
+ }
+ /*console.warn(name, args, body);*/
+ });
+ }
+ return [];
+ },
+ js: []
+ });
+ _G._package_loaded.setIndex(testvm.LValue("ffi"), jsffi);
+ var mt = testvm.LValue([]);
+ mt.setIndex(
+ testvm.LValue("__index"),
+ testvm.LValue(function (t, k) {
+ var jsdef = jsffi._jsdefs[k.toString()];
+ if (!jsffi) {
+ throw "Access of undefined jsdef: ffi.js."+k;
+ }
+ /*console.warn("ffi.js", k+'', jsdef);*/
+ return [testvm.LValue(function() {
+ var args=[];
+ for (var i=0;i < arguments.length;i++)
+ args[i]=arguments[i].value;
+ var ret = jsdef.func.apply(jsdef.func, args);
+ return ret ? [testvm.LValue(ret)] : [];
+ })];
+ })
+ );
+ jsffi.index(testvm.LValue("js")).setMetatable(mt);
+};
+
+if (typeof exports == 'object')
+ exports.init_jsffi = init_jsffi;
View
4 lvm.js
@@ -9,7 +9,7 @@
// EXAMPLE node: luac <input.lua> && node lvm.js
// EXAMPLE browser: see demo.html
-var _VERSION = "Lua 5.1 {ljs=0.00121}"
+var _VERSION = "Lua 5.1 {ljs=0.00122}"
// TODO: find a generic javascript logger
// SEE: demo.html for browser stubs
@@ -1615,6 +1615,8 @@ if (typeof process != 'undefined') { // node
testvm.LValue("./misc/frexp")
).index(testvm.LValue("frexp")));
}
+ require('./ffi').init_jsffi(testvm, _G);
+ if (!_G.value.ffi) throw "failed to init jsffi";
var f = testvm.loadstring(fs.readFileSync("luac.out", "binary"), _G);
View
@@ -0,0 +1,64 @@
+local u;
+local f = {};
+for i=1,2 do
+ f[i] = function (set)
+ if set then
+ u = set;
+ end
+ return u;
+ end;
+end
+
+assert(f[1]("foo") == "foo");
+assert(f[2]() == "foo");
+
+assert(f[2]("bar") == "bar");
+assert(f[1]() == "bar");
+
+local prevmeta = setmetatable({name="prevmeta"}, {__index={id="#prevmeta"}})
+
+local upwithmeta = {name="upwithmeta"}
+function maker()
+ return function()
+ assert(getmetatable(upwithmeta), "upwithmeta has no metatable!")
+ assert("#"..upwithmeta.name == upwithmeta.id)
+ end
+end
+setmetatable(upwithmeta,
+ {__index={id="#upwithmeta"}})
+
+maker()()
+
+function taker()
+ return function()
+ assert(getmetatable(upwithmeta), "upwithmeta has no metatable!")
+ upwithmeta = prevmeta
+ print(upwithmeta.name, upwithmeta.id)
+ assert("#prevmeta" == upwithmeta.id)
+ end
+end
+taker()()
+local luaZ = {}
+function luaZ:make_getS(buff)
+ print("buff",buff)
+ local b = buff
+-- local data
+ return function() -- chunk reader anonymous function here
+ print("buff",b)
+ if not b then return nil end
+ local data = b
+ b = nil
+ return data
+ end
+end
+
+local blah = "print(5)"
+local tmp = luaZ:make_getS(""..blah)
+local blah2 = tmp()
+assert(blah2 == blah, tostring(blah) .. "~="..tostring(blah2))
+
+
+u = "hello";
+print(f[1]())
+assert(f[1]() == "hello");
+assert(f[2]() == "hello");
View
@@ -0,0 +1,27 @@
+if ffi then
+ --local ffi = require("ffi")
+ ffi.jsdef[[
+ function warn(x) { console.warn(x); }
+ function debug(x) { require('sys').debug(x); }
+ function plusone(x) { return x+1; }
+ function add(x,y) { return x+y; }
+ ]]
+ print("ffi.os=", ffi.os)
+ print("ffi.js.debug=", ffi.js.debug);
+ local emit
+ if ffi.os == "node" then
+ function emit(s)
+ ffi.js.debug(s)
+ end
+ else
+ function emit(s)
+ ffi.js.warn(s)
+ end
+ end
+
+ emit("hi!")
+ emit(ffi.js.plusone(6))
+
+ assert(ffi.js.plusone(1)==2)
+ assert(ffi.js.add(10,20)==30)
+end

0 comments on commit b523ce6

Please sign in to comment.