aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2018-06-12 18:04:18 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2018-06-12 18:04:41 -0700
commit3c510e4ee5027aa5191e994bdf0a080a32a4b082 (patch)
treeb8d740f6ce0e263faa92967a63d16af07f3d45e7
parentb5fb8933af283d2b873a03ded085e8b69f374e81 (diff)
Lots of optimizations and simplifications, especially towards getting
better performance on luajit.
-rw-r--r--code_obj.lua6
-rw-r--r--code_obj.moon6
-rwxr-xr-xcompile_lib.sh4
-rw-r--r--core/control_flow.nom12
-rw-r--r--core/metaprogramming.nom10
-rw-r--r--core/operators.nom3
-rw-r--r--nomsu.lua174
-rwxr-xr-xnomsu.moon119
-rw-r--r--nomsu.peg4
-rw-r--r--nomsu_tree.lua76
-rw-r--r--nomsu_tree.moon45
-rw-r--r--tests/control_flow.nom21
12 files changed, 189 insertions, 291 deletions
diff --git a/code_obj.lua b/code_obj.lua
index 47e08cb..39f6c95 100644
--- a/code_obj.lua
+++ b/code_obj.lua
@@ -187,7 +187,7 @@ do
for _index_0 = 1, #vars do
local var = vars[_index_0]
assert(var.type == "Var")
- removals[var.value] = true
+ removals[var[1]] = true
end
local stack = {
self
@@ -196,7 +196,7 @@ do
local lua
lua, stack[#stack] = stack[#stack], nil
for i = #lua.free_vars, 1, -1 do
- if removals[lua.free_vars[i].value] then
+ if removals[lua.free_vars[i][1]] then
remove(lua.free_vars, i)
end
end
@@ -264,7 +264,7 @@ do
local _len_0 = 1
for _index_0 = 1, #to_declare do
local v = to_declare[_index_0]
- _accum_0[_len_0] = string.as_lua_id(v.value)
+ _accum_0[_len_0] = string.as_lua_id(v[1])
_len_0 = _len_0 + 1
end
return _accum_0
diff --git a/code_obj.moon b/code_obj.moon
index 45df615..dae3f52 100644
--- a/code_obj.moon
+++ b/code_obj.moon
@@ -109,13 +109,13 @@ class Lua extends Code
removals = {}
for var in *vars
assert(var.type == "Var")
- removals[var.value] = true
+ removals[var[1]] = true
stack = {self}
while #stack > 0
lua, stack[#stack] = stack[#stack], nil
for i=#lua.free_vars,1,-1
- if removals[lua.free_vars[i].value]
+ if removals[lua.free_vars[i][1]]
remove lua.free_vars, i
for b in *lua.bits
if type(b) != 'string'
@@ -147,7 +147,7 @@ class Lua extends Code
gather_from self
if #to_declare > 0
@remove_free_vars to_declare
- @prepend "local #{concat [string.as_lua_id(v.value) for v in *to_declare], ", "};\n"
+ @prepend "local #{concat [string.as_lua_id(v[1]) for v in *to_declare], ", "};\n"
return to_declare
__tostring: =>
diff --git a/compile_lib.sh b/compile_lib.sh
index fa932b3..d7df5f8 100755
--- a/compile_lib.sh
+++ b/compile_lib.sh
@@ -6,11 +6,11 @@ moonc *.moon
rm -f core/*.lua lib/*.lua
for file in core/*.nom; do
printf "Compiling $file ..."
- lua ./nomsu.lua -O -o "core/$(basename $file .nom).lua" $file
+ luajit ./nomsu.lua -O -o "core/$(basename $file .nom).lua" $file
echo "done."
done
for file in lib/*.nom; do
printf "Compiling $file ..."
- lua ./nomsu.lua -O -o "lib/$(basename $file .nom).lua" $file
+ luajit ./nomsu.lua -O -o "lib/$(basename $file .nom).lua" $file
echo "done."
done
diff --git a/core/control_flow.nom b/core/control_flow.nom
index 73a0f43..f0238a4 100644
--- a/core/control_flow.nom
+++ b/core/control_flow.nom
@@ -188,14 +188,14 @@ immediately
%body has subtree % where
(%.type = "Action") and
(%.stub is "do next %") and
- %.3.value = %var.value
+ %.3.(1) = %var.(1)
..: to %lua write (Lua "\n ::continue_\(%var as lua identifier)::")
to %lua write "\nend --foreach-loop"
if
%body has subtree % where
(%.type = "Action") and
(%.stub is "stop %") and
- %.2.value = %var.value
+ %.2.(1) = %var.(1)
..
%lua <-
Lua ".."
@@ -222,14 +222,14 @@ immediately
%body has subtree % where
(%.type = "Action") and
(%.stub is "do next %") and
- %.3.value = %key.value
+ %.3.(1) = %key.(1)
..: to %lua write (Lua "\n ::continue_\(%key as lua identifier)::")
if
%body has subtree % where
(%.type = "Action") and
(%.stub is "do next %") and
- %.3.value = %value.value
+ %.3.(1) = %value.(1)
..: to %lua write (Lua "\n ::continue_\(%value as lua identifier)::")
to %lua write "\nend --foreach-loop"
@@ -238,14 +238,14 @@ immediately
%body has subtree % where
(%.type = "Action") and
(%.stub is "stop %") and
- %.2.value = %key.value
+ %.2.(1) = %key.(1)
..: to %stop_labels write "\n::stop_\(%key as lua identifier)::"
if
%body has subtree % where
(%.type = "Action") and
(%.stub is "stop %") and
- %.2.value = %value.value
+ %.2.(1) = %value.(1)
..: to %stop_labels write "\n::stop_\(%value as lua identifier)::"
if: (length of %stop_labels) > 0
diff --git a/core/metaprogramming.nom b/core/metaprogramming.nom
index ec65f3e..e413191 100644
--- a/core/metaprogramming.nom
+++ b/core/metaprogramming.nom
@@ -82,7 +82,7 @@ immediately
for i,tok in ipairs(\%shorthand[1]) do
if tok.type == "Var" then
local lua_var = tostring(nomsu:tree_to_lua(tok))
- replacements[tok.value] = lua_var
+ replacements[tok[1]] = lua_var
lua:append(", ", lua_var)
end
end
@@ -90,12 +90,10 @@ immediately
local function make_tree(t)
if type(t) ~= 'table' and type(t) ~= 'userdata' then
return repr(t)
- elseif t.type == 'Var' and replacements[t.value] then
- return replacements[t.value]
+ elseif t.type == 'Var' and replacements[t[1]] then
+ return replacements[t[1]]
elseif t.type == 'Var' then
- return t.type.."("..repr(tostring(t.source))..", "..repr(t.value.."#"..tostring(MANGLE_INDEX))..")"
- elseif t.value then
- return t.type.."("..repr(tostring(t.source))..", "..repr(t.value)..")"
+ return t.type.."("..repr(tostring(t.source))..", "..repr(t[1].."#"..tostring(MANGLE_INDEX))..")"
else
local bits = {repr(tostring(t.source))}
for i, entry in ipairs(t) do
diff --git a/core/operators.nom b/core/operators.nom
index 4ec8ff1..555a636 100644
--- a/core/operators.nom
+++ b/core/operators.nom
@@ -160,8 +160,7 @@ immediately
# Unary operators
compile [- %] to: Lua value "(- \(% as lua expr))"
compile [not %] to: Lua value "(not \(% as lua expr))"
- # Using custom "len()" instead of Lua's "#" operator for compatibility with luajit.
- compile [length of %list] to: Lua value "len(\(%list as lua expr))"
+ compile [length of %list] to: Lua value "(#\(%list as lua expr))"
# Update operators
immediately
diff --git a/nomsu.lua b/nomsu.lua
index e9d394f..4f61c29 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -1,33 +1,10 @@
local _pairs, _ipairs = pairs, ipairs
if jit then
package.cpath = "./luajit_lpeg/?.so;" .. package.cpath
- lpeg = require('lpeg')
+ package.path = "./luajit_lpeg/?.lua;" .. package.path
bit32 = require('bit')
- pairs = function(x)
- do
- local mt = getmetatable(x)
- if mt then
- if mt.__pairs then
- return mt.__pairs(x)
- end
- end
- end
- return _pairs(x)
- end
- 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
-else
- lpeg = require('lpeg')
end
+lpeg = require('lpeg')
re = require('re')
lpeg.setmaxstack(10000)
local P, R, V, S, Cg, C, Cp, B, Cmt, Carg
@@ -53,6 +30,11 @@ do
local _obj_0 = table
insert, remove, concat = _obj_0.insert, _obj_0.remove, _obj_0.concat
end
+local match, sub, rep, gsub, format, byte
+do
+ local _obj_0 = string
+ match, sub, rep, gsub, format, byte, match = _obj_0.match, _obj_0.sub, _obj_0.rep, _obj_0.gsub, _obj_0.format, _obj_0.byte, _obj_0.match
+end
local debug_getinfo = debug.getinfo
local Nomsu, Lua, Source
do
@@ -61,11 +43,11 @@ do
end
local STDIN, STDOUT, STDERR = "/dev/fd/0", "/dev/fd/1", "/dev/fd/2"
string.as_lua_id = function(str)
- return "_" .. (str:gsub("%W", function(c)
+ return "_" .. (gsub(str, "%W", function(c)
if c == "_" then
return "__"
else
- return ("_%x"):format(c:byte())
+ return format("_%x", byte(c))
end
end))
end
@@ -91,10 +73,13 @@ iterate_single = function(item, prev)
end
local all_files
all_files = function(path)
- if path:match("%.nom$") or path:match("%.lua$") or path:match("^/dev/fd/[012]$") then
+ if match(path, "%.nom$") or match(path, "%.lua$") or match(path, "^/dev/fd/[012]$") then
return iterate_single, path
end
- path = path:gsub("\\", "\\\\"):gsub("`", ""):gsub('"', '\\"'):gsub("$", "")
+ path = gsub(path, "\\", "\\\\")
+ path = gsub(path, "`", "")
+ path = gsub(path, '"', '\\"')
+ path = gsub(path, "$", "")
return coroutine.wrap(function()
local f = io.popen('find -L "' .. path .. '" -not -path "*/\\.*" -type f -name "*.nom"')
for line in f:lines() do
@@ -153,9 +138,9 @@ do
return ret
end
if type(i) == 'number' then
- return string.sub(self, i, i)
+ return sub(self, i, i)
elseif type(i) == 'table' then
- return string.sub(self, i[1], i[2])
+ return sub(self, i[1], i[2])
end
end
end
@@ -187,19 +172,19 @@ do
_with_0.utf8_char = (R("\194\223") * R("\128\191") + R("\224\239") * R("\128\191") * R("\128\191") + R("\240\244") * R("\128\191") * R("\128\191") * R("\128\191"))
_with_0.ident_char = R("az", "AZ", "09") + P("_") + _with_0.utf8_char
_with_0.indent = Cmt(Carg(1), function(self, start, userdata)
- if #self:match("^[ ]*", start) >= userdata.indent + 4 then
+ if #match(self, "^[ ]*", start) >= userdata.indent + 4 then
userdata.indent = userdata.indent + 4
return start + userdata.indent
end
end)
_with_0.dedent = Cmt(Carg(1), function(self, start, userdata)
- if #self:match("^[ ]*", start) <= userdata.indent - 4 then
+ if #match(self, "^[ ]*", start) <= userdata.indent - 4 then
userdata.indent = userdata.indent - 4
return start
end
end)
_with_0.nodent = Cmt(Carg(1), function(self, start, userdata)
- if #self:match("^[ ]*", start) >= userdata.indent then
+ if #match(self, "^[ ]*", start) >= userdata.indent then
return start + userdata.indent
end
end)
@@ -403,12 +388,12 @@ do
end
end
insert(_running_files, filename)
- if filename:match("%.lua$") then
+ if match(filename, "%.lua$") then
local file = assert(FILE_CACHE[filename], "Could not find file: " .. tostring(filename))
ret = self:run_lua(Lua(Source(filename, 1, #file), file))
- elseif filename:match("%.nom$") or filename:match("^/dev/fd/[012]$") then
+ elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$") then
if not self.skip_precompiled then
- local lua_filename = filename:gsub("%.nom$", ".lua")
+ local lua_filename = gsub(filename, "%.nom$", ".lua")
local file = FILE_CACHE[lua_filename]
if file then
ret = self:run_lua(Lua(Source(filename, 1, #file), file))
@@ -439,7 +424,7 @@ do
run_lua = function(self, lua)
assert(type(lua) ~= 'string', "Attempt to run lua string instead of Lua (object)")
local lua_string = tostring(lua)
- local run_lua_fn, err = load(lua_string, nil and tostring(lua.source), "t", self.environment)
+ local run_lua_fn, err = load(lua_string, tostring(lua.source), "t", self.environment)
if not run_lua_fn then
local n = 1
local fn
@@ -590,22 +575,18 @@ do
if not (AST.is_syntax_tree(t)) then
return repr(t)
end
- if t.value then
- return t.type .. "(" .. repr(tostring(t.source)) .. ", " .. repr(t.value) .. ")"
- else
- local bits
- do
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #t do
- local bit = t[_index_0]
- _accum_0[_len_0] = make_tree(bit)
- _len_0 = _len_0 + 1
- end
- bits = _accum_0
+ local bits
+ do
+ local _accum_0 = { }
+ local _len_0 = 1
+ for _index_0 = 1, #t do
+ local bit = t[_index_0]
+ _accum_0[_len_0] = make_tree(bit)
+ _len_0 = _len_0 + 1
end
- return t.type .. "(" .. repr(tostring(t.source)) .. ", " .. table.concat(bits, ", ") .. ")"
+ bits = _accum_0
end
+ return t.type .. "(" .. repr(tostring(t.source)) .. ", " .. table.concat(bits, ", ") .. ")"
end
return Lua.Value(tree.source, make_tree(tree[1]))
elseif "Block" == _exp_0 then
@@ -638,7 +619,7 @@ do
end
local bit_lua = self:tree_to_lua(bit)
if not (bit_lua.is_value) then
- local src = ' ' .. tostring(self:tree_to_nomsu(bit)):gsub('\n', '\n ')
+ local src = ' ' .. gsub(tostring(self:tree_to_nomsu(bit)), '\n', '\n ')
local line = tostring(bit.source.filename) .. ":" .. tostring(pos_to_line(FILE_CACHE[bit.source.filename], bit.source.start))
compile_error(bit, "Cannot use:\n%s\nas a string interpolation value, since it's not an expression.")
end
@@ -675,8 +656,8 @@ do
end
lua:append(item_lua)
local item_string = tostring(item_lua)
- local last_line = item_string:match("[^\n]*$")
- if item_string:match("\n") then
+ local last_line = match(item_string, "[^\n]*$")
+ if match(item_string, "\n") then
line_length = #last_line
else
line_length = line_length + #last_line
@@ -700,7 +681,7 @@ do
local entry_lua = self:tree_to_lua(entry)
lua:append(entry_lua)
local entry_lua_str = tostring(entry_lua)
- local last_line = entry_lua_str:match("\n([^\n]*)$")
+ local last_line = match(entry_lua_str, "\n([^\n]*)$")
if last_line then
line_length = #last_line
else
@@ -728,10 +709,10 @@ do
if not (value_lua.is_value) then
compile_error(tree[2], "Cannot use:\n%s\nas a dict value, since it's not an expression.")
end
- local key_str = tostring(key_lua):match([=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
+ local key_str = match(tostring(key_lua), [=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
if key_str then
return Lua(tree.source, key_str, "=", value_lua)
- elseif tostring(key_lua):sub(1, 1) == "[" then
+ elseif sub(tostring(key_lua), 1, 1) == "[" then
return Lua(tree.source, "[ ", key_lua, "]=", value_lua)
else
return Lua(tree.source, "[", key_lua, "]=", value_lua)
@@ -741,7 +722,7 @@ do
if not (lua.is_value) then
compile_error(tree[1], "Cannot index:\n%s\nsince it's not an expression.")
end
- local first_char = tostring(lua):sub(1, 1)
+ local first_char = sub(tostring(lua), 1, 1)
if first_char == "{" or first_char == '"' or first_char == "[" then
lua:parenthesize()
end
@@ -753,10 +734,10 @@ do
end
local key_lua_str = tostring(key_lua)
do
- local lua_id = key_lua_str:match("^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$")
+ local lua_id = match(key_lua_str, "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$")
if lua_id then
lua:append("." .. tostring(lua_id))
- elseif key_lua_str:sub(1, 1) == '[' then
+ elseif sub(key_lua_str, 1, 1) == '[' then
lua:append("[ ", key_lua, " ]")
else
lua:append("[", key_lua, "]")
@@ -765,9 +746,9 @@ do
end
return lua
elseif "Number" == _exp_0 then
- return Lua.Value(tree.source, tostring(tree.value))
+ return Lua.Value(tree.source, tostring(tree[1]))
elseif "Var" == _exp_0 then
- return Lua.Value(tree.source, string.as_lua_id(tree.value))
+ return Lua.Value(tree.source, string.as_lua_id(tree[1]))
else
return error("Unknown type: " .. tostring(tree.type))
end
@@ -824,7 +805,7 @@ do
if arg_nomsu and #arg_nomsu < MAX_LINE then
if bit.type == "Action" then
if can_use_colon and i > 1 then
- nomsu:append(next_space:match("[^ ]*"), ": ", arg_nomsu)
+ nomsu:append(match(next_space, "[^ ]*"), ": ", arg_nomsu)
next_space = "\n.."
last_colon = i
else
@@ -853,7 +834,7 @@ do
nomsu:append(next_space, arg_nomsu)
next_space = "\n.."
end
- if next_space == " " and #(tostring(nomsu):match("[^\n]*$")) > MAX_LINE then
+ if next_space == " " and #(match(tostring(nomsu), "[^\n]*$")) > MAX_LINE then
next_space = "\n.."
end
end
@@ -888,7 +869,7 @@ do
nomsu:append(line)
if i < #tree then
nomsu:append("\n")
- if tostring(line):match("\n") then
+ if match(tostring(line), "\n") then
nomsu:append("\n")
end
end
@@ -900,7 +881,7 @@ do
for _index_0 = 1, #tree do
local bit = tree[_index_0]
if type(bit) == 'string' then
- nomsu:append((bit:gsub("\\", "\\\\"):gsub("\n", "\\n")))
+ nomsu:append((gsub(gsub(bit, "\\", "\\\\"), "\n", "\\n")))
else
local interp_nomsu = self:tree_to_nomsu(bit, true)
if interp_nomsu then
@@ -923,7 +904,7 @@ do
local nomsu = Nomsu(tree.source, '".."\n ')
for i, bit in ipairs(self) do
if type(bit) == 'string' then
- nomsu:append((bit:gsub("\\", "\\\\"):gsub("\n", "\n ")))
+ nomsu:append((gsub(gsub(bit, "\\", "\\\\"), "\n", "\\n")))
else
local interp_nomsu = self:tree_to_nomsu(bit, true)
if interp_nomsu then
@@ -1085,9 +1066,9 @@ do
end
return nomsu
elseif "Number" == _exp_0 then
- return Nomsu(tree.source, tostring(tree.value))
+ return Nomsu(tree.source, tostring(tree[1]))
elseif "Var" == _exp_0 then
- return Nomsu(tree.source, "%", tree.value)
+ return Nomsu(tree.source, "%", tree[1])
else
return error("Unknown type: " .. tostring(tree.type))
end
@@ -1268,60 +1249,11 @@ do
math = math,
io = io,
load = load,
+ pairs = pairs,
+ ipairs = ipairs,
list = list,
dict = dict
}
- if jit then
- self.environment.len = function(x)
- do
- local mt = getmetatable(x)
- if mt then
- if mt.__len then
- return mt.__len(x)
- end
- end
- end
- return #x
- end
- else
- self.environment.len = (function(x)
- return #x
- end)
- end
- self.environment.ipairs = function(x)
- if type(x) == 'function' then
- return coroutine.wrap(x)
- elseif type(x) == 'thread' then
- return coroutine.resume, x, nil
- else
- do
- local mt = getmetatable(x)
- if mt then
- if mt.__ipairs then
- return mt.__ipairs(x)
- end
- end
- end
- end
- return _ipairs(x)
- end
- self.environment.pairs = function(x)
- if type(x) == 'function' then
- return coroutine.wrap(x)
- elseif type(x) == 'thread' then
- return coroutine.resume, x, nil
- else
- do
- local mt = getmetatable(x)
- if mt then
- if mt.__pairs then
- return mt.__pairs(x)
- end
- end
- end
- end
- return _pairs(x)
- end
for k, v in pairs(AST) do
self.environment[k] = v
end
diff --git a/nomsu.moon b/nomsu.moon
index bef479b..5aaf683 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -14,27 +14,12 @@ export lpeg, re
_pairs, _ipairs = pairs, ipairs
if jit
package.cpath = "./luajit_lpeg/?.so;"..package.cpath
- --package.path = "./LPegLJ/src/?.lua;"..package.path
- --lpeg = require "lpeglj"
- lpeg = require 'lpeg'
+ package.path = "./luajit_lpeg/?.lua;"..package.path
export bit32
bit32 = require('bit')
- export pairs, ipairs
- pairs = (x)->
- if mt = getmetatable(x)
- if mt.__pairs
- return mt.__pairs(x)
- return _pairs(x)
- ipairs = (x)->
- if mt = getmetatable(x)
- if mt.__ipairs
- return mt.__ipairs(x)
- return _ipairs(x)
-else
- lpeg = require 'lpeg'
-
+lpeg = require 'lpeg'
re = require 're'
lpeg.setmaxstack 10000
{:P,:R,:V,:S,:Cg,:C,:Cp,:B,:Cmt,:Carg} = lpeg
@@ -45,12 +30,13 @@ colors = setmetatable({}, {__index:->""})
export colored
colored = setmetatable({}, {__index:(_,color)-> ((msg)-> colors[color]..tostring(msg or '')..colors.reset)})
{:insert, :remove, :concat} = table
+{:match, :sub, :rep, :gsub, :format, :byte, :match} = string
debug_getinfo = debug.getinfo
{:Nomsu, :Lua, :Source} = require "code_obj"
STDIN, STDOUT, STDERR = "/dev/fd/0", "/dev/fd/1", "/dev/fd/2"
string.as_lua_id = (str)->
- "_"..(str\gsub("%W", (c)-> if c == "_" then "__" else ("_%x")\format(c\byte!)))
+ "_"..(gsub(str, "%W", (c)-> if c == "_" then "__" else format("_%x", byte(c))))
-- TODO:
-- consider non-linear codegen, rather than doing thunks for things like comprehensions
@@ -77,10 +63,13 @@ FILE_CACHE = setmetatable {}, {
iterate_single = (item, prev) -> if item == prev then nil else item
all_files = (path)->
-- Sanitize path
- if path\match("%.nom$") or path\match("%.lua$") or path\match("^/dev/fd/[012]$")
+ if match(path, "%.nom$") or match(path, "%.lua$") or match(path, "^/dev/fd/[012]$")
return iterate_single, path
-- TODO: improve sanitization
- path = path\gsub("\\","\\\\")\gsub("`","")\gsub('"','\\"')\gsub("$","")
+ path = gsub(path,"\\","\\\\")
+ path = gsub(path,"`","")
+ path = gsub(path,'"','\\"')
+ path = gsub(path,"$","")
return coroutine.wrap ->
f = io.popen('find -L "'..path..'" -not -path "*/\\.*" -type f -name "*.nom"')
for line in f\lines!
@@ -128,8 +117,8 @@ do
STRING_METATABLE.__index = (i)=>
ret = string[i]
if ret != nil then return ret
- if type(i) == 'number' then return string.sub(@, i, i)
- elseif type(i) == 'table' then return string.sub(@, i[1], i[2])
+ if type(i) == 'number' then return sub(@, i, i)
+ elseif type(i) == 'table' then return sub(@, i[1], i[2])
AST = require "nomsu_tree"
@@ -153,19 +142,19 @@ NOMSU_DEFS = with {}
-- If the line begins with #indent+4 spaces, the pattern matches *those* spaces
-- and adds them to the stack (not any more).
.indent = Cmt Carg(1), (start, userdata)=>
- if #@match("^[ ]*", start) >= userdata.indent + 4
+ if #match(@, "^[ ]*", start) >= userdata.indent + 4
userdata.indent += 4
return start + userdata.indent
-- If the number of leading space characters is <= the number of space on the top of the
-- stack minus 4, this pattern matches and pops off the top of the stack exactly once.
.dedent = Cmt Carg(1), (start, userdata)=>
- if #@match("^[ ]*", start) <= userdata.indent - 4
+ if #match(@, "^[ ]*", start) <= userdata.indent - 4
userdata.indent -= 4
return start
-- If the number of leading space characters is >= the number on the top of the
-- stack, this pattern matches and does not modify the stack.
.nodent = Cmt Carg(1), (start, userdata)=>
- if #@match("^[ ]*", start) >= userdata.indent
+ if #match(@, "^[ ]*", start) >= userdata.indent
return start + userdata.indent
.userdata = Carg(1)
@@ -178,8 +167,6 @@ NOMSU_DEFS = with {}
seen_errors[start_pos+1] = colored.bright colored.yellow colored.onred "Too many errors, canceling parsing..."
return #src+1
err_pos = start_pos
- --if src\sub(err_pos,err_pos)\match("[\r\n]")
- -- err_pos += #src\match("[ \t\n\r]*", err_pos)
line_no = pos_to_line(src, err_pos)
src = FILE_CACHE[userdata.source.filename]
line_starts = LINE_STARTS[src]
@@ -276,34 +263,10 @@ class NomsuCompiler
:error, :package, :os, :require, :tonumber, :tostring, :string, :xpcall, :module,
:print, :loadfile, :rawset, :_VERSION, :collectgarbage, :rawget, :bit32, :rawlen,
:table, :assert, :dofile, :loadstring, :type, :select, :debug, :math, :io, :load,
+ :pairs, :ipairs,
-- Nomsu types:
:list, :dict,
}
- @environment.len = if jit
- (x)->
- if mt = getmetatable(x)
- if mt.__len
- return mt.__len(x)
- return #x
- else ((x) -> #x)
- @environment.ipairs = (x)->
- if type(x) == 'function'
- return coroutine.wrap(x)
- elseif type(x) == 'thread'
- return coroutine.resume, x, nil
- elseif mt = getmetatable(x)
- if mt.__ipairs
- return mt.__ipairs(x)
- return _ipairs(x)
- @environment.pairs = (x)->
- if type(x) == 'function'
- return coroutine.wrap(x)
- elseif type(x) == 'thread'
- return coroutine.resume, x, nil
- elseif mt = getmetatable(x)
- if mt.__pairs
- return mt.__pairs(x)
- return _pairs(x)
for k,v in pairs(AST) do @environment[k] = v
@environment.Lua = Lua
@environment.Nomsu = Nomsu
@@ -400,12 +363,12 @@ class NomsuCompiler
error("Circular import, this loops forever: #{concat loop, " -> "}")
insert _running_files, filename
- if filename\match("%.lua$")
+ if match(filename, "%.lua$")
file = assert(FILE_CACHE[filename], "Could not find file: #{filename}")
ret = @run_lua(Lua(Source(filename, 1, #file), file))
- elseif filename\match("%.nom$") or filename\match("^/dev/fd/[012]$")
+ elseif match(filename, "%.nom$") or match(filename, "^/dev/fd/[012]$")
if not @skip_precompiled -- Look for precompiled version
- lua_filename = filename\gsub("%.nom$", ".lua")
+ lua_filename = gsub(filename, "%.nom$", ".lua")
file = FILE_CACHE[lua_filename]
if file
ret = @run_lua(Lua(Source(filename, 1, #file), file))
@@ -426,7 +389,7 @@ class NomsuCompiler
run_lua: (lua)=>
assert(type(lua) != 'string', "Attempt to run lua string instead of Lua (object)")
lua_string = tostring(lua)
- run_lua_fn, err = load(lua_string, nil and tostring(lua.source), "t", @environment)
+ run_lua_fn, err = load(lua_string, tostring(lua.source), "t", @environment)
if not run_lua_fn
n = 1
fn = ->
@@ -526,11 +489,8 @@ class NomsuCompiler
make_tree = (t)->
unless AST.is_syntax_tree(t)
return repr(t)
- if t.value
- return t.type.."("..repr(tostring t.source)..", "..repr(t.value)..")"
- else
- bits = [make_tree(bit) for bit in *t]
- return t.type.."("..repr(tostring t.source)..", "..table.concat(bits, ", ")..")"
+ bits = [make_tree(bit) for bit in *t]
+ return t.type.."("..repr(tostring t.source)..", "..table.concat(bits, ", ")..")"
Lua.Value tree.source, make_tree(tree[1])
when "Block"
@@ -555,7 +515,7 @@ class NomsuCompiler
string_buffer = ""
bit_lua = @tree_to_lua(bit)
unless bit_lua.is_value
- src = ' '..tostring(@tree_to_nomsu(bit))\gsub('\n','\n ')
+ src = ' '..gsub(tostring(@tree_to_nomsu(bit)), '\n','\n ')
line = "#{bit.source.filename}:#{pos_to_line(FILE_CACHE[bit.source.filename], bit.source.start)}"
compile_error bit,
"Cannot use:\n%s\nas a string interpolation value, since it's not an expression."
@@ -582,8 +542,8 @@ class NomsuCompiler
"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 = item_string\match("[^\n]*$")
- if item_string\match("\n")
+ last_line = match(item_string, "[^\n]*$")
+ if match(item_string, "\n")
line_length = #last_line
else
line_length += #last_line
@@ -605,7 +565,7 @@ class NomsuCompiler
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 = entry_lua_str\match("\n([^\n]*)$")
+ last_line = match(entry_lua_str, "\n([^\n]*)$")
if last_line
line_length = #last_line
else
@@ -630,10 +590,10 @@ class NomsuCompiler
unless value_lua.is_value
compile_error tree[2],
"Cannot use:\n%s\nas a dict value, since it's not an expression."
- key_str = tostring(key_lua)\match([=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
+ key_str = match(tostring(key_lua), [=[["']([a-zA-Z_][a-zA-Z0-9_]*)['"]]=])
return if key_str
Lua tree.source, key_str,"=",value_lua
- elseif tostring(key_lua)\sub(1,1) == "["
+ elseif sub(tostring(key_lua),1,1) == "["
-- NOTE: this *must* use a space after the [ to avoid freaking out
-- Lua's parser if the inner expression is a long string. Lua
-- parses x[[[y]]] as x("[y]"), not as x["y"]
@@ -646,7 +606,7 @@ class NomsuCompiler
unless lua.is_value
compile_error tree[1],
"Cannot index:\n%s\nsince it's not an expression."
- first_char = tostring(lua)\sub(1,1)
+ first_char = sub(tostring(lua),1,1)
if first_char == "{" or first_char == '"' or first_char == "["
lua\parenthesize!
@@ -657,9 +617,9 @@ class NomsuCompiler
compile_error key,
"Cannot use:\n%s\nas an index, since it's not an expression."
key_lua_str = tostring(key_lua)
- if lua_id = key_lua_str\match("^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$")
+ if lua_id = match(key_lua_str, "^['\"]([a-zA-Z_][a-zA-Z0-9_]*)['\"]$")
lua\append ".#{lua_id}"
- elseif key_lua_str\sub(1,1) == '['
+ elseif sub(key_lua_str,1,1) == '['
-- NOTE: this *must* use a space after the [ to avoid freaking out
-- Lua's parser if the inner expression is a long string. Lua
-- parses x[[[y]]] as x("[y]"), not as x["y"]
@@ -669,10 +629,10 @@ class NomsuCompiler
return lua
when "Number"
- Lua.Value(tree.source, tostring(tree.value))
+ Lua.Value(tree.source, tostring(tree[1]))
when "Var"
- Lua.Value(tree.source, string.as_lua_id(tree.value))
+ Lua.Value(tree.source, string.as_lua_id(tree[1]))
else
error("Unknown type: #{tree.type}")
@@ -713,7 +673,7 @@ class NomsuCompiler
if arg_nomsu and #arg_nomsu < MAX_LINE
if bit.type == "Action"
if can_use_colon and i > 1
- nomsu\append next_space\match("[^ ]*"), ": ", arg_nomsu
+ nomsu\append match(next_space,"[^ ]*"), ": ", arg_nomsu
next_space = "\n.."
last_colon = i
else
@@ -737,7 +697,7 @@ class NomsuCompiler
nomsu\append next_space, arg_nomsu
next_space = "\n.."
- if next_space == " " and #(tostring(nomsu)\match("[^\n]*$")) > MAX_LINE
+ if next_space == " " and #(match(tostring(nomsu),"[^\n]*$")) > MAX_LINE
next_space = "\n.."
return nomsu
@@ -764,7 +724,7 @@ class NomsuCompiler
nomsu\append line
if i < #tree
nomsu\append "\n"
- if tostring(line)\match("\n")
+ if match(tostring(line), "\n")
nomsu\append "\n"
return nomsu
@@ -774,7 +734,7 @@ class NomsuCompiler
for bit in *tree
if type(bit) == 'string'
-- TODO: unescape better?
- nomsu\append (bit\gsub("\\","\\\\")\gsub("\n","\\n"))
+ nomsu\append (gsub(gsub(bit,"\\","\\\\"),"\n","\\n"))
else
interp_nomsu = @tree_to_nomsu(bit, true)
if interp_nomsu
@@ -791,7 +751,8 @@ class NomsuCompiler
nomsu = Nomsu(tree.source, '".."\n ')
for i, bit in ipairs @
if type(bit) == 'string'
- nomsu\append (bit\gsub("\\","\\\\")\gsub("\n","\n "))
+ -- TODO: unescape better?
+ nomsu\append (gsub(gsub(bit,"\\","\\\\"),"\n","\\n"))
else
interp_nomsu = @tree_to_nomsu(bit, true)
if interp_nomsu
@@ -902,10 +863,10 @@ class NomsuCompiler
return nomsu
when "Number"
- return Nomsu(tree.source, tostring(tree.value))
+ return Nomsu(tree.source, tostring(tree[1]))
when "Var"
- return Nomsu(tree.source, "%", tree.value)
+ return Nomsu(tree.source, "%", tree[1])
else
error("Unknown type: #{tree.type}")
diff --git a/nomsu.peg b/nomsu.peg
index 2de5292..2654f21 100644
--- a/nomsu.peg
+++ b/nomsu.peg
@@ -98,11 +98,11 @@ text_interpolation:
inline_text_interpolation /
("\" indented_expression nodent "..")
-number (Number): {| {:value: (("-"? (([0-9]+ "." [0-9]+) / ("." [0-9]+) / ([0-9]+)))-> tonumber) :} |}
+number (Number): {| (("-"? (([0-9]+ "." [0-9]+) / ("." [0-9]+) / ([0-9]+)))-> tonumber) |}
-- Variables can be nameless (i.e. just %) and can't contain operators like apostrophe
-- which is a hack to allow %'s to parse as "%" and "' s" separately
-variable (Var): "%" {| {:value: (%ident_char+ ((!"'" %operator_char+) / %ident_char+)*)? :} |}
+variable (Var): "%" {| {(%ident_char+ ((!"'" %operator_char+) / %ident_char+)*)?} |}
inline_list (List):
!('[..]')
diff --git a/nomsu_tree.lua b/nomsu_tree.lua
index 5aeefe8..96e5031 100644
--- a/nomsu_tree.lua
+++ b/nomsu_tree.lua
@@ -12,17 +12,18 @@ AST.is_syntax_tree = function(n)
return type(n) == 'table' and getmetatable(n) and AST[n.type] == getmetatable(n)
end
local Tree
-Tree = function(name, leaf_or_branch, methods)
+Tree = function(name, methods)
local cls = methods or { }
- local is_multi = leaf_or_branch == 'branch'
do
cls.type = name
+ cls.__class = cls
+ cls.__name = name
cls.is_instance = function(self, x)
return getmetatable(x) == self
end
cls.__index = cls
cls.__tostring = function(self)
- return tostring(self.name) .. "(#{@value and repr(@value) or table.concat([repr(v) for v in *@]), ', '})"
+ return tostring(self.name) .. "(#{table.concat([repr(v) for v in *@]), ', '})"
end
cls.map = function(self, fn)
do
@@ -31,21 +32,26 @@ Tree = function(name, leaf_or_branch, methods)
return replacement
end
end
- if self.value then
- return self
- end
- local new_vals
- do
- local _accum_0 = { }
- local _len_0 = 1
- for _index_0 = 1, #self do
- local v = self[_index_0]
- _accum_0[_len_0] = v.map and v:map(fn) or v
- _len_0 = _len_0 + 1
+ local made_changes, new_vals = false, { }
+ for i, v in ipairs(self) do
+ if AST.is_syntax_tree(v) then
+ do
+ local replacement = v:map(fn)
+ if replacement then
+ if replacement ~= v then
+ made_changes = true
+ v = replacement
+ end
+ end
+ end
end
- new_vals = _accum_0
+ new_vals[i] = v
end
- return getmetatable(self)(self.source, unpack(new_vals))
+ if not (made_changes) then
+ return self
+ end
+ local replacement = getmetatable(self)(self.source, unpack(new_vals))
+ return replacement
end
end
AST[name] = setmetatable(cls, {
@@ -57,18 +63,10 @@ Tree = function(name, leaf_or_branch, methods)
source = Source:from_string(source)
end
assert(Source:is_instance(source))
- local inst
- if is_multi then
- inst = {
- source = source,
- ...
- }
- else
- inst = {
- source = source,
- value = ...
- }
- end
+ local inst = {
+ source = source,
+ ...
+ }
setmetatable(inst, self)
if inst.__init then
inst:__init()
@@ -77,16 +75,16 @@ Tree = function(name, leaf_or_branch, methods)
end
})
end
-Tree("Number", 'leaf')
-Tree("Var", 'leaf')
-Tree("Block", 'branch')
-Tree("EscapedNomsu", 'branch')
-Tree("Text", 'branch')
-Tree("List", 'branch')
-Tree("Dict", 'branch')
-Tree("DictEntry", 'branch')
-Tree("IndexChain", 'branch')
-Tree("Action", 'branch', {
+Tree("Number")
+Tree("Var")
+Tree("Block")
+Tree("EscapedNomsu")
+Tree("Text")
+Tree("List")
+Tree("Dict")
+Tree("DictEntry")
+Tree("IndexChain")
+Tree("Action", {
__init = function(self)
local stub_bits
do
@@ -107,7 +105,7 @@ Tree("Action", 'branch', {
local _len_0 = 1
for _index_0 = 1, #self do
local a = self[_index_0]
- _accum_0[_len_0] = type(a) == "string" and a or "%" .. tostring(a.value)
+ _accum_0[_len_0] = type(a) == "string" and a or "%" .. tostring(a[1])
_len_0 = _len_0 + 1
end
return _accum_0
diff --git a/nomsu_tree.moon b/nomsu_tree.moon
index fe1c4f4..315571a 100644
--- a/nomsu_tree.moon
+++ b/nomsu_tree.moon
@@ -9,19 +9,28 @@ AST.is_syntax_tree = (n)->
type(n) == 'table' and getmetatable(n) and AST[n.type] == getmetatable(n)
-- Helper method:
-Tree = (name, leaf_or_branch, methods)->
+Tree = (name, methods)->
cls = methods or {}
- is_multi = leaf_or_branch == 'branch'
with cls
.type = name
+ .__class = cls
+ .__name = name
.is_instance = (x)=> getmetatable(x) == @
.__index = cls
- .__tostring = => "#{@name}(#{@value and repr(@value) or table.concat([repr(v) for v in *@]), ', '})"
+ .__tostring = => "#{@name}(#{table.concat([repr(v) for v in *@]), ', '})"
.map = (fn)=>
if replacement = fn(@) then return replacement
- if @value then return @
- new_vals = [v.map and v\map(fn) or v for v in *@]
- return getmetatable(self)(@source, unpack(new_vals))
+ made_changes, new_vals = false, {}
+ for i,v in ipairs @
+ if AST.is_syntax_tree(v)
+ if replacement = v\map(fn)
+ if replacement ~= v
+ made_changes = true
+ v = replacement
+ new_vals[i] = v
+ return @ unless made_changes
+ replacement = getmetatable(self)(@source, unpack(new_vals))
+ return replacement
AST[name] = setmetatable cls,
__tostring: => @name
@@ -29,25 +38,25 @@ Tree = (name, leaf_or_branch, methods)->
if type(source) == 'string'
source = Source\from_string(source)
assert(Source\is_instance(source))
- inst = if is_multi then {:source, ...} else {:source, value:...}
+ inst = {:source, ...}
setmetatable(inst, @)
if inst.__init then inst\__init!
return inst
-Tree "Number", 'leaf'
-Tree "Var", 'leaf'
-Tree "Block", 'branch'
-Tree "EscapedNomsu", 'branch'
-Tree "Text", 'branch'
-Tree "List", 'branch'
-Tree "Dict", 'branch'
-Tree "DictEntry", 'branch'
-Tree "IndexChain", 'branch'
-Tree "Action", 'branch',
+Tree "Number"
+Tree "Var"
+Tree "Block"
+Tree "EscapedNomsu"
+Tree "Text"
+Tree "List"
+Tree "Dict"
+Tree "DictEntry"
+Tree "IndexChain"
+Tree "Action",
__init: =>
stub_bits = [type(a) == 'string' and a or '%' for a in *@]
@stub = concat stub_bits, " "
get_spec: =>
- concat [type(a) == "string" and a or "%#{a.value}" for a in *@], " "
+ concat [type(a) == "string" and a or "%#{a[1]}" for a in *@], " "
return AST
diff --git a/tests/control_flow.nom b/tests/control_flow.nom
index 886b59c..5553811 100644
--- a/tests/control_flow.nom
+++ b/tests/control_flow.nom
@@ -193,14 +193,15 @@ assume
return %n
..= 6
-%nums <- []
-for % in
- values
- -> 4
- -> 5
- -> 6
-..
- add % to %nums
-
-assume (%nums = [4,5,6]) or barf "Coroutine iteration failed"
+#
+ %nums <- []
+ for % in
+ values
+ -> 4
+ -> 5
+ -> 6
+ ..
+ add % to %nums
+
+ assume (%nums = [4,5,6]) or barf "Coroutine iteration failed"