aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--nomsu.lua170
-rwxr-xr-xnomsu.moon134
2 files changed, 114 insertions, 190 deletions
diff --git a/nomsu.lua b/nomsu.lua
index 35d00c4..833c929 100644
--- a/nomsu.lua
+++ b/nomsu.lua
@@ -1,10 +1,20 @@
local re = require('re')
local lpeg = require('lpeg')
local utils = require('utils')
+local insert = table.insert
local INDENT = " "
lpeg.setmaxstack(10000)
local P, V, S, Cg, C, Cp, B, Cmt
P, V, S, Cg, C, Cp, B, Cmt = lpeg.P, lpeg.V, lpeg.S, lpeg.Cg, lpeg.C, lpeg.Cp, lpeg.B, lpeg.Cmt
+local STRING_ESCAPES = {
+ n = "\n",
+ t = "\t",
+ b = "\b",
+ a = "\a",
+ v = "\v",
+ f = "\f",
+ r = "\r"
+}
local NomsuCompiler
do
local _class_0
@@ -24,7 +34,7 @@ do
if not (self:check_permission(fn_name)) then
self:error("You do not have the authority to call: " .. tostring(fn_name))
end
- table.insert(self.callstack, fn_name)
+ insert(self.callstack, fn_name)
local fn, arg_names
fn, arg_names = fn_info.fn, fn_info.arg_names
local args
@@ -38,11 +48,8 @@ do
if self.debug then
self:writeln("Calling " .. tostring(fn_name) .. " with args: " .. tostring(utils.repr(args)))
end
- local ok, ret = pcall(fn, self, args)
+ local ret = fn(self, args)
table.remove(self.callstack)
- if not ok then
- error(ret)
- end
return ret
end,
check_permission = function(self, fn_name)
@@ -93,7 +100,7 @@ do
repeat
local item = _list_0[_index_0]
if item.type == "String" then
- table.insert(invocations, self:tree_to_value(item, vars))
+ insert(invocations, self:tree_to_value(item, vars))
_continue_0 = true
break
end
@@ -105,14 +112,14 @@ do
for _index_1 = 1, #_list_1 do
local token = _list_1[_index_1]
if token.type == "Word" then
- table.insert(name_bits, token.value)
+ insert(name_bits, token.value)
elseif token.type == "Var" then
- table.insert(name_bits, token.src)
+ insert(name_bits, token.src)
else
self:error("Unexpected token type in definition: " .. tostring(token.type) .. " (expected Word or Var)")
end
end
- table.insert(invocations, table.concat(name_bits, " "))
+ insert(invocations, table.concat(name_bits, " "))
_continue_0 = true
until true
if not _continue_0 then
@@ -149,7 +156,7 @@ do
end
_arg_names = _accum_0
end
- table.insert(invocations, invocation)
+ insert(invocations, invocation)
if prev_arg_names then
if not utils.equivalent(utils.set(prev_arg_names), utils.set(_arg_names)) then
self:error("Conflicting argument names " .. tostring(utils.repr(prev_arg_names)) .. " and " .. tostring(utils.repr(_arg_names)) .. " for " .. tostring(utils.repr(text)))
@@ -178,17 +185,6 @@ do
self.defs[invocation] = fn_info
end
end,
- run = function(self, text, filename)
- if self.debug then
- self:writeln("RUNNING TEXT:\n" .. tostring(text))
- end
- local code, retval = self:compile(text, filename)
- if self.debug then
- self:writeln("\nGENERATED LUA CODE:\n" .. tostring(code))
- self:writeln("\nPRODUCED RETURN VALUE:\n" .. tostring(retval))
- end
- return retval
- end,
serialize = function(self, obj)
local _exp_0 = type(obj)
if "function" == _exp_0 then
@@ -236,44 +232,26 @@ do
if self.debug then
self:writeln("PARSING:\n" .. tostring(str))
end
- local get_line_indentation
- get_line_indentation = function(line)
- local indent_amounts = {
- [" "] = 1,
- ["\t"] = 4
- }
- do
- local sum = 0
- local leading_space = line:match("[\t ]*")
- for c in leading_space:gmatch("[\t ]") do
- sum = sum + indent_amounts[c]
- end
- return sum
- end
- end
local indent_stack = {
0
}
local check_indent
check_indent = function(subject, end_pos, spaces)
- local num_spaces = get_line_indentation(spaces)
- if num_spaces > indent_stack[#indent_stack] then
- table.insert(indent_stack, num_spaces)
+ if #spaces > indent_stack[#indent_stack] then
+ insert(indent_stack, #spaces)
return end_pos
end
end
local check_dedent
check_dedent = function(subject, end_pos, spaces)
- local num_spaces = get_line_indentation(spaces)
- if num_spaces < indent_stack[#indent_stack] then
+ if #spaces < indent_stack[#indent_stack] then
table.remove(indent_stack)
return end_pos
end
end
local check_nodent
check_nodent = function(subject, end_pos, spaces)
- local num_spaces = get_line_indentation(spaces)
- if num_spaces == indent_stack[#indent_stack] then
+ if #spaces == indent_stack[#indent_stack] then
return end_pos
end
end
@@ -420,27 +398,17 @@ do
if not tree.type then
self:error("Invalid tree: " .. tostring(utils.repr(tree)))
end
- local indent = ""
- local buffer = { }
- local return_value = nil
- local to_lua
- to_lua = function(t)
- local ret = self:tree_to_lua(t)
- return ret
- end
- local add
- add = function(code)
- return table.insert(buffer, code)
- end
local _exp_0 = tree.type
if "File" == _exp_0 then
- add([[return (function(compiler, vars)
- local ret]])
+ local buffer = {
+ [[return (function(compiler, vars)
+ local ret]]
+ }
local vars = { }
local _list_0 = tree.value.body.value
for _index_0 = 1, #_list_0 do
local statement = _list_0[_index_0]
- local ok, code = pcall(to_lua, statement, "Statement")
+ local ok, code = pcall(self.tree_to_lua, self, statement)
if not ok then
self:writeln("Error occurred in statement:\n" .. tostring(statement.src))
error(code)
@@ -451,44 +419,45 @@ do
error("Failed to compile generated code:\n" .. tostring(code) .. "\n\n" .. tostring(err) .. "\n\nProduced by statement:\n" .. tostring(utils.repr(statement)))
end
local value = lua_thunk()
+ local return_value
ok, return_value = pcall(value, self, vars)
if not ok then
self:writeln("Error occurred in statement:\n" .. tostring(statement.src))
error(return_value)
end
- add(code)
+ insert(buffer, code)
end
- add([[ return ret
+ insert(buffer, [[ return ret
end)
]])
+ return table.concat(buffer, "\n"), return_value
elseif "Block" == _exp_0 then
+ local buffer = { }
local _list_0 = tree.value
for _index_0 = 1, #_list_0 do
local statement = _list_0[_index_0]
- add(to_lua(statement))
+ insert(buffer, self:tree_to_lua(statement))
end
+ return table.concat(buffer, "\n")
elseif "Thunk" == _exp_0 then
assert(tree.value.type == "Block", "Non-block value in Thunk")
- add([[ (function(compiler, vars)
+ return [[ (function(compiler, vars)
local ret
- ]] .. to_lua(tree.value) .. "\n" .. [[ return ret
+ ]] .. self:tree_to_lua(tree.value) .. "\n" .. [[ return ret
end)
- ]])
+ ]]
elseif "Statement" == _exp_0 then
if tree.value.type == "FunctionCall" then
local name = self:fn_name_from_tree(tree.value)
if self.defs[name] and self.defs[name].is_macro then
- add(self:run_macro(tree.value, "Statement"))
- else
- add("ret = " .. (to_lua(tree.value):match("%s*(.*)")))
+ return self:run_macro(tree.value, "Statement")
end
- else
- add("ret = " .. (to_lua(tree.value):match("%s*(.*)")))
end
+ return "ret = " .. (self:tree_to_lua(tree.value))
elseif "FunctionCall" == _exp_0 then
local name = self:fn_name_from_tree(tree)
if self.defs[name] and self.defs[name].is_macro then
- add(self:run_macro(tree, "Expression"))
+ return self:run_macro(tree, "Expression")
else
local args
do
@@ -498,29 +467,20 @@ do
for _index_0 = 1, #_list_0 do
local a = _list_0[_index_0]
if a.type ~= "Word" then
- _accum_0[_len_0] = to_lua(a)
+ _accum_0[_len_0] = self:tree_to_lua(a)
_len_0 = _len_0 + 1
end
end
args = _accum_0
end
- table.insert(args, 1, utils.repr(name))
- add(self.__class:comma_separated_items("compiler:call(", args, ")"))
+ insert(args, 1, utils.repr(name))
+ return self.__class:comma_separated_items("compiler:call(", args, ")")
end
elseif "String" == _exp_0 then
- local escapes = {
- n = "\n",
- t = "\t",
- b = "\b",
- a = "\a",
- v = "\v",
- f = "\f",
- r = "\r"
- }
local unescaped = tree.value:gsub("\\(.)", (function(c)
- return escapes[c] or c
+ return STRING_ESCAPES[c] or c
end))
- add(utils.repr(unescaped))
+ return utils.repr(unescaped)
elseif "Longstring" == _exp_0 then
local concat_parts = { }
local string_buffer = ""
@@ -534,50 +494,48 @@ do
string_buffer = string_buffer .. bit:gsub("\\\\", "\\")
else
if string_buffer ~= "" then
- table.insert(concat_parts, utils.repr(string_buffer))
+ insert(concat_parts, utils.repr(string_buffer))
string_buffer = ""
end
- table.insert(concat_parts, "compiler.utils.repr_if_not_string(" .. tostring(to_lua(bit)) .. ")")
+ insert(concat_parts, "compiler.utils.repr_if_not_string(" .. tostring(self:tree_to_lua(bit)) .. ")")
end
end
end
if string_buffer ~= "" then
- table.insert(concat_parts, utils.repr(string_buffer))
+ insert(concat_parts, utils.repr(string_buffer))
end
if #concat_parts == 0 then
- add("''")
+ return "''"
elseif #concat_parts == 1 then
- add(concat_parts[1])
+ return concat_parts[1]
else
- add("(" .. tostring(table.concat(concat_parts, "..")) .. ")")
+ return "(" .. tostring(table.concat(concat_parts, "..")) .. ")"
end
elseif "Number" == _exp_0 then
- add(tree.value)
+ return tree.value
elseif "List" == _exp_0 then
if #tree.value == 0 then
- add("{}")
+ return "{}"
elseif #tree.value == 1 then
- add("{" .. tostring(to_lua(tree.value[1])) .. "}")
+ return "{" .. tostring(self:tree_to_lua(tree.value[1])) .. "}"
else
- add(self.__class:comma_separated_items("{", (function()
+ return self.__class:comma_separated_items("{", (function()
local _accum_0 = { }
local _len_0 = 1
local _list_0 = tree.value
for _index_0 = 1, #_list_0 do
local item = _list_0[_index_0]
- _accum_0[_len_0] = to_lua(item)
+ _accum_0[_len_0] = self:tree_to_lua(item)
_len_0 = _len_0 + 1
end
return _accum_0
- end)(), "}"))
+ end)(), "}")
end
elseif "Var" == _exp_0 then
- add("vars[" .. tostring(utils.repr(tree.value)) .. "]")
+ return "vars[" .. tostring(utils.repr(tree.value)) .. "]"
else
- self:error("Unknown/unimplemented thingy: " .. tostring(tree.type))
+ return self:error("Unknown/unimplemented thingy: " .. tostring(tree.type))
end
- buffer = table.concat(buffer, "\n")
- return buffer, return_value
end,
fn_name_from_tree = function(self, tree)
assert(tree.type == "FunctionCall", "Attempt to get fn name from non-functioncall tree: " .. tostring(tree.type))
@@ -585,7 +543,7 @@ do
local _list_0 = tree.value
for _index_0 = 1, #_list_0 do
local token = _list_0[_index_0]
- table.insert(name_bits, (function()
+ insert(name_bits, (function()
if token.type == "Word" then
return token.value
else
@@ -644,7 +602,7 @@ do
end
args = _tbl_0
end
- table.insert(self.callstack, name)
+ insert(self.callstack, name)
local ret, manual_mode = fn(self, args, kind)
table.remove(self.callstack)
if not ret then
@@ -741,11 +699,11 @@ do
for line in coroutine.wrap(function()
return self:_yield_tree(tree)
end) do
- table.insert(result, line)
+ insert(result, line)
end
return table.concat(result, "\n")
end,
- compile = function(self, src, filename, output_file)
+ run = function(self, src, filename, output_file)
if output_file == nil then
output_file = nil
end
@@ -759,7 +717,7 @@ do
local output = io.open(output_file, "w")
output:write(code)
end
- return code, retval
+ return retval, code
end,
error = function(self, ...)
self:writeln("ERROR!")
@@ -900,7 +858,7 @@ if arg and arg[1] then
if arg[2] == "-" then
c.write = function() end
end
- local code, retval = c:compile(input, arg[1])
+ local retval, code = c:run(input, arg[1])
c.write = _write
if arg[2] then
local output
diff --git a/nomsu.moon b/nomsu.moon
index c36dbb6..ed53b64 100755
--- a/nomsu.moon
+++ b/nomsu.moon
@@ -2,6 +2,7 @@
re = require 're'
lpeg = require 'lpeg'
utils = require 'utils'
+insert = table.insert
-- TODO:
-- improve indentation of generated lua code
@@ -16,6 +17,7 @@ utils = require 'utils'
INDENT = " "
lpeg.setmaxstack 10000 -- whoa
{:P,:V,:S,:Cg,:C,:Cp,:B,:Cmt} = lpeg
+STRING_ESCAPES = n:"\n", t:"\t", b:"\b", a:"\a", v:"\v", f:"\f", r:"\r"
class NomsuCompiler
@@ -40,15 +42,13 @@ class NomsuCompiler
@error "Attempt to call macro at runtime: #{fn_name}\nThis can be caused by using a macro in a function that is defined before the macro."
unless @check_permission(fn_name)
@error "You do not have the authority to call: #{fn_name}"
- table.insert @callstack, fn_name
+ insert @callstack, fn_name
{:fn, :arg_names} = fn_info
args = {name, select(i,...) for i,name in ipairs(arg_names[fn_name])}
if @debug
@writeln "Calling #{fn_name} with args: #{utils.repr(args)}"
- ok,ret = pcall(fn, self, args)
+ ret = fn(self, args)
table.remove @callstack
- if not ok
- error(ret)
return ret
check_permission: (fn_name)=>
@@ -79,19 +79,19 @@ class NomsuCompiler
invocations = {}
for item in *def.value
if item.type == "String"
- table.insert invocations, @tree_to_value(item, vars)
+ insert invocations, @tree_to_value(item, vars)
continue
if item.type != "FunctionCall"
@error "Invalid list item: #{item.type}, expected FunctionCall or String"
name_bits = {}
for token in *item.value
if token.type == "Word"
- table.insert name_bits, token.value
+ insert name_bits, token.value
elseif token.type == "Var"
- table.insert name_bits, token.src
+ insert name_bits, token.src
else
@error "Unexpected token type in definition: #{token.type} (expected Word or Var)"
- table.insert invocations, table.concat(name_bits, " ")
+ insert invocations, table.concat(name_bits, " ")
return invocations
get_invocations:(text)=>
@@ -106,7 +106,7 @@ class NomsuCompiler
for _text in *text
invocation = _text\gsub("'"," '")\gsub("%%%S+","%%")\gsub("%s+"," ")
_arg_names = [arg for arg in _text\gmatch("%%(%S[^%s']*)")]
- table.insert(invocations, invocation)
+ insert(invocations, invocation)
if prev_arg_names
if not utils.equivalent(utils.set(prev_arg_names), utils.set(_arg_names))
@error("Conflicting argument names #{utils.repr(prev_arg_names)} and #{utils.repr(_arg_names)} for #{utils.repr(text)}")
@@ -121,16 +121,6 @@ class NomsuCompiler
fn_info = {fn:lua_gen_fn, :arg_names, :invocations, :src, is_macro:true}
for invocation in *invocations
@defs[invocation] = fn_info
-
- run: (text, filename)=>
- if @debug
- @writeln "RUNNING TEXT:\n#{text}"
- -- This will execute each chunk as it goes along
- code, retval = @compile(text, filename)
- if @debug
- @writeln "\nGENERATED LUA CODE:\n#{code}"
- @writeln "\nPRODUCED RETURN VALUE:\n#{retval}"
- return retval
serialize: (obj)=>
switch type(obj)
@@ -161,27 +151,17 @@ class NomsuCompiler
if @debug
@writeln("PARSING:\n#{str}")
- get_line_indentation = (line)->
- indent_amounts = {[" "]:1, ["\t"]:4}
- with sum = 0
- leading_space = line\match("[\t ]*")
- for c in leading_space\gmatch "[\t ]"
- sum += indent_amounts[c]
-
indent_stack = {0}
check_indent = (subject,end_pos,spaces)->
- num_spaces = get_line_indentation(spaces)
- if num_spaces > indent_stack[#indent_stack]
- table.insert(indent_stack, num_spaces)
+ if #spaces > indent_stack[#indent_stack]
+ insert(indent_stack, #spaces)
return end_pos
check_dedent = (subject,end_pos,spaces)->
- num_spaces = get_line_indentation(spaces)
- if num_spaces < indent_stack[#indent_stack]
+ if #spaces < indent_stack[#indent_stack]
table.remove(indent_stack)
return end_pos
check_nodent = (subject,end_pos,spaces)->
- num_spaces = get_line_indentation(spaces)
- if num_spaces == indent_stack[#indent_stack]
+ if #spaces == indent_stack[#indent_stack]
return end_pos
lingo = [=[
@@ -315,23 +295,13 @@ class NomsuCompiler
assert tree, "No tree provided."
if not tree.type
@error "Invalid tree: #{utils.repr(tree)}"
- indent = ""
- buffer = {}
- return_value = nil
-
- to_lua = (t)->
- ret = @tree_to_lua(t)
- return ret
-
- add = (code)-> table.insert(buffer, code)
-
switch tree.type
when "File"
- add [[return (function(compiler, vars)
- local ret]]
+ buffer = {[[return (function(compiler, vars)
+ local ret]]}
vars = {}
for statement in *tree.value.body.value
- ok,code = pcall(to_lua, statement, "Statement")
+ ok,code = pcall(@tree_to_lua, self, statement)
if not ok
@writeln "Error occurred in statement:\n#{statement.src}"
error(code)
@@ -346,22 +316,25 @@ class NomsuCompiler
if not ok
@writeln "Error occurred in statement:\n#{statement.src}"
error(return_value)
- add code
- add [[
+ insert buffer, code
+ insert buffer, [[
return ret
end)
]]
+ return table.concat(buffer, "\n"), return_value
when "Block"
+ buffer = {}
for statement in *tree.value
- add to_lua(statement)
+ insert buffer, @tree_to_lua(statement)
+ return table.concat(buffer, "\n")
when "Thunk"
assert tree.value.type == "Block", "Non-block value in Thunk"
- add [[
+ return [[
(function(compiler, vars)
local ret
- ]]..to_lua(tree.value).."\n"..[[
+ ]]..@tree_to_lua(tree.value).."\n"..[[
return ret
end)
]]
@@ -371,25 +344,21 @@ class NomsuCompiler
if tree.value.type == "FunctionCall"
name = @fn_name_from_tree(tree.value)
if @defs[name] and @defs[name].is_macro
- add @run_macro(tree.value, "Statement")
- else
- add "ret = "..(to_lua(tree.value)\match("%s*(.*)"))
- else
- add "ret = "..(to_lua(tree.value)\match("%s*(.*)"))
+ return @run_macro(tree.value, "Statement")
+ return "ret = "..(@tree_to_lua(tree.value))
when "FunctionCall"
name = @fn_name_from_tree(tree)
if @defs[name] and @defs[name].is_macro
- add @run_macro(tree, "Expression")
+ return @run_macro(tree, "Expression")
else
- args = [to_lua(a) for a in *tree.value when a.type != "Word"]
- table.insert args, 1, utils.repr(name)
- add @@comma_separated_items("compiler:call(", args, ")")
+ args = [@tree_to_lua(a) for a in *tree.value when a.type != "Word"]
+ insert args, 1, utils.repr(name)
+ return @@comma_separated_items("compiler:call(", args, ")")
when "String"
- escapes = n:"\n", t:"\t", b:"\b", a:"\a", v:"\v", f:"\f", r:"\r"
- unescaped = tree.value\gsub("\\(.)", ((c)-> escapes[c] or c))
- add utils.repr(unescaped)
+ unescaped = tree.value\gsub("\\(.)", ((c)-> STRING_ESCAPES[c] or c))
+ return utils.repr(unescaped)
when "Longstring"
concat_parts = {}
@@ -401,41 +370,37 @@ class NomsuCompiler
string_buffer ..= bit\gsub("\\\\","\\")
else
if string_buffer ~= ""
- table.insert concat_parts, utils.repr(string_buffer)
+ insert concat_parts, utils.repr(string_buffer)
string_buffer = ""
- table.insert concat_parts, "compiler.utils.repr_if_not_string(#{to_lua(bit)})"
+ insert concat_parts, "compiler.utils.repr_if_not_string(#{@tree_to_lua(bit)})"
if string_buffer ~= ""
- table.insert concat_parts, utils.repr(string_buffer)
+ insert concat_parts, utils.repr(string_buffer)
if #concat_parts == 0
- add "''"
+ return "''"
elseif #concat_parts == 1
- add concat_parts[1]
+ return concat_parts[1]
else
- add "(#{table.concat(concat_parts, "..")})"
+ return "(#{table.concat(concat_parts, "..")})"
when "Number"
- add tree.value
+ return tree.value
when "List"
if #tree.value == 0
- add "{}"
+ return "{}"
elseif #tree.value == 1
- add "{#{to_lua(tree.value[1])}}"
+ return "{#{@tree_to_lua(tree.value[1])}}"
else
- add @@comma_separated_items("{", [to_lua(item) for item in *tree.value], "}")
+ return @@comma_separated_items("{", [@tree_to_lua(item) for item in *tree.value], "}")
when "Var"
- add "vars[#{utils.repr(tree.value)}]"
+ return "vars[#{utils.repr(tree.value)}]"
else
@error("Unknown/unimplemented thingy: #{tree.type}")
- -- TODO: make indentation clean
- buffer = table.concat(buffer, "\n")
- return buffer, return_value
-
@comma_separated_items: (open, items, close)=>
utils.accumulate "\n", ->
buffer = open
@@ -456,7 +421,7 @@ class NomsuCompiler
assert(tree.type == "FunctionCall", "Attempt to get fn name from non-functioncall tree: #{tree.type}")
name_bits = {}
for token in *tree.value
- table.insert name_bits, if token.type == "Word" then token.value else "%"
+ insert name_bits, if token.type == "Word" then token.value else "%"
table.concat(name_bits, " ")
var_to_lua_identifier: (var)=>
@@ -474,7 +439,7 @@ class NomsuCompiler
{:fn, :arg_names} = @defs[name]
args = [a for a in *tree.value when a.type != "Word"]
args = {name,args[i] for i,name in ipairs(arg_names[name])}
- table.insert @callstack, name
+ insert @callstack, name
ret, manual_mode = fn(self, args, kind)
table.remove @callstack
if not ret
@@ -547,10 +512,10 @@ class NomsuCompiler
stringify_tree:(tree)=>
result = {}
for line in coroutine.wrap(-> @_yield_tree(tree))
- table.insert(result, line)
+ insert(result, line)
return table.concat result, "\n"
- compile: (src, filename, output_file=nil)=>
+ run: (src, filename, output_file=nil)=>
if @debug
@writeln "COMPILING:\n#{src}"
tree = @parse(src, filename)
@@ -559,7 +524,7 @@ class NomsuCompiler
if output_file
output = io.open(output_file, "w")
output\write(code)
- return code, retval
+ return retval, code
error: (...)=>
@writeln "ERROR!"
@@ -635,7 +600,7 @@ if arg and arg[1]
_write = c.write
if arg[2] == "-"
c.write = ->
- code, retval = c\compile(input, arg[1])
+ retval, code = c\run(input, arg[1])
c.write = _write -- put it back
if arg[2]
output = if arg[2] == "-"
@@ -653,6 +618,7 @@ if arg and arg[1]
local c = NomsuCompiler()
return load()(c, {})
]]
+
elseif arg
-- REPL:
c = NomsuCompiler()