diff options
| -rw-r--r-- | core/id.nom | 1 | ||||
| -rw-r--r-- | core/metaprogramming.nom | 3 | ||||
| -rw-r--r-- | lib/object.nom | 6 | ||||
| -rw-r--r-- | nomsu.lua | 2 | ||||
| -rwxr-xr-x | nomsu.moon | 2 | ||||
| -rw-r--r-- | nomsu_compiler.lua | 356 | ||||
| -rw-r--r-- | nomsu_compiler.moon | 219 |
7 files changed, 323 insertions, 266 deletions
diff --git a/core/id.nom b/core/id.nom index 9656dd0..d3b2b71 100644 --- a/core/id.nom +++ b/core/id.nom @@ -3,6 +3,7 @@ A simple UUID function based on RFC 4122: http://www.ietf.org/rfc/rfc4122.txt use "core/metaprogramming.nom" +use "core/operators.nom" use "core/math.nom" use "core/collections.nom" use "core/control_flow.nom" diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom index 93d5486..5d31c2b 100644 --- a/core/metaprogramming.nom +++ b/core/metaprogramming.nom @@ -372,7 +372,8 @@ compile [command line args] to (Lua value "arg") compile [with local compile actions %body] to (..) Lua "\ ..do - local nomsu = table.fork(nomsu, {COMPILE_ACTIONS=table.fork(COMPILE_ACTIONS)}) + local nomsu = nomsu:fork() + local COMPILE_ACTIONS = nomsu.environment.COMPILE_ACTIONS \(%body as lua statements) end" diff --git a/lib/object.nom b/lib/object.nom index 88b9d1e..b49b8f2 100644 --- a/lib/object.nom +++ b/lib/object.nom @@ -84,9 +84,9 @@ compile [object %classname extends %parent %class_body] to: return inst end, }) - nomsu[("new "..class.name):as_lua_id()] = class - nomsu[("new "..class.name.." 1"):as_lua_id()] = class - nomsu[class.name:as_lua_id()] = function() return class end + nomsu.environment[("new "..class.name):as_lua_id()] = class + nomsu.environment[("new "..class.name.." 1"):as_lua_id()] = class + nomsu.environment[class.name:as_lua_id()] = function() return class end class.__index = class class.class = class class.__tostring = function(inst) @@ -133,7 +133,7 @@ if not args or args.help then os.exit(EXIT_FAILURE) end local nomsu = NomsuCompiler -nomsu.arg = NomsuCompiler._List(args.nomsu_args) +nomsu.environment.arg = NomsuCompiler.environment._List(args.nomsu_args) if args.version then nomsu:run([[use "core" say (Nomsu version)]]) @@ -87,7 +87,7 @@ if not args or args.help os.exit(EXIT_FAILURE) nomsu = NomsuCompiler -nomsu.arg = NomsuCompiler._List(args.nomsu_args) +nomsu.environment.arg = NomsuCompiler.environment._List(args.nomsu_args) if args.version nomsu\run [[ diff --git a/nomsu_compiler.lua b/nomsu_compiler.lua index 7d733e6..d490712 100644 --- a/nomsu_compiler.lua +++ b/nomsu_compiler.lua @@ -37,6 +37,7 @@ do end local AST = require("syntax_tree") local make_parser = require("parser") +local pretty_error = require("pretty_errors") SOURCE_MAP = { } table.map = function(t, fn) return setmetatable((function() @@ -148,10 +149,120 @@ local NomsuCompiler = setmetatable({ }, { }) local _anon_chunk = 0 do - NomsuCompiler.NOMSU_COMPILER_VERSION = 8 + NomsuCompiler.NOMSU_COMPILER_VERSION = 9 NomsuCompiler.NOMSU_SYNTAX_VERSION = max_parser_version - NomsuCompiler.nomsu = NomsuCompiler - NomsuCompiler.global = Dict({ }) + NomsuCompiler.can_optimize = function() + return false + end + NomsuCompiler.environment = { + NOMSU_COMPILER_VERSION = 8, + NOMSU_SYNTAX_VERSION = max_parser_version, + next = next, + unpack = unpack, + setmetatable = setmetatable, + coroutine = coroutine, + rawequal = rawequal, + getmetatable = getmetatable, + pcall = pcall, + error = error, + package = package, + os = os, + require = require, + tonumber = tonumber, + tostring = tostring, + string = string, + xpcall = xpcall, + module = module, + print = print, + loadfile = loadfile, + rawset = rawset, + _VERSION = _VERSION, + collectgarbage = collectgarbage, + rawget = rawget, + rawlen = rawlen, + table = table, + assert = assert, + dofile = dofile, + loadstring = loadstring, + type = type, + select = select, + math = math, + io = io, + load = load, + pairs = pairs, + ipairs = ipairs, + _List = List, + _Dict = Dict, + repr = repr, + stringify = stringify, + utils = utils, + lpeg = lpeg, + re = re, + Files = Files, + AST = AST, + TESTS = Dict({ }, { + globals = Dict({ }) + }), + LuaCode = LuaCode, + NomsuCode = NomsuCode, + Source = Source, + nomsu = NomsuCompiler, + __imported = Dict({ }), + __parent = nil + } + setmetatable(NomsuCompiler.environment, { + __index = function(self, key) + do + local imported = rawget(self, "__imported") + if imported then + local ret = imported[key] + if not (ret == nil) then + return ret + end + end + end + do + local parent = rawget(self, "__parent") + if parent then + return parent[key] + end + end + end + }) + if _VERSION == "Lua 5.4" then + NomsuCompiler.environment.ipairs = function(x) + do + local mt = getmetatable(x) + if mt then + if mt.__ipairs then + return mt.__ipairs(x) + end + end + end + return ipairs(x) + end + end + if jit or _VERSION == "Lua 5.2" then + NomsuCompiler.environment.bit = require("bitops") + end + for k, v in pairs(AST) do + NomsuCompiler.environment[k] = v + end + NomsuCompiler.fork = function(self) + local f = setmetatable({ }, { + __index = self + }) + f.environment = setmetatable({ + __parent = self.environment, + __imported = Dict({ }), + nomsu = f, + COMPILE_ACTIONS = setmetatable({ + __parent = self.environment.COMPILE_ACTIONS, + __imported = Dict({ }) + }, getmetatable(self.environment)) + }, getmetatable(self.environment)) + return f + end NomsuCompiler.parse = function(self, nomsu_code, source, version) if source == nil then source = nil @@ -169,7 +280,6 @@ do local syntax_version = version and tonumber(version:match("^[0-9]+")) or max_parser_version local parse = Parsers[syntax_version] or Parsers[max_parser_version] local tree = parse(nomsu_code, source.filename) - local pretty_error = require("pretty_errors") local find_errors find_errors = function(t) if t.type == "Error" then @@ -230,101 +340,6 @@ do end return tree end - NomsuCompiler.can_optimize = function() - return false - end - local to_add = { - repr = repr, - stringify = stringify, - utils = utils, - lpeg = lpeg, - re = re, - Files = Files, - next = next, - unpack = unpack, - setmetatable = setmetatable, - coroutine = coroutine, - rawequal = rawequal, - getmetatable = getmetatable, - pcall = pcall, - error = error, - package = package, - os = os, - require = require, - tonumber = tonumber, - tostring = tostring, - string = string, - xpcall = xpcall, - module = module, - print = print, - loadfile = loadfile, - rawset = rawset, - _VERSION = _VERSION, - collectgarbage = collectgarbage, - rawget = rawget, - rawlen = rawlen, - table = table, - assert = assert, - dofile = dofile, - loadstring = loadstring, - type = type, - select = select, - math = math, - io = io, - load = load, - pairs = pairs, - ipairs = ipairs, - _List = List, - _Dict = Dict - } - if _VERSION == "Lua 5.4" then - to_add.ipairs = function(x) - do - local mt = getmetatable(x) - if mt then - if mt.__ipairs then - return mt.__ipairs(x) - end - end - end - return ipairs(x) - end - end - if jit or _VERSION == "Lua 5.2" then - to_add.bit = require("bitops") - end - for k, v in pairs(to_add) do - NomsuCompiler[k] = v - end - for k, v in pairs(AST) do - NomsuCompiler[k] = v - end - NomsuCompiler.LuaCode = LuaCode - NomsuCompiler.NomsuCode = NomsuCode - NomsuCompiler.Source = Source - NomsuCompiler.LOADED = { } - NomsuCompiler.TESTS = { } - NomsuCompiler.AST = AST - NomsuCompiler.fork = function(self) - local f = setmetatable({ }, { - __index = self - }) - f.COMPILE_ACTIONS = setmetatable({ }, { - __index = self.COMPILE_ACTIONS - }) - f.nomsu = f - return f - end - local math_expression = re.compile([[ ([+-] " ")* [0-9]+ (" " [*/^+-] (" " [+-])* " " [0-9]+)+ !. ]]) - NomsuCompiler.get_compile_action = function(self, stub) - local ret = self.COMPILE_ACTIONS[stub] - if not (ret == nil) then - return ret - end - if math_expression:match(stub) then - return self.COMPILE_ACTIONS["# compile math expr #"] - end - end NomsuCompiler.compile_error = function(self, source, err_format_string, ...) err_format_string = err_format_string:gsub("%%[^s]", "%%%1") local file = Files.read(source.filename) @@ -340,7 +355,7 @@ do return error(tostring(source.filename) .. ":" .. tostring(line_no) .. ": " .. err_msg, 0) end local add_lua_bits - add_lua_bits = function(self, val_or_stmt, code) + add_lua_bits = function(self, val_or_stmt, code, compile_actions) local cls = val_or_stmt == "value" and LuaCode.Value or LuaCode local operate_on_text operate_on_text = function(text) @@ -352,7 +367,7 @@ do elseif bit.type == "Text" then lua:append(operate_on_text(bit)) else - local bit_lua = self:compile(bit) + local bit_lua = self:compile(bit, compile_actions) if not (bit_lua.is_value) then self:compile_error(bit.source, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.") end @@ -397,28 +412,31 @@ do end return operate_on_text(code) end - NomsuCompiler.COMPILE_ACTIONS = { - ["# compile math expr #"] = function(self, tree, ...) - local lua = LuaCode.Value(tree.source) - for i, tok in ipairs(tree) do - if type(tok) == 'string' then - lua:append(tok) - else - local tok_lua = self:compile(tok) - if not (tok_lua.is_value) then - self:compile_error(tok.source, "Non-expression value inside math expression:\n%s") - end - if tok.type == "Action" then - tok_lua:parenthesize() - end - lua:append(tok_lua) + local math_expression = re.compile([[ ([+-] " ")* [0-9]+ (" " [*/^+-] (" " [+-])* " " [0-9]+)+ !. ]]) + local compile_math_expression + compile_math_expression = function(self, tree, ...) + local lua = LuaCode.Value(tree.source) + for i, tok in ipairs(tree) do + if type(tok) == 'string' then + lua:append(tok) + else + local tok_lua = self:compile(tok, compile_actions) + if not (tok_lua.is_value) then + self:compile_error(tok.source, "Non-expression value inside math expression:\n%s") end - if i < #tree then - lua:append(" ") + if tok.type == "Action" then + tok_lua:parenthesize() end + lua:append(tok_lua) end - return lua - end, + if i < #tree then + lua:append(" ") + end + end + return lua + end + NomsuCompiler.environment.COMPILE_ACTIONS = setmetatable({ + __imported = Dict({ }), ["Lua 1"] = function(self, tree, code) return add_lua_string_bits(self, 'statements', code) end, @@ -466,19 +484,46 @@ do end, ["Lua version"] = function(self, tree, code) return LuaCode.Value(tree.source, repr(_VERSION)) - end - } + end, + __parent = setmetatable({ }, { + __index = function(self, key) + if type(key) == 'string' and math_expression:match(key) then + return compile_math_expression + end + end + }) + }, getmetatable(NomsuCompiler.environment)) NomsuCompiler.import = function(self, mod) for k, v in pairs(mod) do - if not (k == "COMPILE_ACTIONS" or k == "nomsu" or k == "_ENV") then - self[k] = v + local _continue_0 = false + repeat + if k == "__imported" or k == "__parent" then + _continue_0 = true + break + end + self.environment.__imported[k] = v + _continue_0 = true + until true + if not _continue_0 then + break end end for k, v in pairs(mod.COMPILE_ACTIONS) do - self.COMPILE_ACTIONS[k] = v + local _continue_0 = false + repeat + if k == "__imported" or k == "__parent" then + _continue_0 = true + break + end + self.environment.COMPILE_ACTIONS.__imported[k] = self.environment.COMPILE_ACTIONS.__imported[k] or v + _continue_0 = true + until true + if not _continue_0 then + break + end end end - NomsuCompiler.run = function(self, to_run) + NomsuCompiler.run = function(self, to_run, compile_actions) local source = to_run.source or Source(to_run, 1, #to_run) if type(source) == 'string' then source = Source:from_string(source) @@ -504,7 +549,7 @@ do local all_lua = { } for _index_0 = 1, #tree do local chunk = tree[_index_0] - local lua = self:compile(chunk):as_statements("return ") + local lua = self:compile(chunk, compile_actions):as_statements("return ") lua:declare_locals() lua:prepend("-- File: " .. tostring(source.filename:gsub("\n.*", "...")) .. "\n") insert(all_lua, tostring(lua)) @@ -513,9 +558,10 @@ do return ret end local _running_files = { } - NomsuCompiler.run_file = function(self, filename) - if self.LOADED[filename] then - return self.LOADED[filename] + local _loaded_files = { } + NomsuCompiler.run_file = function(self, filename, compile_actions) + if _loaded_files[filename] then + return _loaded_files[filename] end for i, running in ipairs(_running_files) do if running == filename then @@ -535,10 +581,11 @@ do end insert(_running_files, filename) local mod = self:fork() + local ret = mod.environment mod.from_file = filename if match(filename, "%.lua$") then local file = assert(Files.read(filename), "Could not find file: " .. tostring(filename)) - local ret = mod:run_lua(LuaCode(Source(filename, 1, #file), file)) + ret = mod:run_lua(LuaCode(Source(filename, 1, #file), file)) or ret elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$") then local ran_lua if self.can_optimize(filename) then @@ -546,10 +593,7 @@ do do local file = Files.read(lua_filename) if file then - local ret = mod:run_lua(LuaCode(Source(lua_filename, 1, #file), file)) - if type(ret) == 'table' then - mod = ret - end + ret = mod:run_lua(LuaCode(Source(lua_filename, 1, #file), file)) or ret ran_lua = true end end @@ -559,21 +603,18 @@ do if not file then error("Tried to run file that does not exist: " .. tostring(filename)) end - local ret = mod:run(NomsuCode(Source(filename, 1, #file), file)) - if type(ret) == 'table' then - mod = ret - end + ret = mod:run(NomsuCode(Source(filename, 1, #file), file), compile_actions) or ret end else error("Invalid filetype for " .. tostring(filename), 0) end - self.LOADED[filename] = mod + _loaded_files[filename] = ret remove(_running_files) - return mod + return ret end NomsuCompiler.run_lua = function(self, lua) local lua_string = tostring(lua) - local run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self) + local run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self.environment) if not run_lua_fn then local line_numbered_lua = concat((function() local _accum_0 = { } @@ -623,7 +664,8 @@ do end return run_lua_fn() end - NomsuCompiler.compile = function(self, tree) + NomsuCompiler.compile = function(self, tree, compile_actions) + compile_actions = compile_actions or self.environment.COMPILE_ACTIONS if tree.version then do local get_version = self[("Nomsu version"):as_lua_id()] @@ -641,7 +683,7 @@ do if "Action" == _exp_0 then local stub = tree.stub do - local compile_action = self:get_compile_action(stub) + local compile_action = compile_actions[stub] if compile_action then local args do @@ -665,7 +707,7 @@ do end local lua = LuaCode.Value(tree.source) if tree.target then - local target_lua = self:compile(tree.target) + local target_lua = self:compile(tree.target, compile_actions) if tostring(target_lua):match("^%(.*%)$") or tostring(target_lua):match("^[_a-zA-Z][_a-zA-Z0-9]*$") then lua:append(target_lua, ":") else @@ -681,7 +723,7 @@ do _continue_0 = true break end - local arg_lua = self:compile(tok) + local arg_lua = self:compile(tok, compile_actions) if not (arg_lua.is_value) then if tok.type == "Block" then self:compile_error(tok.source, ("Cannot compile action '" .. tostring(stub) .. "' with a Block as an argument.\n" .. "Maybe there should be a compile-time action with that name that isn't being found?")) @@ -713,12 +755,12 @@ do elseif type(k) == 'string' and match(k, "[_a-zA-Z][_a-zA-Z0-9]*") then lua:append(k, "= ") else - lua:append("[", (AST.is_syntax_tree(k) and self:compile(k) or repr(k)), "]= ") + lua:append("[", (AST.is_syntax_tree(k) and self:compile(k, compile_actions) or repr(k)), "]= ") end if k == "source" then lua:append(repr(tostring(v))) else - lua:append(AST.is_syntax_tree(v) and self:compile(v) or repr(v)) + lua:append(AST.is_syntax_tree(v) and self:compile(v, compile_actions) or repr(v)) end end lua:append("}") @@ -730,7 +772,7 @@ do local _len_0 = 1 for _index_0 = 1, #tree do local line = tree[_index_0] - _accum_0[_len_0] = self:compile(line):as_statements() + _accum_0[_len_0] = self:compile(line, compile_actions):as_statements() _len_0 = _len_0 + 1 end return _accum_0 @@ -754,9 +796,9 @@ do lua:append(repr(string_buffer)) string_buffer = "" end - local bit_lua = self:compile(bit) + local bit_lua = self:compile(bit, compile_actions) if not (bit_lua.is_value) then - local src = ' ' .. gsub(tostring(self:compile(bit)), '\n', '\n ') + local src = ' ' .. gsub(tostring(self:compile(bit, compile_actions)), '\n', '\n ') local line = tostring(bit.source.filename) .. ":" .. tostring(Files.get_line_number(Files.read(bit.source.filename), bit.source.start)) self:compile_error(bit.source, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.") end @@ -790,7 +832,7 @@ do local _len_0 = 1 for _index_0 = 1, #tree do local e = tree[_index_0] - _accum_0[_len_0] = self:compile(e) + _accum_0[_len_0] = self:compile(e, compile_actions) _len_0 = _len_0 + 1 end return _accum_0 @@ -804,7 +846,7 @@ do local _len_0 = 1 for _index_0 = 1, #tree do local e = tree[_index_0] - _accum_0[_len_0] = self:compile(e) + _accum_0[_len_0] = self:compile(e, compile_actions) _len_0 = _len_0 + 1 end return _accum_0 @@ -813,11 +855,11 @@ do return lua elseif "DictEntry" == _exp_0 then local key, value = tree[1], tree[2] - local key_lua = self:compile(key) + local key_lua = self:compile(key, compile_actions) if not (key_lua.is_value) then self:compile_error(tree[1].source, "Cannot use:\n%s\nas a dict key, since it's not an expression.") end - local value_lua = value and self:compile(value) or LuaCode.Value(key.source, "true") + local value_lua = value and self:compile(value, compile_actions) or LuaCode.Value(key.source, "true") if not (value_lua.is_value) then self:compile_error(tree[2].source, "Cannot use:\n%s\nas a dict value, since it's not an expression.") end @@ -830,7 +872,7 @@ do return LuaCode(tree.source, "[", key_lua, "]=", value_lua) end elseif "IndexChain" == _exp_0 then - local lua = self:compile(tree[1]) + local lua = self:compile(tree[1], compile_actions) if not (lua.is_value) then self:compile_error(tree[1].source, "Cannot index:\n%s\nsince it's not an expression.") end @@ -840,7 +882,7 @@ do end for i = 2, #tree do local key = tree[i] - local key_lua = self:compile(key) + local key_lua = self:compile(key, compile_actions) if not (key_lua.is_value) then self:compile_error(key.source, "Cannot use:\n%s\nas an index, since it's not an expression.") end diff --git a/nomsu_compiler.moon b/nomsu_compiler.moon index 944f7b8..09e114e 100644 --- a/nomsu_compiler.moon +++ b/nomsu_compiler.moon @@ -25,6 +25,7 @@ unpack or= table.unpack {:NomsuCode, :LuaCode, :Source} = require "code_obj" AST = require "syntax_tree" make_parser = require("parser") +pretty_error = require("pretty_errors") -- Mapping from source string (e.g. "@core/metaprogramming.nom[1:100]") to a mapping -- from lua line number to nomsu line number export SOURCE_MAP @@ -84,13 +85,63 @@ for version=1,999 else break MAX_LINE = 80 -- For beautification purposes, try not to make lines much longer than this value -NomsuCompiler = setmetatable {}, __tostring: => "Nomsu" +NomsuCompiler = setmetatable {}, {__tostring: => "Nomsu"} _anon_chunk = 0 with NomsuCompiler - .NOMSU_COMPILER_VERSION = 8 + .NOMSU_COMPILER_VERSION = 9 .NOMSU_SYNTAX_VERSION = max_parser_version - .nomsu = NomsuCompiler - .global = Dict{} + .can_optimize = -> false + + -- Discretionary/convenience stuff + .environment = { + NOMSU_COMPILER_VERSION: 8, NOMSU_SYNTAX_VERSION: max_parser_version + -- Lua stuff: + :next, :unpack, :setmetatable, :coroutine, :rawequal, :getmetatable, :pcall, + :error, :package, :os, :require, :tonumber, :tostring, :string, :xpcall, :module, + :print, :loadfile, :rawset, :_VERSION, :collectgarbage, :rawget, :rawlen, + :table, :assert, :dofile, :loadstring, :type, :select, :math, :io, :load, + :pairs, :ipairs, + -- Nomsu types: + _List:List, _Dict:Dict, + -- Utilities and misc. + repr:repr, stringify:stringify, utils:utils, lpeg:lpeg, re:re, Files:Files, + :AST, TESTS: Dict{}, globals: Dict{} + :LuaCode, :NomsuCode, :Source + nomsu:NomsuCompiler + __imported: Dict{} + __parent: nil + } + setmetatable(.environment, { + __index: (key)=> + if imported = rawget(@, "__imported") + ret = imported[key] + return ret unless ret == nil + if parent = rawget(@, "__parent") + return parent[key] + }) + + if _VERSION == "Lua 5.4" + .environment.ipairs = (x)-> + if mt = getmetatable(x) + if mt.__ipairs then return mt.__ipairs(x) + return ipairs(x) + if jit or _VERSION == "Lua 5.2" + .environment.bit = require("bitops") + for k,v in pairs(AST) do .environment[k] = v + + .fork = => + f = setmetatable({}, {__index:@}) + f.environment = setmetatable({ + __parent: @environment + __imported: Dict{} + nomsu: f + COMPILE_ACTIONS: setmetatable({ + __parent: @environment.COMPILE_ACTIONS + __imported: Dict{} + }, getmetatable(@environment)) + }, getmetatable(@environment)) + return f + .parse = (nomsu_code, source=nil, version=nil)=> source or= nomsu_code.source nomsu_code = tostring(nomsu_code) @@ -101,7 +152,6 @@ with NomsuCompiler syntax_version = version and tonumber(version\match("^[0-9]+")) or max_parser_version parse = Parsers[syntax_version] or Parsers[max_parser_version] tree = parse(nomsu_code, source.filename) - pretty_error = require("pretty_errors") find_errors = (t)-> if t.type == "Error" coroutine.yield t @@ -121,52 +171,6 @@ with NomsuCompiler table.insert(err_strings, "\027[31;1m +#{num_errs-#errs} additional errors...\027[0m\n") error(table.concat(err_strings, '\n\n'), 0) return tree - .can_optimize = -> false - - -- Discretionary/convenience stuff - to_add = { - repr:repr, stringify:stringify, utils:utils, lpeg:lpeg, re:re, Files:Files, - -- Lua stuff: - :next, :unpack, :setmetatable, :coroutine, :rawequal, :getmetatable, :pcall, - :error, :package, :os, :require, :tonumber, :tostring, :string, :xpcall, :module, - :print, :loadfile, :rawset, :_VERSION, :collectgarbage, :rawget, :rawlen, - :table, :assert, :dofile, :loadstring, :type, :select, :math, :io, :load, - :pairs, :ipairs, - -- Nomsu types: - _List:List, _Dict:Dict, - } - if _VERSION == "Lua 5.4" - to_add.ipairs = (x)-> - if mt = getmetatable(x) - if mt.__ipairs then return mt.__ipairs(x) - return ipairs(x) - if jit or _VERSION == "Lua 5.2" - to_add.bit = require("bitops") - for k,v in pairs(to_add) do NomsuCompiler[k] = v - for k,v in pairs(AST) do NomsuCompiler[k] = v - .LuaCode = LuaCode - .NomsuCode = NomsuCode - .Source = Source - .LOADED = {} - .TESTS = {} - .AST = AST - - .fork = => - f = setmetatable({}, {__index:@}) - f.COMPILE_ACTIONS = setmetatable({}, {__index:@COMPILE_ACTIONS}) - f.nomsu = f - return f - - -- This is a bit of a hack, but this code handles arbitrarily complex - -- math expressions like 2*x + 3^2 without having to define a single - -- action for every possibility. - math_expression = re.compile [[ ([+-] " ")* [0-9]+ (" " [*/^+-] (" " [+-])* " " [0-9]+)+ !. ]] - - .get_compile_action = (stub)=> - ret = @COMPILE_ACTIONS[stub] - return ret unless ret == nil - if math_expression\match(stub) - return @COMPILE_ACTIONS["# compile math expr #"] -- TODO: use pretty_error instead of this .compile_error = (source, err_format_string, ...)=> @@ -183,7 +187,7 @@ with NomsuCompiler err_msg = err_format_string\format(src, ...) error("#{source.filename}:#{line_no}: "..err_msg, 0) - add_lua_bits = (val_or_stmt, code)=> + add_lua_bits = (val_or_stmt, code, compile_actions)=> cls = val_or_stmt == "value" and LuaCode.Value or LuaCode operate_on_text = (text)-> lua = cls(text.source) @@ -193,7 +197,7 @@ with NomsuCompiler elseif bit.type == "Text" lua\append(operate_on_text(bit)) else - bit_lua = @compile(bit) + bit_lua = @compile(bit, compile_actions) unless bit_lua.is_value @compile_error bit.source, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression." @@ -226,23 +230,25 @@ with NomsuCompiler return lua return operate_on_text code - .COMPILE_ACTIONS = { - ["# compile math expr #"]: (tree, ...)=> - lua = LuaCode.Value(tree.source) - for i,tok in ipairs tree - if type(tok) == 'string' - lua\append tok - else - tok_lua = @compile(tok) - unless tok_lua.is_value - @compile_error tok.source, "Non-expression value inside math expression:\n%s" - if tok.type == "Action" - tok_lua\parenthesize! - lua\append tok_lua - if i < #tree - lua\append " " - return lua - + -- This is a bit of a hack, but this code handles arbitrarily complex + -- math expressions like 2*x + 3^2 without having to define a single + -- action for every possibility. + math_expression = re.compile [[ ([+-] " ")* [0-9]+ (" " [*/^+-] (" " [+-])* " " [0-9]+)+ !. ]] + compile_math_expression = (tree, ...)=> + lua = LuaCode.Value(tree.source) + for i,tok in ipairs tree + if type(tok) == 'string' + lua\append tok + else + tok_lua = @compile(tok, compile_actions) + unless tok_lua.is_value + @compile_error tok.source, "Non-expression value inside math expression:\n%s" + tok_lua\parenthesize! if tok.type == "Action" + lua\append tok_lua + lua\append " " if i < #tree + return lua + .environment.COMPILE_ACTIONS = setmetatable({ + __imported: Dict{} ["Lua 1"]: (tree, code)=> return add_lua_string_bits(@, 'statements', code) @@ -276,15 +282,23 @@ with NomsuCompiler ["Lua version"]: (tree, code)=> return LuaCode.Value(tree.source, repr(_VERSION)) - } + + __parent: setmetatable({}, { + __index: (key)=> + if type(key) == 'string' and math_expression\match(key) + return compile_math_expression + }) + }, getmetatable(.environment)) .import = (mod)=> for k,v in pairs(mod) - @[k] = v unless k == "COMPILE_ACTIONS" or k == "nomsu" or k == "_ENV" + continue if k == "__imported" or k == "__parent" + @environment.__imported[k] = v for k,v in pairs(mod.COMPILE_ACTIONS) - @COMPILE_ACTIONS[k] = v + continue if k == "__imported" or k == "__parent" + @environment.COMPILE_ACTIONS.__imported[k] or= v - .run = (to_run)=> + .run = (to_run, compile_actions)=> source = to_run.source or Source(to_run, 1, #to_run) if type(source) == 'string' then source = Source\from_string(source) if not Files.read(source.filename) then Files.spoof(source.filename, to_run) @@ -299,7 +313,7 @@ with NomsuCompiler ret = nil all_lua = {} for chunk in *tree - lua = @compile(chunk)\as_statements("return ") + lua = @compile(chunk, compile_actions)\as_statements("return ") lua\declare_locals! lua\prepend "-- File: #{source.filename\gsub("\n.*", "...")}\n" insert all_lua, tostring(lua) @@ -307,10 +321,11 @@ with NomsuCompiler return ret _running_files = {} -- For detecting circular imports - .run_file = (filename)=> + _loaded_files = {} + .run_file = (filename, compile_actions)=> -- Filename should be an absolute path, i.e. package.nomsupath will not be searched for it - if @LOADED[filename] - return @LOADED[filename] + if _loaded_files[filename] + return _loaded_files[filename] -- Check for circular import -- TODO: optimize? for i,running in ipairs _running_files @@ -321,34 +336,31 @@ with NomsuCompiler insert _running_files, filename mod = @fork! + ret = mod.environment mod.from_file = filename if match(filename, "%.lua$") file = assert(Files.read(filename), "Could not find file: #{filename}") - ret = mod\run_lua(LuaCode(Source(filename, 1, #file), file)) + ret = mod\run_lua(LuaCode(Source(filename, 1, #file), file)) or ret elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$") ran_lua = if @.can_optimize(filename) -- Look for precompiled version lua_filename = gsub(filename, "%.nom$", ".lua") if file = Files.read(lua_filename) - ret = mod\run_lua(LuaCode(Source(lua_filename, 1, #file), file)) - if type(ret) == 'table' - mod = ret + ret = mod\run_lua(LuaCode(Source(lua_filename, 1, #file), file)) or ret true unless ran_lua file = Files.read(filename) if not file error("Tried to run file that does not exist: #{filename}") - ret = mod\run(NomsuCode(Source(filename,1,#file), file)) - if type(ret) == 'table' - mod = ret + ret = mod\run(NomsuCode(Source(filename,1,#file), file), compile_actions) or ret else error("Invalid filetype for #{filename}", 0) - @LOADED[filename] = mod + _loaded_files[filename] = ret remove _running_files - return mod + return ret .run_lua = (lua)=> lua_string = tostring(lua) - run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self) + run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", @environment) if not run_lua_fn line_numbered_lua = concat( [format("%3d|%s",i,line) for i, line in ipairs Files.get_lines(lua_string)], @@ -382,7 +394,8 @@ with NomsuCompiler return run_lua_fn! - .compile = (tree)=> + .compile = (tree, compile_actions)=> + compile_actions or= @environment.COMPILE_ACTIONS if tree.version if get_version = @[("Nomsu version")\as_lua_id!] if upgrade = @[("1 upgraded from 2 to 3")\as_lua_id!] @@ -390,7 +403,7 @@ with NomsuCompiler switch tree.type when "Action" stub = tree.stub - if compile_action = @get_compile_action(stub) + if compile_action = compile_actions[stub] args = [arg for arg in *tree when type(arg) != "string"] -- Force Lua to avoid tail call optimization for debugging purposes -- TODO: use tail call? @@ -402,7 +415,7 @@ with NomsuCompiler lua = LuaCode.Value(tree.source) if tree.target -- Method call - target_lua = @compile tree.target + target_lua = @compile tree.target, compile_actions if tostring(target_lua)\match("^%(.*%)$") or tostring(target_lua)\match("^[_a-zA-Z][_a-zA-Z0-9]*$") lua\append target_lua, ":" else @@ -411,7 +424,7 @@ with NomsuCompiler args = {} for i, tok in ipairs tree if type(tok) == "string" then continue - arg_lua = @compile(tok) + arg_lua = @compile(tok, compile_actions) unless arg_lua.is_value if tok.type == "Block" @compile_error tok.source, @@ -438,17 +451,17 @@ with NomsuCompiler elseif type(k) == 'string' and match(k,"[_a-zA-Z][_a-zA-Z0-9]*") lua\append(k, "= ") else - lua\append("[", (AST.is_syntax_tree(k) and @compile(k) or repr(k)), "]= ") + lua\append("[", (AST.is_syntax_tree(k) and @compile(k, compile_actions) or repr(k)), "]= ") if k == "source" lua\append repr(tostring(v)) else - lua\append(AST.is_syntax_tree(v) and @compile(v) or repr(v)) + lua\append(AST.is_syntax_tree(v) and @compile(v, compile_actions) or repr(v)) lua\append "}" return lua when "Block" lua = LuaCode(tree.source) - lua\concat_append([@compile(line)\as_statements! for line in *tree], "\n") + lua\concat_append([@compile(line, compile_actions)\as_statements! for line in *tree], "\n") return lua when "Text" @@ -462,9 +475,9 @@ with NomsuCompiler if #lua.bits > 0 then lua\append ".." lua\append repr(string_buffer) string_buffer = "" - bit_lua = @compile(bit) + bit_lua = @compile(bit, compile_actions) unless bit_lua.is_value - src = ' '..gsub(tostring(@compile(bit)), '\n','\n ') + src = ' '..gsub(tostring(@compile(bit, compile_actions)), '\n','\n ') line = "#{bit.source.filename}:#{Files.get_line_number(Files.read(bit.source.filename), bit.source.start)}" @compile_error bit.source, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression." @@ -483,23 +496,23 @@ with NomsuCompiler when "List" lua = LuaCode.Value tree.source, "_List{" - lua\concat_append([@compile(e) for e in *tree], ", ", ",\n ") + lua\concat_append([@compile(e, compile_actions) for e in *tree], ", ", ",\n ") lua\append "}" return lua when "Dict" lua = LuaCode.Value tree.source, "_Dict{" - lua\concat_append([@compile(e) for e in *tree], ", ", ",\n ") + lua\concat_append([@compile(e, compile_actions) for e in *tree], ", ", ",\n ") lua\append "}" return lua when "DictEntry" key, value = tree[1], tree[2] - key_lua = @compile(key) + key_lua = @compile(key, compile_actions) unless key_lua.is_value @compile_error tree[1].source, "Cannot use:\n%s\nas a dict key, since it's not an expression." - value_lua = value and @compile(value) or LuaCode.Value(key.source, "true") + value_lua = value and @compile(value, compile_actions) or LuaCode.Value(key.source, "true") unless value_lua.is_value @compile_error tree[2].source, "Cannot use:\n%s\nas a dict value, since it's not an expression." @@ -516,7 +529,7 @@ with NomsuCompiler LuaCode tree.source, "[",key_lua,"]=",value_lua when "IndexChain" - lua = @compile(tree[1]) + lua = @compile(tree[1], compile_actions) unless lua.is_value @compile_error tree[1].source, "Cannot index:\n%s\nsince it's not an expression." @@ -526,7 +539,7 @@ with NomsuCompiler for i=2,#tree key = tree[i] - key_lua = @compile(key) + key_lua = @compile(key, compile_actions) unless key_lua.is_value @compile_error key.source, "Cannot use:\n%s\nas an index, since it's not an expression." |
