Operating system for OpenComputers
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

196 lines
4.9KB

  1. #!/usr/bin/env lua5.3
  2. local _env = {}
  3. local directives = {}
  4. function directives.include(env, args)
  5. local path, err = args.get("string", 1)
  6. if (not path) then
  7. return false, err
  8. end
  9. local nenv = {code = ""}
  10. setmetatable(nenv, {__index=_env})
  11. local data, err = nenv:process(path)
  12. if (not data) then
  13. return false, err
  14. end
  15. env.code = env.code .. "\n" .. data
  16. return true
  17. end
  18. local mods = {}
  19. function directives.loadmod(env, args)
  20. local path, err = args.get("string", 1)
  21. if (not path) then
  22. return false, err
  23. end
  24. local file = io.open(path, "rb")
  25. if (not file) then
  26. return false, "`"..path.."' not found."
  27. end
  28. local env = {}
  29. local copies = {{_G, env}}
  30. while #copies ~= 0 do
  31. local c = {}
  32. for i=1, #copies do
  33. for k, v in pairs(copies[i][1]) do
  34. if (type(v) == "table") then
  35. copies[i][2][k] = {}
  36. c[#c+1] = {v, copies[i][2][k]}
  37. else
  38. copies[i][2][k] = v
  39. end
  40. end
  41. end
  42. for i=1, #copies do
  43. copies[i] = nil
  44. end
  45. for i=1, #c do
  46. copies[i] = c[i]
  47. end
  48. end
  49. local dir2a = {}
  50. env.add_directive = function(name, func) do
  51. dir2a[#dir2a+1] = {name, func}
  52. end
  53. local func, err = load(file:read("*a"), "="..path, "t", env)
  54. if (not func) then
  55. return false, err
  56. end
  57. local name = func()
  58. if not name then
  59. return false, "Module did not return a name."
  60. end
  61. for i=1, #dir2a do
  62. directives[dir2a[i][1]] = dir2a[i][2]
  63. end
  64. return true
  65. end
  66. end
  67. function _env:process(path)
  68. print("PROC", path)
  69. local file = io.open(path, "rb")
  70. local f, err = load(file:read("*a"), "="..path)
  71. if not f then
  72. io.stderr:write("ERROR: "..err.."\n")
  73. os.exit(1)
  74. end
  75. file:seek("set", 0)
  76. local ln = 0
  77. for line in file:lines() do
  78. ln = ln + 1
  79. line = line:gsub("^%s+", "")
  80. if (line:sub(1, 3) == "--#") then
  81. --Process directive
  82. local dir = line:sub(4)
  83. local tmp = ""
  84. local open_quote = false
  85. local escape = false
  86. local cmd = nil
  87. local args = {}
  88. local pos = 0
  89. dir = dir:gsub("^%s+", ""):gsub("%s+$", ""):gsub("%s+", " ")
  90. for i=1, #dir do
  91. local c = dir:sub(i, i)
  92. if (c == " " and not open_quote) then
  93. if (tmp ~= "") then
  94. if not cmd then
  95. cmd = tmp
  96. else
  97. args[#args+1] = tmp
  98. end
  99. end
  100. tmp = ""
  101. elseif (c == "\"" and not escape and not open_quote) then
  102. open_quote = true
  103. elseif (c == "\"" and not escape) then
  104. open_quote = false
  105. args[#args+1] = {"string", tmp}
  106. tmp = ""
  107. elseif (c == "\\" and not escape) then
  108. escape = true
  109. else
  110. if (escape) then escape = false end
  111. tmp = tmp .. c
  112. end
  113. end
  114. --Process arguments
  115. local rargs = {}
  116. for i=1, #args do
  117. if (type(args[i]) == "table") then
  118. if (args[i][1] == "string") then
  119. local str = args[i][2]
  120. local sp, ep = str:find("%$%([%w_]+%)")
  121. while sp do
  122. local var = str:sub(sp, ep)
  123. local st1, st2 = str:sub(1, sp-3), str:sub(ep+2)
  124. str = st1 .. var
  125. local nsp = #str
  126. str = str .. st2
  127. sp, ep = str:find("%$%([%w_]+%)", nsp)
  128. end
  129. args[i][2] = str
  130. end
  131. rargs[#rargs+1] = args[i]
  132. elseif (tonumber(args[i])) then
  133. rargs[#rargs+1] = {"number", args[i]}
  134. elseif (args == "true" or args == "false") then
  135. rargs[#rargs+1] = {"boolean", args[i] == "true"}
  136. elseif (os.getenv(args[i])) then
  137. rargs[#rargs+1] = {"var", args[i]}
  138. else
  139. io.stderr:write("ERROR: "..path..":"..ln..": Undefined variable.\n")
  140. os.exit(1)
  141. end
  142. end
  143. if (not directives[cmd]) then
  144. io.stderr:write("ERROR: "..path..":"..ln..": Unknown directive.\n")
  145. os.exit(1)
  146. end
  147. local rtn, err = directives[cmd](self, {get=function(atype, i)
  148. if (type(atype) == "number") then
  149. return rargs[i][2], rargs[i][1]
  150. end
  151. if (rargs[i] == nil) then
  152. return false, "argument #"..i..": expected `"..atype.."', got nil"
  153. end
  154. if (rargs[i][1] ~= atype) then
  155. return false, "argument #"..i..": expected `"..atype.."', got `"..rargs[i][1].."'"
  156. end
  157. return rargs[i][2]
  158. end})
  159. if (type(rtn) ~= "boolean") then
  160. io.stderr:write("ERROR: "..path..":"..ln..": Expected return type `boolean', got `"..type(rtn).."'.\n")
  161. os.exit(1)
  162. end
  163. if (not rtn) then
  164. err = err or "Unknown error"
  165. io.stderr:write("ERROR: "..path..":"..ln..": "..err..".\n")
  166. end
  167. else
  168. self.code = self.code .. line .. "\n"
  169. end
  170. end
  171. return self.code
  172. end
  173. local env = {code = ""}
  174. setmetatable(env, {__index=_env})
  175. env:process(arg[1])
  176. local tmpfile = os.tmpname()
  177. if tmpfile:sub(#tmpfile) == "." then tmpfile = tmpfile:sub(1, #tmpfile - 1) end
  178. local tmpf = io.open(tmpfile, "wb")
  179. env.code = env.code:gsub("%-%-.-\n","\n"):gsub("\n\n","\n")
  180. tmpf:write(env.code)
  181. tmpf:close()
  182. --if (os.execute("lua minify.lua "..tmpfile.." > "..arg[2])) then
  183. if (os.execute("cat "..tmpfile.." > "..arg[2])) then
  184. os.execute("stat -c \"Output: %s bytes\" "..arg[2])
  185. else
  186. io.stderr:write("Error: ")
  187. os.execute("cat "..arg[2].." 1>&2")
  188. os.remove(arg[2])
  189. end
  190. os.remove(tmpfile)