Skip to content

jangabrielsson/LuaLua_emu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 

Repository files navigation

LuaLua emulator

Lua implemented in vanilla Lua without any libraries.

Compiles Lua src to a bytecode run by an emulator implemented in Lua. Used in sandboxed environment where loadstring, metatables, and coroutines are not allowed. ~10-30x slower than "native" Lua. Goto and label not implemented but metatables and coroutines works.

Divided up in a parser and a compiler. The parser outputs a parse tree and the compiler creates bytecode of the parse tree, thats run by a small vm (not compatible with Lua's bytecode). The parser can be parsed by the parser and the parse-tree then compiled by the compiler thus reducing the code foot print.

dofile("luaParser.lua")
dofile("luaCompiler.lua")
dofile("lib/json.lua")

Toolbox_Module.LuaParser.init(nil,{})
Toolbox_Module.LuaCompiler.init(nil,{})

local function main()
  code([[
  print("Coroutine test")
  local function foo() for i=1,5 do print("Foo:"..i) coroutine.yield() end end
  local function bar() for j=6,10 do print("Bar"..j) coroutine.yield() end end
  local co_foo = coroutine.create(foo)
  local co_bar = coroutine.create(bar)
  for k=1,6 do
    coroutine.resume(co_foo)
    coroutine.resume(co_bar)
  end

-------------------------------------------
  print("metatable test")
  function setDefault (t, d)
     local mt = {__index = function () return d end}
     setmetatable(t, mt)
  end
    
  tab = {x=10, y=20}
  print(tab.x, tab.z)     --> 10   nil
  setDefault(tab, 0)
  print(tab.x, tab.z)     --> 10   0

-------------------------------------------
--  print("HTTP test") -- turning async calls into synchronous...
--  local function myMain(co)

--    local function httpRequest(url)
--       net.HTTPClient():request(url,{
--         options={},
--         success =function(res) 
--             local r = json.decode(res.data)
--             coroutine.resume(co,"success",r.datetime) 
--         end,
--         error = function(res) coroutine.resume(co,"error",res) end,
--       })
--       return coroutine.yield()
--    end

--  -- Now we can call httpRequest as a synchronous function that returns the value immediatly - no more callbacks
--  -- Disclaimer, this is not the best/most efficient way to do it but it demonstrates the principle....
--  local code,res = httpRequest("http://worldtimeapi.org/api/ip") -- Note this server sometimes refuses with 'success'
--  print(code,res)
--  local code,res = httpRequest("http://worldtimeapi.org/api/ip")
--  print(code,res)

--  end
--  local co = coroutine.create(myMain)
--  coroutine.resume(co,co)

 ------------------------------------------------
  print("Illegal boundary test")
  function foo() fopp() print("Never here") end
  function bar() print("..on the other side, 'yield' will barf") coroutine.yield() end
  local c = coroutine.create(foo)
  coroutine.resume(c)
  coroutine.resume(c)
]])
end

function fopp() print("Crossing..") bar() end -- Non-LuaLua function to test with

local debug = {}

function run()  debug={struct=false,codel=false,trace=false} main() end
function debugC()  debug={struct=false,codel=false,trace=true} main() end
function debugCStar()  debug={struct=false,codel=true,trace=true} main() end

comp = Toolbox_Module.LuaCompiler.inited
function code(str)
  return comp.load(str,nil,nil,comp.stdFuns,debug)()
end
run()

A simple function with all tracing bells turned on

debug={struct=true,codel=true,trace=true}
code([[function fact(x) if x == 0 then return 1 else return x*fact(x-1) end end; print(fact(3))]])

gives the following output

DEBUG: ["block",[["nop",["function","glob","fun",["glob","fact"],["x"],false,["block",[["if",["==",["var","x"],0],["block",[["return1",[1]]]],[],["block",[["return1",[["*",["var","x"],["call",["glob","fact"],[["-",["var","x"],1]]]]]]]]]]]]],["nop",["call",["glob","print"],[["call",["glob","fact"],[3]]]]]]]
DEBUG: PC:  1 ["function",["x"],false,"glob","fun",["glob","fact"],[["var","x"],["push",0],["eq"],["ifnskip3",5],["push",1],["return",1],["pop"],["goto",10],["var","x"],["var","x"],["push",1],["sub"],["glob","fact"],["call",1,["glob","fact"]],["mul"],["return",1],["pop"],["return",0]]]
DEBUG: PC:  2 ["pop"]
DEBUG: PC:  3 ["push",3]
DEBUG: PC:  4 ["glob","fact"]
DEBUG: PC:  5 ["call",1,["glob","fact"]]
DEBUG: PC:  6 ["glob","print"]
DEBUG: PC:  7 ["call",1,["glob","print"]]
DEBUG: PC:  8 ["pop"]
DEBUG: PC:  9 ["return",0]
TRACE: main    PC:001 ST:000 ["function",["x"],false,"glob","fun",["glob","fact"],[["var","x"],["push",0],["e null
TRACE: main    PC:002 ST:001 ["pop"]                        <non-json>
TRACE: main    PC:003 ST:000 ["push",3]                     null
TRACE: main    PC:004 ST:001 ["glob","fact"]                3
TRACE: main    PC:005 ST:002 ["call",1,["glob","fact"]]     <non-json>
TRACE: main    PC:001 ST:000 ["var","x"]                    null
TRACE: main    PC:002 ST:001 ["push",0]                     3
TRACE: main    PC:003 ST:002 ["eq"]                         0
TRACE: main    PC:004 ST:001 ["ifnskip3",5]                 false
TRACE: main    PC:009 ST:000 ["var","x"]                    null
TRACE: main    PC:010 ST:001 ["var","x"]                    3
TRACE: main    PC:011 ST:002 ["push",1]                     3
TRACE: main    PC:012 ST:003 ["sub"]                        1
TRACE: main    PC:013 ST:002 ["glob","fact"]                2
TRACE: main    PC:014 ST:003 ["call",1,["glob","fact"]]     <non-json>
TRACE: main    PC:001 ST:000 ["var","x"]                    null
TRACE: main    PC:002 ST:001 ["push",0]                     2
TRACE: main    PC:003 ST:002 ["eq"]                         0
TRACE: main    PC:004 ST:001 ["ifnskip3",5]                 false
TRACE: main    PC:009 ST:000 ["var","x"]                    null
TRACE: main    PC:010 ST:001 ["var","x"]                    2
TRACE: main    PC:011 ST:002 ["push",1]                     2
TRACE: main    PC:012 ST:003 ["sub"]                        1
TRACE: main    PC:013 ST:002 ["glob","fact"]                1
TRACE: main    PC:014 ST:003 ["call",1,["glob","fact"]]     <non-json>
TRACE: main    PC:001 ST:000 ["var","x"]                    null
TRACE: main    PC:002 ST:001 ["push",0]                     1
TRACE: main    PC:003 ST:002 ["eq"]                         0
TRACE: main    PC:004 ST:001 ["ifnskip3",5]                 false
TRACE: main    PC:009 ST:000 ["var","x"]                    null
TRACE: main    PC:010 ST:001 ["var","x"]                    1
TRACE: main    PC:011 ST:002 ["push",1]                     1
TRACE: main    PC:012 ST:003 ["sub"]                        1
TRACE: main    PC:013 ST:002 ["glob","fact"]                0
TRACE: main    PC:014 ST:003 ["call",1,["glob","fact"]]     <non-json>
TRACE: main    PC:001 ST:000 ["var","x"]                    null
TRACE: main    PC:002 ST:001 ["push",0]                     0
TRACE: main    PC:003 ST:002 ["eq"]                         0
TRACE: main    PC:004 ST:001 ["ifnskip3",5]                 true
TRACE: main    PC:005 ST:000 ["push",1]                     null
TRACE: main    PC:006 ST:001 ["return",1]                   1
TRACE: main    PC:015 ST:002 ["mul"]                        1
TRACE: main    PC:016 ST:001 ["return",1]                   1
TRACE: main    PC:015 ST:002 ["mul"]                        1
TRACE: main    PC:016 ST:001 ["return",1]                   2
TRACE: main    PC:015 ST:002 ["mul"]                        2
TRACE: main    PC:016 ST:001 ["return",1]                   6
TRACE: main    PC:006 ST:001 ["glob","print"]               6
TRACE: main    PC:007 ST:002 ["call",1,["glob","print"]]    <non-json>
6
TRACE: main    PC:008 ST:001 ["pop"]                        null
TRACE: main    PC:009 ST:000 ["return",0]                   null
Program completed in 0.05 seconds (pid: 38158).

About

Lua compiler/vm written in lua

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages