Skip to content

jangabrielsson/LuaLua_emu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

8 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 a nested Lua function of the parse tree. 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

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages