local R={}local K=require(script.Parent.LuaP)R.LUA_SIGNATURE="\027\076\117\097"R.LUA_TNUMBER=3 R.LUA_TSTRING=4 R.LUA_TNIL=0 R.LUA_TBOOLEAN=1 R.LUA_TNONE=-1 R.LUAC_VERSION=81 R.LUAC_FORMAT=0 R.LUAC_HEADERSIZE=12 function R.make_setS(R)local K={}K.data=""local A=function(R,K)if not R then return 0 end K.data=K.data..R return 0 end return A,K end function R.ttype(K,R)local A=type(R.value)if A=="\110\117\109\098\101\114"then return K.LUA_TNUMBER elseif A=="\115\116\114\105\110\103"then return K.LUA_TSTRING elseif A=="\110\105\108"then return K.LUA_TNIL elseif A=="\098\111\111\108\101\097\110"then return K.LUA_TBOOLEAN else return K.LUA_TNONE end end function R.from_double(K,R)local function A(R)local K=R%256 return(R-K)/256,string.char(K)end local C=0 if R<0 then C=1 R=-R end local i,s=math.frexp(R)if R==0 then i,s=0,0 elseif R==1/0 then i,s=0,2047 else i=(i*2-1)*math.ldexp(.5,53)s=s+1022 end local y,V=""R=math.floor(i)for K=1,6,1 do R,V=A(R)y=y..V end R,V=A(s*16+R)y=y..V R,V=A(C*128+R)y=y..V return y end function R.from_int(K,R)local A=""R=math.floor(R)if R<0 then R=4294967296+R end for K=1,4,1 do local C=R%256 A=A..string.char(C)R=math.floor(R/256)end return A end function R.DumpBlock(A,R,K)if K.status==0 then K.status=K.write(R,K.data)end end function R.DumpChar(A,R,K)A:DumpBlock(string.char(R),K)end function R.DumpInt(A,R,K)A:DumpBlock(A:from_int(R),K)end function R.DumpNumber(A,R,K)A:DumpBlock(A:from_double(R),K)end function R.DumpString(A,R,K)if R==nil then A:DumpInt(0,K)else R=R.."\000"A:DumpInt(#R,K)A:DumpBlock(R,K)end end function R.DumpCode(C,R,A)local i=R.sizecode C:DumpInt(i,A)for i=0,i-1,1 do C:DumpBlock(K:Instruction(R.code[i]),A)end end function R.DumpConstants(A,R,K)local C=R.sizek A:DumpInt(C,K)for C=0,C-1,1 do local i=R.k[C]local s=A:ttype(i)A:DumpChar(s,K)if s==A.LUA_TNIL then elseif s==A.LUA_TBOOLEAN then A:DumpChar(i.value and 1 or 0,K)elseif s==A.LUA_TNUMBER then A:DumpNumber(i.value,K)elseif s==A.LUA_TSTRING then A:DumpString(i.value,K)else end end C=R.sizep A:DumpInt(C,K)for C=0,C-1,1 do A:DumpFunction(R.p[C],R.source,K)end end function R.DumpDebug(A,R,K)local C C=K.strip and 0 or R.sizelineinfo A:DumpInt(C,K)for C=0,C-1,1 do A:DumpInt(R.lineinfo[C],K)end C=K.strip and 0 or R.sizelocvars A:DumpInt(C,K)for C=0,C-1,1 do A:DumpString(R.locvars[C].varname,K)A:DumpInt(R.locvars[C].startpc,K)A:DumpInt(R.locvars[C].endpc,K)end C=K.strip and 0 or R.sizeupvalues A:DumpInt(C,K)for C=0,C-1,1 do A:DumpString(R.upvalues[C],K)end end function R.DumpFunction(C,R,K,A)local i=R.source if i==K or A.strip then i=nil end C:DumpString(i,A)C:DumpInt(R.lineDefined,A)C:DumpInt(R.lastlinedefined,A)C:DumpChar(R.nups,A)C:DumpChar(R.numparams,A)C:DumpChar(R.is_vararg,A)C:DumpChar(R.maxstacksize,A)C:DumpCode(R,A)C:DumpConstants(R,A)C:DumpDebug(R,A)end function R.DumpHeader(K,R)local A=K:header()assert(#A==K.LUAC_HEADERSIZE)K:DumpBlock(A,R)end function R.header(R)local K=1 return R.LUA_SIGNATURE..string.char(R.LUAC_VERSION,R.LUAC_FORMAT,K,4,4,4,8,0)end function R.dump(s,R,K,A,C,i)local y={}y.L=R y.write=A y.data=C y.strip=i y.status=0 s:DumpHeader(y)s:DumpFunction(K,nil,y)y.write(nil,y.data)return y.status end return R
--# selene: allow(incorrect_standard_library_use, multiple_statements, shadowing, unused_variable, empty_if, divide_by_zero, unbalanced_assignments)
--[[--------------------------------------------------------------------

  ldump.lua
  Save precompiled Lua chunks
  This file is part of Yueliang.

  Copyright (c) 2006 Kein-Hong Man <khman@users.sf.net>
  The COPYRIGHT file describes the conditions
  under which this software may be distributed.

  See the ChangeLog for more information.

----------------------------------------------------------------------]]

--[[--------------------------------------------------------------------
-- Notes:
-- * WARNING! byte order (little endian) and data type sizes for header
--   signature values hard-coded; see luaU:header
-- * chunk writer generators are included, see below
-- * one significant difference is that instructions are still in table
--   form (with OP/A/B/C/Bx fields) and luaP:Instruction() is needed to
--   convert them into 4-char strings
--
-- Not implemented:
-- * DumpVar, DumpMem has been removed
-- * DumpVector folded into folded into DumpDebug, DumpCode
--
-- Added:
-- * for convenience, the following two functions have been added:
--   luaU:make_setS: create a chunk writer that writes to a string
--   luaU:make_setF: create a chunk writer that writes to a file
--   (lua.h contains a typedef for lua_Writer/lua_Chunkwriter, and
--    a Lua-based implementation exists, writer() in lstrlib.c)
-- * luaU:ttype(o) (from lobject.h)
-- * for converting number types to its binary equivalent:
--   luaU:from_double(x): encode double value for writing
--   luaU:from_int(x): encode integer value for writing
--     (error checking is limited for these conversion functions)
--     (double conversion does not support denormals or NaNs)
--
-- Changed in 5.1.x:
-- * the dumper was mostly rewritten in Lua 5.1.x, so notes on the
--   differences between 5.0.x and 5.1.x is limited
-- * LUAC_VERSION bumped to 0x51, LUAC_FORMAT added
-- * developer is expected to adjust LUAC_FORMAT in order to identify
--   non-standard binary chunk formats
-- * header signature code is smaller, has been simplified, and is
--   tested as a single unit; its logic is shared with the undumper
-- * no more endian conversion, invalid endianness mean rejection
-- * opcode field sizes are no longer exposed in the header
-- * code moved to front of a prototype, followed by constants
-- * debug information moved to the end of the binary chunk, and the
--   relevant functions folded into a single function
-- * luaU:dump returns a writer status code
-- * chunk writer now implements status code because dumper uses it
-- * luaU:endianness removed
----------------------------------------------------------------------]]

--requires luaP
local luaU = {}
local luaP = require(script.Parent.LuaP)

-- mark for precompiled code ('<esc>Lua') (from lua.h)
luaU.LUA_SIGNATURE = "\27Lua"

-- constants used by dumper (from lua.h)
luaU.LUA_TNUMBER  = 3
luaU.LUA_TSTRING  = 4
luaU.LUA_TNIL     = 0
luaU.LUA_TBOOLEAN = 1
luaU.LUA_TNONE    = -1

-- constants for header of binary files (from lundump.h)
luaU.LUAC_VERSION    = 0x51     -- this is Lua 5.1
luaU.LUAC_FORMAT     = 0        -- this is the official format
luaU.LUAC_HEADERSIZE = 12       -- size of header of binary files

--[[--------------------------------------------------------------------
-- Additional functions to handle chunk writing
-- * to use make_setS and make_setF, see test_ldump.lua elsewhere
----------------------------------------------------------------------]]

------------------------------------------------------------------------
-- create a chunk writer that writes to a string
-- * returns the writer function and a table containing the string
-- * to get the final result, look in buff.data
------------------------------------------------------------------------
function luaU:make_setS()
  local buff = {}
        buff.data = ""
  local writer =
    function(s, buff)  -- chunk writer
      if not s then return 0 end
      buff.data = buff.data..s
      return 0
    end
  return writer, buff
end

------------------------------------------------------------------------
-- create a chunk writer that writes to a file
-- * returns the writer function and a table containing the file handle
-- * if a nil is passed, then writer should close the open file
------------------------------------------------------------------------

--[[
function luaU:make_setF(filename)
  local buff = {}
        buff.h = io.open(filename, "wb")
  if not buff.h then return nil end
  local writer =
    function(s, buff)  -- chunk writer
      if not buff.h then return 0 end
      if not s then
        if buff.h:close() then return 0 end
      else
        if buff.h:write(s) then return 0 end
      end
      return 1
    end
  return writer, buff
end--]]

------------------------------------------------------------------------
-- works like the lobject.h version except that TObject used in these
-- scripts only has a 'value' field, no 'tt' field (native types used)
------------------------------------------------------------------------
function luaU:ttype(o)
  local tt = type(o.value)
  if tt == "number" then return self.LUA_TNUMBER
  elseif tt == "string" then return self.LUA_TSTRING
  elseif tt == "nil" then return self.LUA_TNIL
  elseif tt == "boolean" then return self.LUA_TBOOLEAN
  else
    return self.LUA_TNONE  -- the rest should not appear
  end
end

-----------------------------------------------------------------------
-- converts a IEEE754 double number to an 8-byte little-endian string
-- * luaU:from_double() and luaU:from_int() are adapted from ChunkBake
-- * supports +/- Infinity, but not denormals or NaNs
-----------------------------------------------------------------------
function luaU:from_double(x)
  local function grab_byte(v)
    local c = v % 256
    return (v - c) / 256, string.char(c)
  end
  local sign = 0
  if x < 0 then sign = 1; x = -x end
  local mantissa, exponent = math.frexp(x)
  if x == 0 then -- zero
    mantissa, exponent = 0, 0
  elseif x == 1/0 then
    mantissa, exponent = 0, 2047
  else
    mantissa = (mantissa * 2 - 1) * math.ldexp(0.5, 53)
    exponent = exponent + 1022
  end
  local v, byte = "" -- convert to bytes
  x = math.floor(mantissa)
  for i = 1,6 do
    x, byte = grab_byte(x); v = v..byte -- 47:0
  end
  x, byte = grab_byte(exponent * 16 + x); v = v..byte -- 55:48
  x, byte = grab_byte(sign * 128 + x); v = v..byte -- 63:56
  return v
end

-----------------------------------------------------------------------
-- converts a number to a little-endian 32-bit integer string
-- * input value assumed to not overflow, can be signed/unsigned
-----------------------------------------------------------------------
function luaU:from_int(x)
  local v = ""
  x = math.floor(x)
  if x < 0 then x = 4294967296 + x end  -- ULONG_MAX+1
  for i = 1, 4 do
    local c = x % 256
    v = v..string.char(c); x = math.floor(x / 256)
  end
  return v
end

--[[--------------------------------------------------------------------
-- Functions to make a binary chunk
-- * many functions have the size parameter removed, since output is
--   in the form of a string and some sizes are implicit or hard-coded
----------------------------------------------------------------------]]

--[[--------------------------------------------------------------------
-- struct DumpState:
--   L  -- lua_State (not used in this script)
--   writer  -- lua_Writer (chunk writer function)
--   data  -- void* (chunk writer context or data already written)
--   strip  -- if true, don't write any debug information
--   status  -- if non-zero, an error has occured
----------------------------------------------------------------------]]

------------------------------------------------------------------------
-- dumps a block of bytes
-- * lua_unlock(D.L), lua_lock(D.L) unused
------------------------------------------------------------------------
function luaU:DumpBlock(b, D)
  if D.status == 0 then
    -- lua_unlock(D->L);
    D.status = D.write(b, D.data)
    -- lua_lock(D->L);
  end
end

------------------------------------------------------------------------
-- dumps a char
------------------------------------------------------------------------
function luaU:DumpChar(y, D)
  self:DumpBlock(string.char(y), D)
end

------------------------------------------------------------------------
-- dumps a 32-bit signed or unsigned integer (for int) (hard-coded)
------------------------------------------------------------------------
function luaU:DumpInt(x, D)
  self:DumpBlock(self:from_int(x), D)
end

------------------------------------------------------------------------
-- dumps a lua_Number (hard-coded as a double)
------------------------------------------------------------------------
function luaU:DumpNumber(x, D)
  self:DumpBlock(self:from_double(x), D)
end

------------------------------------------------------------------------
-- dumps a Lua string (size type is hard-coded)
------------------------------------------------------------------------
function luaU:DumpString(s, D)
  if s == nil then
    self:DumpInt(0, D)
  else
    s = s.."\0"  -- include trailing '\0'
    self:DumpInt(#s, D)
    self:DumpBlock(s, D)
  end
end

------------------------------------------------------------------------
-- dumps instruction block from function prototype
------------------------------------------------------------------------
function luaU:DumpCode(f, D)
  local n = f.sizecode
  --was DumpVector
  self:DumpInt(n, D)
  for i = 0, n - 1 do
    self:DumpBlock(luaP:Instruction(f.code[i]), D)
  end
end

------------------------------------------------------------------------
-- dump constant pool from function prototype
-- * bvalue(o), nvalue(o) and rawtsvalue(o) macros removed
------------------------------------------------------------------------
function luaU:DumpConstants(f, D)
  local n = f.sizek
  self:DumpInt(n, D)
  for i = 0, n - 1 do
    local o = f.k[i]  -- TValue
    local tt = self:ttype(o)
    self:DumpChar(tt, D)
    if tt == self.LUA_TNIL then
    elseif tt == self.LUA_TBOOLEAN then
      self:DumpChar(o.value and 1 or 0, D)
    elseif tt == self.LUA_TNUMBER then
      self:DumpNumber(o.value, D)
    elseif tt == self.LUA_TSTRING then
      self:DumpString(o.value, D)
    else
      --lua_assert(0)  -- cannot happen
    end
  end
  n = f.sizep
  self:DumpInt(n, D)
  for i = 0, n - 1 do
    self:DumpFunction(f.p[i], f.source, D)
  end
end

------------------------------------------------------------------------
-- dump debug information
------------------------------------------------------------------------
function luaU:DumpDebug(f, D)
  local n
  n = D.strip and 0 or f.sizelineinfo           -- dump line information
  --was DumpVector
  self:DumpInt(n, D)
  for i = 0, n - 1 do
    self:DumpInt(f.lineinfo[i], D)
  end
  n = D.strip and 0 or f.sizelocvars            -- dump local information
  self:DumpInt(n, D)
  for i = 0, n - 1 do
    self:DumpString(f.locvars[i].varname, D)
    self:DumpInt(f.locvars[i].startpc, D)
    self:DumpInt(f.locvars[i].endpc, D)
  end
  n = D.strip and 0 or f.sizeupvalues           -- dump upvalue information
  self:DumpInt(n, D)
  for i = 0, n - 1 do
    self:DumpString(f.upvalues[i], D)
  end
end

------------------------------------------------------------------------
-- dump child function prototypes from function prototype
------------------------------------------------------------------------
function luaU:DumpFunction(f, p, D)
  local source = f.source
  if source == p or D.strip then source = nil end
  self:DumpString(source, D)
  self:DumpInt(f.lineDefined, D)
  self:DumpInt(f.lastlinedefined, D)
  self:DumpChar(f.nups, D)
  self:DumpChar(f.numparams, D)
  self:DumpChar(f.is_vararg, D)
  self:DumpChar(f.maxstacksize, D)
  self:DumpCode(f, D)
  self:DumpConstants(f, D)
  self:DumpDebug(f, D)
end

------------------------------------------------------------------------
-- dump Lua header section (some sizes hard-coded)
------------------------------------------------------------------------
function luaU:DumpHeader(D)
  local h = self:header()
  assert(#h == self.LUAC_HEADERSIZE) -- fixed buffer now an assert
  self:DumpBlock(h, D)
end

------------------------------------------------------------------------
-- make header (from lundump.c)
-- returns the header string
------------------------------------------------------------------------
function luaU:header()
 local x = 1
 return self.LUA_SIGNATURE..
        string.char(
          self.LUAC_VERSION,
          self.LUAC_FORMAT,
          x,                    -- endianness (1=little)
          4,                    -- sizeof(int)
          4,                    -- sizeof(size_t)
          4,                    -- sizeof(Instruction)
          8,                    -- sizeof(lua_Number)
          0)                    -- is lua_Number integral?
end

------------------------------------------------------------------------
-- dump Lua function as precompiled chunk
-- (lua_State* L, const Proto* f, lua_Writer w, void* data, int strip)
-- * w, data are created from make_setS, make_setF
------------------------------------------------------------------------
function luaU:dump(L, f, w, data, strip)
  local D = {}  -- DumpState
  D.L = L
  D.write = w
  D.data = data
  D.strip = strip
  D.status = 0
  self:DumpHeader(D)
  self:DumpFunction(f, nil, D)
  -- added: for a chunk writer writing to a file, this final call with
  -- nil data is to indicate to the writer to close the file
  D.write(nil, D.data)
  return D.status
end

return luaU
