aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--code_obj.lua31
-rw-r--r--code_obj.moon24
-rw-r--r--nomsu.lua260
-rwxr-xr-xnomsu.moon186
-rw-r--r--parser.lua2
-rw-r--r--parser.moon3
6 files changed, 182 insertions, 324 deletions
diff --git a/code_obj.lua b/code_obj.lua
index 6dbffca..de62c8f 100644
--- a/code_obj.lua
+++ b/code_obj.lua
@@ -98,26 +98,35 @@ do
end
self.__str = nil
end,
- concat_append = function(self, values, joiner)
+ concat_append = function(self, values, joiner, wrapping_joiner)
+ wrapping_joiner = wrapping_joiner or joiner
local bits, indents = self.bits, self.indents
local match = string.match
+ local line_len = 0
for i = 1, #values do
local b = values[i]
- assert(b)
if i > 1 then
- bits[#bits + 1] = joiner
+ if line_len > 80 then
+ bits[#bits + 1] = wrapping_joiner
+ line_len = 0
+ else
+ bits[#bits + 1] = joiner
+ end
end
bits[#bits + 1] = b
- if type(b) == 'string' then
- do
- local spaces = match(b, "\n([ ]*)[^\n]*$")
- if spaces then
- self.current_indent = #spaces
- end
- end
- elseif self.current_indent ~= 0 then
+ if type(b) ~= 'string' and self.current_indent ~= 0 then
indents[#bits] = self.current_indent
end
+ local b_str = tostring(b)
+ local line, spaces = match(b_str, "\n(([ ]*)[^\n]*)$")
+ if spaces then
+ if type(b) == 'string' then
+ self.current_indent = #spaces
+ end
+ line_len = #line
+ else
+ line_len = line_len + #b
+ end
end
self.__str = nil
end,
diff --git a/code_obj.moon b/code_obj.moon
index 9e2e324..73a1ba8 100644
--- a/code_obj.moon
+++ b/code_obj.moon
@@ -66,20 +66,30 @@ class Code
indents[#bits] = @current_indent
@__str = nil
- concat_append: (values, joiner)=>
+ concat_append: (values, joiner, wrapping_joiner)=>
+ wrapping_joiner or= joiner
bits, indents = @bits, @indents
match = string.match
+ line_len = 0
for i=1,#values
b = values[i]
- assert(b)
if i > 1
- bits[#bits+1] = joiner
+ if line_len > 80
+ bits[#bits+1] = wrapping_joiner
+ line_len = 0
+ else
+ bits[#bits+1] = joiner
bits[#bits+1] = b
- if type(b) == 'string'
- if spaces = match(b, "\n([ ]*)[^\n]*$")
- @current_indent = #spaces
- elseif @current_indent != 0
+ if type(b) != 'string' and @current_indent != 0
indents[#bits] = @current_indent
+ b_str = tostring(b)
+ line, spaces = match(b_str, "\n(([ ]*)[^\n]*)$")
+ if spaces
+ if type(b) == 'string'
+ @current_indent = #spaces
+ line_len = #line
+ else
+ line_len += #b
@__str = nil
prepend: (...)=>
diff --git a/nomsu.lua b/nomsu.lua
index f322abf..b8e5137 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -1,16 +1,10 @@
local lpeg = require('lpeg')
local re = require('re')
lpeg.setmaxstack(10000)
-local P, R, V, S, Cg, C, Cp, B, Cmt, Carg
-P, R, V, S, Cg, C, Cp, B, Cmt, Carg = lpeg.P, lpeg.R, lpeg.V, lpeg.S, lpeg.Cg, lpeg.C, lpeg.Cp, lpeg.B, lpeg.Cmt, lpeg.Carg
local utils = require('utils')
-local repr, stringify, min, max, equivalent, set, is_list, sum
-repr, stringify, min, max, equivalent, set, is_list, sum = utils.repr, utils.stringify, utils.min, utils.max, utils.equivalent, utils.set, utils.is_list, utils.sum
-local colors = setmetatable({ }, {
- __index = function()
- return ""
- end
-})
+local repr, stringify, equivalent
+repr, stringify, equivalent = utils.repr, utils.stringify, utils.equivalent
+colors = require('consolecolors')
colored = setmetatable({ }, {
__index = function(_, color)
return (function(msg)
@@ -35,6 +29,8 @@ do
local _obj_0 = require("code_obj")
NomsuCode, LuaCode, Source = _obj_0.NomsuCode, _obj_0.LuaCode, _obj_0.Source
end
+local AST = require("nomsu_tree")
+local parse = require("parser")
local STDIN, STDOUT, STDERR = "/dev/fd/0", "/dev/fd/1", "/dev/fd/2"
string.as_lua_id = function(str)
local argnum = 0
@@ -60,6 +56,11 @@ table.map = function(self, fn)
end
return _accum_0
end
+table.fork = function(t, values)
+ return setmetatable(values or { }, {
+ __index = t
+ })
+end
FILE_CACHE = setmetatable({ }, {
__index = function(self, filename)
local file = io.open(filename)
@@ -103,12 +104,12 @@ end
local line_counter = re.compile([[ lines <- {| line (%nl line)* |}
line <- {} (!%nl .)*
]], {
- nl = P("\r") ^ -1 * P("\n")
+ nl = lpeg.P("\r") ^ -1 * lpeg.P("\n")
})
local get_lines = re.compile([[ lines <- {| line (%nl line)* |}
line <- {[^%nl]*}
]], {
- nl = P("\r") ^ -1 * P("\n")
+ nl = lpeg.P("\r") ^ -1 * lpeg.P("\n")
})
LINE_STARTS = setmetatable({ }, {
__mode = "k",
@@ -127,7 +128,6 @@ LINE_STARTS = setmetatable({ }, {
return line_starts
end
})
-local pos_to_line
pos_to_line = function(str, pos)
local line_starts = LINE_STARTS[str]
local lo, hi = 1, #line_starts
@@ -158,9 +158,8 @@ do
end
end
end
-local AST = require("nomsu_tree")
local _list_mt = {
- __eq = utils.equivalent,
+ __eq = equivalent,
__tostring = function(self)
return "[" .. concat((function()
local _accum_0 = { }
@@ -179,7 +178,7 @@ list = function(t)
return setmetatable(t, _list_mt)
end
local _dict_mt = {
- __eq = utils.equivalent,
+ __eq = equivalent,
__tostring = function(self)
return "{" .. concat((function()
local _accum_0 = { }
@@ -212,7 +211,6 @@ local NomsuCompiler = setmetatable({ }, {
do
NomsuCompiler._ENV = NomsuCompiler
NomsuCompiler.nomsu = NomsuCompiler
- local parse = require("parser")
NomsuCompiler.parse = function(self, ...)
return parse(...)
end
@@ -270,9 +268,6 @@ do
NomsuCompiler.LuaCode = LuaCode
NomsuCompiler.NomsuCode = NomsuCode
NomsuCompiler.Source = Source
- NomsuCompiler.ARG_ORDERS = setmetatable({ }, {
- __mode = "k"
- })
NomsuCompiler.ALIASES = setmetatable({ }, {
__mode = "k"
})
@@ -337,7 +332,7 @@ do
end
end
NomsuCompiler.COMPILE_ACTIONS = setmetatable({
- compile_math_expr = function(self, tree, ...)
+ ["# compile math expr #"] = function(self, tree, ...)
local lua = LuaCode.Value(tree.source)
for i, tok in ipairs(tree) do
if type(tok) == 'string' then
@@ -393,19 +388,10 @@ do
}, {
__index = function(self, stub)
if math_expression:match(stub) then
- return self.compile_math_expr
+ return self["# compile math expr #"]
end
end
})
- NomsuCompiler.fork = function(self)
- return setmetatable({
- COMPILE_ACTIONS = setmetatable({ }, {
- __index = self.COMPILE_ACTIONS
- })
- }, {
- __index = self
- })
- end
NomsuCompiler.run = function(self, to_run, source)
if source == nil then
source = nil
@@ -453,10 +439,12 @@ do
for filename in all_files(filename) do
local _continue_0 = false
repeat
- if self.LOADED[filename] then
+ do
ret = self.LOADED[filename]
- _continue_0 = true
- break
+ if ret then
+ _continue_0 = true
+ break
+ end
end
for i, running in ipairs(_running_files) do
if running == filename then
@@ -471,7 +459,7 @@ do
loop = _accum_0
end
insert(loop, filename)
- error("Circular import, this loops forever: " .. tostring(concat(loop, " -> ")))
+ error("Circular import, this loops forever: " .. tostring(concat(loop, " -> ")) .. "...")
end
end
insert(_running_files, filename)
@@ -479,21 +467,24 @@ do
local file = assert(FILE_CACHE[filename], "Could not find file: " .. tostring(filename))
ret = self:run_lua(file, Source(filename, 1, #file))
elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$") then
+ local ran_lua
if not self.skip_precompiled then
local lua_filename = gsub(filename, "%.nom$", ".lua")
- local file = FILE_CACHE[lua_filename]
- if file then
- ret = self:run_lua(file, Source(filename, 1, #file))
- remove(_running_files)
- _continue_0 = true
- break
+ do
+ local file = FILE_CACHE[lua_filename]
+ if file then
+ ret = self:run_lua(file, Source(lua_filename, 1, #file))
+ ran_lua = true
+ end
end
end
- local file = file or FILE_CACHE[filename]
- if not file then
- error("File does not exist: " .. tostring(filename), 0)
+ if not (ran_lua) then
+ local file = file or FILE_CACHE[filename]
+ if not file then
+ error("File does not exist: " .. tostring(filename), 0)
+ end
+ ret = self:run(file, Source(filename, 1, #file))
end
- ret = self:run(file, Source(filename, 1, #file))
else
error("Invalid filetype for " .. tostring(filename), 0)
end
@@ -515,13 +506,15 @@ do
local lua_string = tostring(lua)
local run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self)
if not run_lua_fn then
- local n = 1
- local fn
- fn = function()
- n = n + 1
- return ("\n%-3d|"):format(n)
- end
- local line_numbered_lua = "1 |" .. lua_string:gsub("\n", fn)
+ local line_numbered_lua = concat((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ for i, line in ipairs(get_lines:match(lua_string)) do
+ _accum_0[_len_0] = format("%3d|%s", i, line)
+ _len_0 = _len_0 + 1
+ end
+ return _accum_0
+ end)(), "\n")
error("Failed to compile generated code:\n" .. tostring(colored.bright(colored.blue(colored.onblack(line_numbered_lua)))) .. "\n\n" .. tostring(err), 0)
end
local source_key = tostring(source or lua.source)
@@ -559,7 +552,6 @@ do
return run_lua_fn()
end
NomsuCompiler.compile = function(self, tree)
- assert(LuaCode)
local _exp_0 = tree.type
if "Action" == _exp_0 then
local stub = tree.stub
@@ -579,21 +571,6 @@ do
end
args = _accum_0
end
- do
- local arg_orders = self.ARG_ORDERS[stub]
- if arg_orders then
- do
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #arg_orders do
- local p = arg_orders[_index_0]
- _accum_0[_len_0] = args[p]
- _len_0 = _len_0 + 1
- end
- args = _accum_0
- end
- end
- end
local ret = compile_action(self, tree, unpack(args))
if not ret then
self:compile_error(tree, "Compile-time action:\n%s\nfailed to produce any Lua")
@@ -601,28 +578,7 @@ do
return ret
end
end
- local action = self['A' .. string.as_lua_id(stub)]
- local lua = LuaCode.Value(tree.source)
- if not action and math_expression:match(stub) then
- 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, "Non-expression value inside math expression:\n%s")
- end
- if tok.type == "Action" then
- tok_lua:parenthesize()
- end
- lua:append(tok_lua)
- end
- if i < #tree then
- lua:append(" ")
- end
- end
- return lua
- end
+ local lua = LuaCode.Value(tree.source, "A", string.as_lua_id(stub), "(")
local args = { }
for i, tok in ipairs(tree) do
local _continue_0 = false
@@ -642,30 +598,7 @@ do
break
end
end
- if action then
- do
- local arg_orders = self.ARG_ORDERS[stub]
- if arg_orders then
- do
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #arg_orders do
- local p = arg_orders[_index_0]
- _accum_0[_len_0] = args[p]
- _len_0 = _len_0 + 1
- end
- args = _accum_0
- end
- end
- end
- end
- lua:append("A", string.as_lua_id(stub), "(")
- for i, arg in ipairs(args) do
- lua:append(arg)
- if i < #args then
- lua:append(", ")
- end
- end
+ lua:concat_append(args, ", ")
lua:append(")")
return lua
elseif "EscapedNomsu" == _exp_0 then
@@ -690,13 +623,16 @@ do
return LuaCode.Value(tree.source, make_tree(tree[1]))
elseif "Block" == _exp_0 then
local lua = LuaCode(tree.source)
- for i, line in ipairs(tree) do
- local line_lua = self:compile(line)
- if i > 1 then
- lua:append("\n")
+ lua:concat_append((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #tree do
+ local line = tree[_index_0]
+ _accum_0[_len_0] = self:compile(line):as_statements()
+ _len_0 = _len_0 + 1
end
- lua:append(line_lua:as_statements())
- end
+ return _accum_0
+ end)(), "\n")
return lua
elseif "Text" == _exp_0 then
local lua = LuaCode.Value(tree.source)
@@ -747,55 +683,29 @@ do
return lua
elseif "List" == _exp_0 then
local lua = LuaCode.Value(tree.source, "list{")
- local line_length = 0
+ local items = { }
for i, item in ipairs(tree) do
local item_lua = self:compile(item)
if not (item_lua.is_value) then
self:compile_error(item, "Cannot use:\n%s\nas a list item, since it's not an expression.")
end
- lua:append(item_lua)
- local item_string = tostring(item_lua)
- local last_line = match(item_string, "[^\n]*$")
- if match(item_string, "\n") then
- line_length = #last_line
- else
- line_length = line_length + #last_line
- end
- if i < #tree then
- if line_length >= MAX_LINE then
- lua:append(",\n ")
- line_length = 0
- else
- lua:append(", ")
- line_length = line_length + 2
- end
- end
+ items[i] = item_lua
end
+ lua:concat_append(items, ", ", ",\n ")
lua:append("}")
return lua
elseif "Dict" == _exp_0 then
local lua = LuaCode.Value(tree.source, "dict{")
- local line_length = 0
- for i, entry in ipairs(tree) do
- local entry_lua = self:compile(entry)
- lua:append(entry_lua)
- local entry_lua_str = tostring(entry_lua)
- local last_line = match(entry_lua_str, "\n([^\n]*)$")
- if last_line then
- line_length = #last_line
- else
- line_length = line_length + #entry_lua_str
- end
- if i < #tree then
- if line_length >= MAX_LINE then
- lua:append(",\n ")
- line_length = 0
- else
- lua:append(", ")
- line_length = line_length + 2
- end
+ lua:concat_append((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #tree do
+ local e = tree[_index_0]
+ _accum_0[_len_0] = self:compile(e)
+ _len_0 = _len_0 + 1
end
- end
+ return _accum_0
+ end)(), ", ", ",\n ")
lua:append("}")
return lua
elseif "DictEntry" == _exp_0 then
@@ -848,6 +758,8 @@ do
return LuaCode.Value(tree.source, tostring(tree[1]))
elseif "Var" == _exp_0 then
return LuaCode.Value(tree.source, string.as_lua_id(tree[1]))
+ elseif "FileChunks" == _exp_0 then
+ return error("Cannot convert FileChunks to a single block of lua, since each chunk's " .. "compilation depends on the earlier chunks")
else
return error("Unknown type: " .. tostring(tree.type))
end
@@ -860,7 +772,23 @@ do
can_use_colon = false
end
local _exp_0 = tree.type
- if "Action" == _exp_0 then
+ if "FileChunks" == _exp_0 then
+ if inline then
+ return nil
+ end
+ local nomsu = NomsuCode(tree.source)
+ nomsu:concat_append((function()
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #tree do
+ local c = tree[_index_0]
+ _accum_0[_len_0] = self:tree_to_nomsu(c)
+ _len_0 = _len_0 + 1
+ end
+ return _accum_0
+ end)(), "\n" .. tostring(("~"):rep(80)) .. "\n")
+ return nomsu
+ elseif "Action" == _exp_0 then
if inline then
local nomsu = NomsuCode(tree.source)
for i, bit in ipairs(tree) do
@@ -1221,7 +1149,6 @@ do
end
end
if arg and debug_getinfo(2).func ~= require then
- colors = require('consolecolors')
local parser = re.compile([[ args <- {| (flag ";")* {:inputs: {| ({file} ";")* |} :} {:nomsu_args: {| ("--;" ({[^;]*} ";")*)? |} :} ";"? |} !.
flag <-
{:interactive: ("-i" -> true) :}
@@ -1294,12 +1221,6 @@ OPTIONS
end
if info.short_src or info.source or info.linedefine or info.currentline then
do
- local arg_orders = nomsu.ARG_ORDERS[info.func]
- if arg_orders then
- info.name = next(arg_orders)
- end
- end
- do
local map = nomsu.source_map[info.source]
if map then
if info.currentline then
@@ -1383,14 +1304,7 @@ OPTIONS
local file = FILE_CACHE[filename]:sub(tonumber(start), tonumber(stop))
local err_line = get_line(file, calling_fn.currentline):sub(1, -2)
local offending_statement = colored.bright(colored.red(err_line:match("^[ ]*(.*)")))
- do
- local arg_orders = nomsu.ARG_ORDERS[calling_fn.func]
- if arg_orders then
- name = "action '" .. tostring(next(arg_orders)) .. "'"
- else
- name = "main chunk"
- end
- end
+ name = "action '" .. tostring(calling_fn.name) .. "'"
line = colored.yellow(tostring(filename) .. ":" .. tostring(calling_fn.currentline) .. " in " .. tostring(name) .. "\n " .. tostring(offending_statement))
else
local file
diff --git a/nomsu.moon b/nomsu.moon
index 1e6a89f..230b4fb 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -13,17 +13,18 @@
lpeg = require 'lpeg'
re = require 're'
lpeg.setmaxstack 10000
-{:P,:R,:V,:S,:Cg,:C,:Cp,:B,:Cmt,:Carg} = lpeg
utils = require 'utils'
-{:repr, :stringify, :min, :max, :equivalent, :set, :is_list, :sum} = utils
-colors = setmetatable({}, {__index:->""})
-export colored
+{:repr, :stringify, :equivalent} = utils
+export colors, colored
+colors = require 'consolecolors'
colored = setmetatable({}, {__index:(_,color)-> ((msg)-> colors[color]..tostring(msg or '')..colors.reset)})
{:insert, :remove, :concat} = table
unpack or= table.unpack
{:match, :sub, :rep, :gsub, :format, :byte, :match, :find} = string
debug_getinfo = debug.getinfo
{:NomsuCode, :LuaCode, :Source} = require "code_obj"
+AST = require "nomsu_tree"
+parse = require("parser")
STDIN, STDOUT, STDERR = "/dev/fd/0", "/dev/fd/1", "/dev/fd/2"
string.as_lua_id = (str)->
@@ -40,15 +41,11 @@ string.as_lua_id = (str)->
return '_'..str
table.map = (fn)=> [fn(v) for _,v in ipairs(@)]
+table.fork = (t, values)-> setmetatable(values or {}, {__index:t})
-- TODO:
-- consider non-linear codegen, rather than doing thunks for things like comprehensions
--- type checking?
--- Add compiler options for optimization level (compile-fast vs. run-fast, etc.)
--- Do a pass on all actions to enforce parameters-are-nouns heuristic
--- Maybe do some sort of lazy definitions of actions that defer until they're used in code
-- Add a ((%x foo %y) where {x:"asdf", y:"fdsa"}) compile-time action for substitution
--- Maybe support some kind of regex action definitions like "foo %first (and %next)*"?
-- Re-implement nomsu-to-lua comment translation?
export FILE_CACHE
@@ -84,11 +81,11 @@ all_files = (path)->
line_counter = re.compile([[
lines <- {| line (%nl line)* |}
line <- {} (!%nl .)*
-]], nl:P("\r")^-1 * P("\n"))
+]], nl:lpeg.P("\r")^-1 * lpeg.P("\n"))
get_lines = re.compile([[
lines <- {| line (%nl line)* |}
line <- {[^%nl]*}
-]], nl:P("\r")^-1 * P("\n"))
+]], nl:lpeg.P("\r")^-1 * lpeg.P("\n"))
-- Mapping from line number -> character offset
export LINE_STARTS
-- LINE_STARTS is a mapping from strings to a table that maps line number to character positions
@@ -104,6 +101,7 @@ LINE_STARTS = setmetatable {}, {
self[k] = line_starts
return line_starts
}
+export pos_to_line
pos_to_line = (str, pos)->
line_starts = LINE_STARTS[str]
-- Binary search for line number of position
@@ -127,17 +125,17 @@ do
if type(i) == 'number' then return sub(@, i, i)
elseif type(i) == 'table' then return sub(@, i[1], i[2])
-AST = require "nomsu_tree"
-
+-- List and Dict classes to provide basic equality/tostring functionality for the tables
+-- used in Nomsu. This way, they retain a notion of whether they were originally lists or dicts.
_list_mt =
- __eq:utils.equivalent
+ __eq:equivalent
-- Could consider adding a __newindex to enforce list-ness, but would hurt performance
__tostring: =>
"["..concat([repr(b) for b in *@], ", ").."]"
list = (t)-> setmetatable(t, _list_mt)
_dict_mt =
- __eq:utils.equivalent
+ __eq:equivalent
__tostring: =>
"{"..concat(["#{repr(k)}: #{repr(v)}" for k,v in pairs @], ", ").."}"
dict = (t)-> setmetatable(t, _dict_mt)
@@ -147,7 +145,6 @@ NomsuCompiler = setmetatable({}, {__index: (k)=> if _self = rawget(@, "self") th
with NomsuCompiler
._ENV = NomsuCompiler
.nomsu = NomsuCompiler
- parse = require("parser")
.parse = (...)=> parse(...)
-- Mapping from source string (e.g. "@core/metaprogramming.nom[1:100]") to a mapping
@@ -170,7 +167,6 @@ with NomsuCompiler
.LuaCode = LuaCode
.NomsuCode = NomsuCode
.Source = Source
- .ARG_ORDERS = setmetatable({}, {__mode:"k"})
.ALIASES = setmetatable({}, {__mode:"k"})
.LOADED = {}
.AST = AST
@@ -226,7 +222,7 @@ with NomsuCompiler
lua\append bit_lua
.COMPILE_ACTIONS = setmetatable {
- compile_math_expr: (tree, ...)=>
+ ["# compile math expr #"]: (tree, ...)=>
lua = LuaCode.Value(tree.source)
for i,tok in ipairs tree
if type(tok) == 'string'
@@ -234,8 +230,7 @@ with NomsuCompiler
else
tok_lua = @compile(tok)
unless tok_lua.is_value
- @compile_error tok,
- "Non-expression value inside math expression:\n%s"
+ @compile_error tok, "Non-expression value inside math expression:\n%s"
if tok.type == "Action"
tok_lua\parenthesize!
lua\append tok_lua
@@ -274,17 +269,17 @@ with NomsuCompiler
}, {
__index: (stub)=>
if math_expression\match(stub)
- return @compile_math_expr
+ return @["# compile math expr #"]
}
- .fork = =>
- setmetatable({COMPILE_ACTIONS:setmetatable({}, {__index:@COMPILE_ACTIONS})}, {__index:@})
-
.run = (to_run, source=nil)=>
tree = if AST.is_syntax_tree(to_run) then tree else @parse(to_run, source or to_run.source)
if tree == nil -- Happens if pattern matches, but there are no captures, e.g. an empty string
return nil
if tree.type == "FileChunks"
+ -- Each chunk's compilation is affected by the code in the previous chunks
+ -- (typically), so each chunk needs to compile and run before the next one
+ -- compiles.
ret = nil
all_lua = {}
for chunk in *tree
@@ -310,32 +305,31 @@ with NomsuCompiler
return @LOADED[filename]
ret = nil
for filename in all_files(filename)
- if @LOADED[filename]
- ret = @LOADED[filename]
+ if ret = @LOADED[filename]
continue
+ -- Check for circular import
for i,running in ipairs _running_files
if running == filename
loop = [_running_files[j] for j=i,#_running_files]
insert loop, filename
- error("Circular import, this loops forever: #{concat loop, " -> "}")
+ error("Circular import, this loops forever: #{concat loop, " -> "}...")
insert _running_files, filename
if match(filename, "%.lua$")
file = assert(FILE_CACHE[filename], "Could not find file: #{filename}")
ret = @run_lua file, Source(filename, 1, #file)
elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$")
- if not @skip_precompiled -- Look for precompiled version
+ ran_lua = if not @skip_precompiled -- Look for precompiled version
lua_filename = gsub(filename, "%.nom$", ".lua")
- file = FILE_CACHE[lua_filename]
- if file
- ret = @run_lua file, Source(filename, 1, #file)
- remove _running_files
- continue
- file = file or FILE_CACHE[filename]
- if not file
- error("File does not exist: #{filename}", 0)
- ret = @run file, Source(filename,1,#file)
+ if file = FILE_CACHE[lua_filename]
+ ret = @run_lua file, Source(lua_filename, 1, #file)
+ true
+ unless ran_lua
+ file = file or FILE_CACHE[filename]
+ if not file
+ error("File does not exist: #{filename}", 0)
+ ret = @run file, Source(filename,1,#file)
else
error("Invalid filetype for #{filename}", 0)
@LOADED[filename] = ret or true
@@ -348,11 +342,9 @@ with NomsuCompiler
lua_string = tostring(lua)
run_lua_fn, err = load(lua_string, nil and tostring(source or lua.source), "t", self)
if not run_lua_fn
- n = 1
- fn = ->
- n = n + 1
- ("\n%-3d|")\format(n)
- line_numbered_lua = "1 |"..lua_string\gsub("\n", fn)
+ line_numbered_lua = concat(
+ [format("%3d|%s",i,line) for i, line in ipairs get_lines\match(lua_string)],
+ "\n")
error("Failed to compile generated code:\n#{colored.bright colored.blue colored.onblack line_numbered_lua}\n\n#{err}", 0)
source_key = tostring(source or lua.source)
unless @source_map[source_key]
@@ -381,14 +373,11 @@ with NomsuCompiler
return run_lua_fn!
.compile = (tree)=>
- assert(LuaCode)
switch tree.type
when "Action"
stub = tree.stub
if compile_action = @COMPILE_ACTIONS[stub]
args = [arg for arg in *tree when type(arg) != "string"]
- if arg_orders = @ARG_ORDERS[stub]
- args = [args[p] for p in *arg_orders]
-- Force Lua to avoid tail call optimization for debugging purposes
-- TODO: use tail call?
ret = compile_action(@, tree, unpack(args))
@@ -397,28 +386,7 @@ with NomsuCompiler
"Compile-time action:\n%s\nfailed to produce any Lua"
return ret
- action = @['A'..string.as_lua_id(stub)]
-
- lua = LuaCode.Value(tree.source)
- if not action and math_expression\match(stub)
- -- 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.
- 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,
- "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
-
+ lua = LuaCode.Value(tree.source, "A",string.as_lua_id(stub),"(")
args = {}
for i, tok in ipairs tree
if type(tok) == "string" then continue
@@ -428,15 +396,7 @@ with NomsuCompiler
"Cannot use:\n%s\nas an argument to %s, since it's not an expression, it produces: %s",
stub, repr arg_lua
insert args, arg_lua
-
- if action
- if arg_orders = @ARG_ORDERS[stub]
- args = [args[p] for p in *arg_orders]
-
- lua\append "A",string.as_lua_id(stub),"("
- for i, arg in ipairs args
- lua\append arg
- if i < #args then lua\append ", "
+ lua\concat_append args, ", "
lua\append ")"
return lua
@@ -450,11 +410,7 @@ with NomsuCompiler
when "Block"
lua = LuaCode(tree.source)
- for i,line in ipairs tree
- line_lua = @compile(line)
- if i > 1
- lua\append "\n"
- lua\append line_lua\as_statements!
+ lua\concat_append([@compile(line)\as_statements! for line in *tree], "\n")
return lua
when "Text"
@@ -489,49 +445,20 @@ with NomsuCompiler
when "List"
lua = LuaCode.Value tree.source, "list{"
- line_length = 0
+ items = {}
for i, item in ipairs tree
item_lua = @compile(item)
unless item_lua.is_value
@compile_error item,
"Cannot use:\n%s\nas a list item, since it's not an expression."
- lua\append item_lua
- item_string = tostring(item_lua)
- last_line = match(item_string, "[^\n]*$")
- if match(item_string, "\n")
- line_length = #last_line
- else
- line_length += #last_line
- if i < #tree
- if line_length >= MAX_LINE
- lua\append ",\n "
- line_length = 0
- else
- lua\append ", "
- line_length += 2
+ items[i] = item_lua
+ lua\concat_append(items, ", ", ",\n ")
lua\append "}"
return lua
when "Dict"
lua = LuaCode.Value tree.source, "dict{"
- line_length = 0
- for i, entry in ipairs tree
- entry_lua = @compile(entry)
- lua\append entry_lua
- entry_lua_str = tostring(entry_lua)
- -- TODO: maybe make this more accurate? It's only a heuristic, so eh...
- last_line = match(entry_lua_str, "\n([^\n]*)$")
- if last_line
- line_length = #last_line
- else
- line_length += #entry_lua_str
- if i < #tree
- if line_length >= MAX_LINE
- lua\append ",\n "
- line_length = 0
- else
- lua\append ", "
- line_length += 2
+ lua\concat_append([@compile(e) for e in *tree], ", ", ",\n ")
lua\append "}"
return lua
@@ -545,6 +472,7 @@ with NomsuCompiler
unless value_lua.is_value
@compile_error tree[2],
"Cannot use:\n%s\nas a dict value, since it's not an expression."
+ -- TODO: support arbitrary words here, like operators and unicode
key_str = match(tostring(key_lua), [=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
return if key_str
LuaCode tree.source, key_str,"=",value_lua
@@ -588,12 +516,22 @@ with NomsuCompiler
when "Var"
LuaCode.Value(tree.source, string.as_lua_id(tree[1]))
-
+
+ when "FileChunks"
+ error("Cannot convert FileChunks to a single block of lua, since each chunk's "..
+ "compilation depends on the earlier chunks")
+
else
error("Unknown type: #{tree.type}")
.tree_to_nomsu = (tree, inline=false, can_use_colon=false)=>
switch tree.type
+ when "FileChunks"
+ return nil if inline
+ nomsu = NomsuCode(tree.source)
+ nomsu\concat_append [@tree_to_nomsu(c) for c in *tree], "\n#{("~")\rep(80)}\n"
+ return nomsu
+
when "Action"
if inline
nomsu = NomsuCode(tree.source)
@@ -858,18 +796,9 @@ with NomsuCompiler
error("Unknown type: #{tree.type}")
-
-
-
-
-- Command line interface:
-
-
-
-- Only run this code if this file was run directly with command line arguments, and not require()'d:
if arg and debug_getinfo(2).func != require
- export colors
- colors = require 'consolecolors'
parser = re.compile([[
args <- {| (flag ";")* {:inputs: {| ({file} ";")* |} :} {:nomsu_args: {| ("--;" ({[^;]*} ";")*)? |} :} ";"? |} !.
flag <-
@@ -926,8 +855,7 @@ OPTIONS
else debug_getinfo(thread,f,what)
if not info or not info.func then return info
if info.short_src or info.source or info.linedefine or info.currentline
- if arg_orders = nomsu.ARG_ORDERS[info.func]
- info.name = next(arg_orders)
+ -- TODO: get name properly
if map = nomsu.source_map[info.source]
if info.currentline
info.currentline = assert(map[info.currentline])
@@ -981,10 +909,8 @@ OPTIONS
file = FILE_CACHE[filename]\sub(tonumber(start),tonumber(stop))
err_line = get_line(file, calling_fn.currentline)\sub(1,-2)
offending_statement = colored.bright(colored.red(err_line\match("^[ ]*(.*)")))
- if arg_orders = nomsu.ARG_ORDERS[calling_fn.func]
- name = "action '#{next(arg_orders)}'"
- else
- name = "main chunk"
+ -- TODO: get name properly
+ name = "action '#{calling_fn.name}'"
line = colored.yellow("#{filename}:#{calling_fn.currentline} in #{name}\n #{offending_statement}")
else
ok, file = pcall ->FILE_CACHE[calling_fn.short_src]
diff --git a/parser.lua b/parser.lua
index e995c3c..863e17e 100644
--- a/parser.lua
+++ b/parser.lua
@@ -127,7 +127,7 @@ do
ident <- [a-zA-Z_][a-zA-Z0-9_]*
comment <- "--" [^%nl]*
]])
- local nomsu_peg = peg_tidier:match(FILE_CACHE["nomsu.peg"])
+ local nomsu_peg = peg_tidier:match(io.open("nomsu.peg"):read('*a'))
NOMSU_PATTERN = re.compile(nomsu_peg, NOMSU_DEFS)
end
local parse
diff --git a/parser.moon b/parser.moon
index cac126c..ad9d0d0 100644
--- a/parser.moon
+++ b/parser.moon
@@ -67,7 +67,6 @@ NOMSU_DEFS = with {}
err_line = colored.white(err_line\sub(1, i))..colored.bright(colored.red(err_line\sub(i+1,i+1)))..colored.dim(err_line\sub(i+2,-1))
err_msg ..= "\n#{err_line}\n#{colored.red pointer}"
if #next_line > 0 then err_msg ..= "\n"..colored.dim(next_line)
- --error(err_msg)
seen_errors[start_pos] = err_msg
return true
@@ -98,7 +97,7 @@ NOMSU_PATTERN = do
ident <- [a-zA-Z_][a-zA-Z0-9_]*
comment <- "--" [^%nl]*
]]
- nomsu_peg = peg_tidier\match(FILE_CACHE["nomsu.peg"])
+ nomsu_peg = peg_tidier\match(io.open("nomsu.peg")\read('*a'))
re.compile(nomsu_peg, NOMSU_DEFS)
parse = (nomsu_code, source=nil)->