1 local NomsuCode, LuaCode, Source
3 local _obj_0 = require("code_obj")
4 NomsuCode, LuaCode, Source = _obj_0.NomsuCode, _obj_0.LuaCode, _obj_0.Source
8 local _obj_0 = require('containers')
9 List, Dict = _obj_0.List, _obj_0.Dict
11 local Text = require('text')
12 local SyntaxTree = require("syntax_tree")
13 local Files = require("files")
14 local Errhand = require("error_handling")
15 local C = require("colors")
16 local make_parser = require("parser")
17 local pretty_error = require("pretty_errors")
19 make_tree = function(tree, userdata)
20 tree.source = Source(userdata.filename, tree.start, tree.stop)
21 tree.start, tree.stop = nil, nil
22 tree = SyntaxTree(tree)
26 for version = 1, NOMSU_VERSION[1] do
28 if package.nomsupath then
29 local pegpath = package.nomsupath:gsub("lib/%?%.nom", "?.peg"):gsub("lib/%?%.lua", "?.peg")
31 local path = package.searchpath("nomsu." .. tostring(version), pegpath, "/")
33 peg_file = io.open(path)
37 peg_file = io.open("nomsu." .. tostring(version) .. ".peg")
39 assert(peg_file, "No PEG file found for Nomsu version " .. tostring(version))
40 local peg_contents = peg_file:read('*a')
42 Parsers[version] = make_parser(peg_contents, make_tree)
44 local tree_to_nomsu, tree_to_inline_nomsu
46 local _obj_0 = require("nomsu_decompiler")
47 tree_to_nomsu, tree_to_inline_nomsu = _obj_0.tree_to_nomsu, _obj_0.tree_to_inline_nomsu
49 local compile, fail_at
51 local _obj_0 = require('nomsu_compiler')
52 compile, fail_at = _obj_0.compile, _obj_0.fail_at
54 local _module_imports = { }
55 local _importer_mt = {
56 __index = function(self, k)
57 return _module_imports[self][k]
61 Importer = function(t, imports)
62 _module_imports[t] = imports or { }
63 t._IMPORTS = _module_imports[t]
64 return setmetatable(t, _importer_mt)
67 _1_as_text = function(x)
77 nomsu_pairs = function(self)
78 local mt = getmetatable(self)
79 if mt and mt.__next then
80 return mt.__next, self, nil
82 return next, self, nil
86 if _VERSION == "Lua 5.2" or _VERSION == "Lua 5.1" then
87 inext = function(self, i)
88 local value = self[i + 1]
97 nomsu_ipairs = function(self)
98 local mt = getmetatable(self)
99 if mt and mt.__inext then
100 return mt.__inext, self, 0
102 return inext, self, 0
105 local nomsu_environment
106 nomsu_environment = Importer({
109 unpack = unpack or table.unpack,
110 setmetatable = setmetatable,
112 getmetatable = getmetatable,
114 yield = coroutine.yield,
115 resume = coroutine.resume,
116 coroutine_status_of = coroutine.status,
117 coroutine_wrap = coroutine.wrap,
118 coroutine_from = coroutine.create,
131 collectgarbage = collectgarbage,
137 loadstring = loadstring,
145 _ipairs = nomsu_ipairs,
148 LUA_VERSION = (jit and jit.version or _VERSION),
150 Bit = (jit or _VERSION == "Lua 5.2") and require('bitops') or nil,
157 SyntaxTree = SyntaxTree,
161 NomsuCode = NomsuCode,
163 LuaCode_from = (function(src, ...)
164 return LuaCode:from(src, ...)
166 NomsuCode_from = (function(src, ...)
167 return NomsuCode:from(src, ...)
169 enhance_error = Errhand.enhance_error,
172 _1_as_nomsu = tree_to_nomsu,
173 _1_as_inline_nomsu = tree_to_inline_nomsu,
176 _1_as_text = _1_as_text,
177 _1_as_an_iterable = _1_as_an_iterable,
180 _1_parsed = function(nomsu_code, syntax_version)
181 if type(nomsu_code) == 'string' then
182 local filename = Files.spoof(nomsu_code)
183 nomsu_code = NomsuCode:from(Source(filename, 1, #nomsu_code), nomsu_code)
185 local source = nomsu_code.source
186 nomsu_code = tostring(nomsu_code)
187 local version = nomsu_code:match("^#![^\n]*nomsu[ ]+-V[ ]*([0-9.]+)")
188 if syntax_version then
189 syntax_version = tonumber(syntax_version:match("^[0-9]+"))
191 syntax_version = syntax_version or (version and tonumber(version:match("^[0-9]+")) or NOMSU_VERSION[1])
192 local parse = Parsers[syntax_version]
193 assert(parse, "No parser found for Nomsu syntax version " .. tostring(syntax_version))
194 local tree = parse(nomsu_code, source.filename)
196 local shebang_version = tree.shebang:match("nomsu %-V[ ]*([%d.]+)")
197 if shebang_version and shebang_version ~= "" then
198 tree.version = tree.version or List((function()
201 for v in shebang_version:gmatch("%d+") do
202 _accum_0[_len_0] = tonumber(v)
211 Module = function(self, package_name)
213 if package_name:match("%.nom$") or package_name:match("%.lua") then
217 path, err = package.searchpath(package_name, package.nomsupath, "/")
222 path = path:gsub("^%./", "")
224 local ret = package.nomsuloaded[package_name] or package.nomsuloaded[path]
229 local currently_running = { }
231 local info = debug.getinfo(i, 'f')
232 if not (info.func) then
235 if info.func == self.Module then
236 local n, upper_path = debug.getlocal(i, 3)
237 table.insert(currently_running, upper_path)
239 if upper_path == path then
240 local circle = table.concat(currently_running, "', which imports '")
242 info = debug.getinfo(err_i)
243 while info and (info.func == self.Module or info.func == self.use or info.func == self.export) do
245 info = debug.getinfo(err_i)
247 fail_at((info or debug.getinfo(2)), "Circular import: File '" .. tostring(path) .. "' imports '" .. circle .. "'")
251 local mod = self:new_environment()
252 mod.MODULE_NAME = package_name
253 local code = Files.read(path)
254 if path:match("%.lua$") then
255 code = LuaCode:from(Source(path, 1, #code), code)
257 code = NomsuCode:from(Source(path, 1, #code), code)
259 local ret = mod:run(code)
263 package.nomsuloaded[package_name] = mod
264 package.nomsuloaded[path] = mod
267 use = function(self, package_name)
268 local mod = self:Module(package_name)
269 local imports = assert(_module_imports[self])
270 for k, v in pairs(mod) do
273 local cr_imports = assert(_module_imports[self.COMPILE_RULES])
274 if mod.COMPILE_RULES then
275 for k, v in pairs(mod.COMPILE_RULES) do
281 export = function(self, package_name)
282 local mod = self:Module(package_name)
283 local imports = assert(_module_imports[self])
284 for k, v in pairs(_module_imports[mod]) do
285 if rawget(imports, k) == nil then
289 for k, v in pairs(mod) do
290 if rawget(self, k) == nil then
294 local cr_imports = assert(_module_imports[self.COMPILE_RULES])
295 if mod.COMPILE_RULES then
296 for k, v in pairs(_module_imports[mod.COMPILE_RULES]) do
297 if rawget(cr_imports, k) == nil then
301 for k, v in pairs(mod.COMPILE_RULES) do
302 if rawget(self.COMPILE_RULES, k) == nil then
303 self.COMPILE_RULES[k] = v
309 run = function(self, to_run)
311 error("Need both something to run and an environment")
313 if type(to_run) == 'string' then
314 local filename = Files.spoof(to_run)
315 to_run = NomsuCode:from(Source(filename, 1, #to_run), to_run)
316 return self:run(to_run)
317 elseif NomsuCode:is_instance(to_run) then
318 local tree = self._1_parsed(to_run)
322 return self:run(tree)
323 elseif SyntaxTree:is_instance(to_run) then
324 local filename = to_run.source.filename:gsub("\n.*", "...")
325 local version = to_run.version
326 if to_run.type ~= "FileChunks" then
332 for chunk_no, chunk in ipairs(to_run) do
333 chunk.version = version
334 local lua = self:compile(chunk)
336 lua:prepend("-- File: " .. tostring(filename) .. " chunk #" .. tostring(chunk_no) .. "\n")
340 elseif LuaCode:is_instance(to_run) then
341 local source = to_run.source
342 local lua_string = to_run:text()
343 lua_string = lua_string:gsub("^#![^\n]*\n", "")
344 local run_lua_fn, err = load(lua_string, tostring(source), "t", self)
345 if not run_lua_fn then
350 for i, line in ipairs(lua_string:lines()) do
351 _accum_0[_len_0] = ("%3d|%s"):format(i, line)
356 local line_numbered_lua = table.concat(lines, "\n")
357 error("Failed to compile generated code:\n" .. tostring(C("bright blue", line_numbered_lua)) .. "\n\n" .. tostring(err), 0)
359 local source_key = tostring(source)
360 if not (self.SOURCE_MAP[source_key] or self.OPTIMIZATION >= 2) then
362 local file = Files.read(source.filename)
363 if not file and NOMSU_PREFIX then
364 file = Files.read(tostring(NOMSU_PREFIX) .. "/share/nomsu/" .. tostring(table.concat(NOMSU_VERSION, ".")) .. "/" .. tostring(source.filename))
367 error("Failed to find file: " .. tostring(source.filename))
369 local nomsu_str = file:sub(source.start, source.stop)
371 local nomsu_line = Files.get_line_number(file, source.start)
373 map_sources = function(s)
374 if type(s) == 'string' then
375 for nl in s:gmatch("\n") do
376 map[lua_line] = map[lua_line] or nomsu_line
377 lua_line = lua_line + 1
380 if s.source and s.source.filename == source.filename then
381 nomsu_line = Files.get_line_number(file, s.source.start)
383 local _list_0 = s.bits
384 for _index_0 = 1, #_list_0 do
385 local b = _list_0[_index_0]
391 map[lua_line] = map[lua_line] or nomsu_line
393 self.SOURCE_MAP[source_key] = map
397 return error("Attempt to run unknown thing: " .. _1_as_lua(to_run))
400 new_environment = function()
401 local env = Importer({ }, (function()
403 for k, v in pairs(nomsu_environment) do
410 env.TESTS = Dict({ })
411 env.COMPILE_RULES = Importer({ }, (function()
413 for k, v in pairs(nomsu_environment.COMPILE_RULES) do
421 nomsu_environment._ENV = nomsu_environment
422 nomsu_environment._G = nomsu_environment
423 nomsu_environment.COMPILE_RULES = Importer(require('bootstrap'), nil)
424 nomsu_environment.MODULE_NAME = "nomsu"
425 SOURCE_MAP = nomsu_environment.SOURCE_MAP
426 return nomsu_environment