aboutsummaryrefslogtreecommitdiff
path: root/nomic.lua
diff options
context:
space:
mode:
authorBruce Hill <bitbucket@bruce-hill.com>2017-09-12 21:59:46 -0700
committerBruce Hill <bitbucket@bruce-hill.com>2017-09-12 21:59:46 -0700
commit20a9fd8a3e81fdc264172564cf7405690974bfb6 (patch)
treebd99b1ac9fe7b6cfca06fb050f07f96bf6abf396 /nomic.lua
parent395e6c8e5ba5d8f19f7c8abd81b22cb34629f13d (diff)
Updated names.
Diffstat (limited to 'nomic.lua')
-rw-r--r--nomic.lua839
1 files changed, 0 insertions, 839 deletions
diff --git a/nomic.lua b/nomic.lua
deleted file mode 100644
index f111fc7..0000000
--- a/nomic.lua
+++ /dev/null
@@ -1,839 +0,0 @@
-local re = require('re')
-local lpeg = require('lpeg')
-local utils = require('utils')
-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 wordchar = P(1) - S(' \t\n\r%:;,.{}[]()"')
-local comment = re.compile([[comment <- "(#" (comment / ((! "#)") .))* "#)"]])
-local whitespace = (S(" \t") + comment) ^ 1
-local nl = P("\n")
-local blank_line = whitespace ^ -1 * nl
-local get_line_indentation
-get_line_indentation = function(line)
- local indent_amounts = {
- [" "] = 1,
- ["\t"] = 4
- }
- do
- local sum = 0
- local leading_space = line:gsub("([\t ]*).*", "%1")
- for c in leading_space:gmatch("[\t ]") do
- sum = sum + indent_amounts[c]
- end
- return sum
- end
-end
-local make_parser
-make_parser = function(lingo, extra_definitions)
- local indent_stack = {
- 0
- }
- local push
- push = function(n)
- return table.insert(indent_stack, n)
- end
- local pop
- pop = function()
- return table.remove(indent_stack)
- end
- 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
- return nil
- end
- push(num_spaces)
- return end_pos
- 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
- return nil
- end
- pop()
- return end_pos
- 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
- return nil
- end
- return end_pos
- end
- local defs = {
- wordchar = wordchar,
- nl = nl,
- ws = whitespace,
- comment = comment,
- eol = #nl + (P("") - P(1)),
- word_boundary = whitespace + B(P("..")) + B(S("\";)]")) + #S("\":([") + #((whitespace + nl) ^ 0 * P("..")),
- indent = #(nl * blank_line ^ 0 * Cmt(whitespace ^ -1, check_indent)),
- dedent = #(nl * blank_line ^ 0 * Cmt(whitespace ^ -1, check_dedent)),
- new_line = nl * blank_line ^ 0 * Cmt(whitespace ^ -1, check_nodent),
- error_handler = function(src, pos, errors)
- local line_no = 1
- for _ in src:sub(1, -#errors):gmatch("\n") do
- line_no = line_no + 1
- end
- local err_pos = #src - #errors + 1
- if errors:sub(1, 1) == "\n" then
- err_pos = err_pos + #errors:match("[ \t]*", 2)
- end
- local start_of_err_line = err_pos
- while src:sub(start_of_err_line, start_of_err_line) ~= "\n" do
- start_of_err_line = start_of_err_line - 1
- end
- local start_of_prev_line = start_of_err_line - 1
- while src:sub(start_of_prev_line, start_of_prev_line) ~= "\n" do
- start_of_prev_line = start_of_prev_line - 1
- end
- local prev_line, err_line, next_line = src:match("([^\n]*)\n([^\n]*)\n([^\n]*)", start_of_prev_line + 1)
- local pointer = ("-"):rep(err_pos - start_of_err_line + 0) .. "^"
- return error("\nParse error on line " .. tostring(line_no) .. ":\n\n" .. tostring(prev_line) .. "\n" .. tostring(err_line) .. "\n" .. tostring(pointer) .. "\n" .. tostring(next_line) .. "\n")
- end
- }
- if extra_definitions then
- for k, v in pairs(extra_definitions) do
- defs[k] = v
- end
- end
- setmetatable(defs, {
- __index = function(t, key)
- local fn
- fn = function(src, value, errors)
- local token = {
- type = key,
- src = src,
- value = value,
- errors = errors
- }
- return token
- end
- t[key] = fn
- return fn
- end
- })
- return re.compile(lingo, defs)
-end
-local Compiler
-do
- local _class_0
- local _base_0 = {
- call = function(self, fn_name, ...)
- local fn_info = self.defs[fn_name]
- if fn_info == nil then
- self:error("Attempt to call undefined function: " .. tostring(fn_name))
- end
- if fn_info.is_macro then
- self:error("Attempt to call macro at runtime: " .. tostring(fn_name))
- end
- 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)
- local fn, arg_names
- fn, arg_names = fn_info.fn, fn_info.arg_names
- local args
- do
- local _tbl_0 = { }
- for i, name in ipairs(arg_names) do
- _tbl_0[name] = select(i, ...)
- end
- args = _tbl_0
- end
- if self.debug then
- print("Calling " .. tostring(fn_name) .. " with args: " .. tostring(utils.repr(args)))
- end
- local ret = fn(self, args)
- table.remove(self.callstack)
- return ret
- end,
- check_permission = function(self, fn_name)
- local fn_info = self.defs[fn_name]
- if fn_info == nil then
- self:error("Undefined function: " .. tostring(fn_name))
- end
- if fn_info.whiteset == nil then
- return true
- end
- local _list_0 = self.callstack
- for _index_0 = 1, #_list_0 do
- local caller = _list_0[_index_0]
- if fn_info.whiteset[caller] then
- return true
- end
- end
- return false
- end,
- def = function(self, spec, fn)
- if self.debug then
- print("Defining rule: " .. tostring(spec))
- end
- local invocations, arg_names = self:get_invocations(spec)
- local fn_info = {
- fn = fn,
- arg_names = arg_names,
- invocations = invocations,
- is_macro = false
- }
- for _index_0 = 1, #invocations do
- local invocation = invocations[_index_0]
- self.defs[invocation] = fn_info
- end
- end,
- get_invocations = function(self, text)
- if type(text) == 'string' then
- text = {
- text
- }
- end
- local invocations = { }
- local arg_names
- for _index_0 = 1, #text do
- local _text = text[_index_0]
- local invocation = _text:gsub("%%%S+", "%%")
- local _arg_names
- do
- local _accum_0 = { }
- local _len_0 = 1
- for arg in _text:gmatch("%%(%S+)") do
- _accum_0[_len_0] = arg
- _len_0 = _len_0 + 1
- end
- _arg_names = _accum_0
- end
- table.insert(invocations, invocation)
- if arg_names then
- if not utils.equivalent(utils.set(arg_names), utils.set(_arg_names)) then
- self:error("Conflicting argument names " .. tostring(utils.repr(arg_names)) .. " and " .. tostring(utils.repr(_arg_names)) .. " for " .. tostring(utils.repr(text)))
- end
- else
- arg_names = _arg_names
- end
- end
- return invocations, arg_names
- end,
- defmacro = function(self, spec, lua_gen_fn)
- local invocations, arg_names = self:get_invocations(spec)
- local fn_info = {
- fn = lua_gen_fn,
- arg_names = arg_names,
- invocations = invocations,
- is_macro = true
- }
- for _index_0 = 1, #invocations do
- local invocation = invocations[_index_0]
- self.defs[invocation] = fn_info
- end
- end,
- run = function(self, text)
- if self.debug then
- print("RUNNING TEXT:\n" .. tostring(text))
- end
- local code = self:compile(text)
- if self.debug then
- print("\nGENERATED LUA CODE:\n" .. tostring(code))
- end
- return code
- end,
- parse = function(self, str)
- if self.debug then
- print("PARSING:\n" .. tostring(str))
- end
- local lingo = [=[ file <- ({ {| %ws? %new_line? {:body: block :} %new_line? %ws? (errors)? |} }) -> File
- errors <- (({.+}) => error_handler)
- block <- ({ {| statement (%new_line statement)* |} }) -> Block
- statement <- ({ (functioncall / expression) }) -> Statement
- one_liner <- ({ {|
- (({
- (({ {|
- (expression (%word_boundary fn_bit)+) / (word (%word_boundary fn_bit)*)
- |} }) -> FunctionCall)
- / (expression)
- }) -> Statement)
- |} }) -> Block
-
- functioncall <- ({ {| (expression %word_boundary fn_bits) / (word (%word_boundary fn_bits)?) |} }) -> FunctionCall
- fn_bit <- (expression / word)
- fn_bits <-
- ((".." %ws? (%indent %new_line indented_fn_bits %dedent) (%new_line ".." %ws? fn_bits)?)
- / (%new_line ".." fn_bit (%word_boundary fn_bits)?)
- / (fn_bit (%word_boundary fn_bits)?))
- indented_fn_bits <-
- fn_bit ((%new_line / %word_boundary) indented_fn_bits)?
-
- thunk <-
- ({ ":" %ws?
- ((%indent %new_line block ((%dedent (%new_line "..")?) / errors))
- / (one_liner (%ws? (%new_line? ".."))?)) }) -> Thunk
-
- word <- ({ !number {%wordchar+} }) -> Word
- expression <- ({ (longstring / string / number / variable / list / thunk / subexpression) }) -> Expression
-
- string <- ({ (!longstring) '"' {(("\" .) / [^"])*} '"' }) -> String
- longstring <- ({ '".."' %ws? %indent {(%new_line "|" [^%nl]*)+} ((%dedent (%new_line '..')?) / errors) }) -> Longstring
- number <- ({ {'-'? [0-9]+ ("." [0-9]+)?} }) -> Number
- variable <- ({ ("%" {%wordchar+}) }) -> Var
-
- subexpression <-
- (!%comment "(" %ws? (functioncall / expression) %ws? ")")
- / ("(..)" %ws? %indent %new_line ((({ {| indented_fn_bits |} }) -> FunctionCall) / expression) %dedent (%new_line "..")?)
-
- list <- ({ {|
- ("[..]" %ws? %indent %new_line indented_list ","? ((%dedent (%new_line "..")?) / errors))
- / ("[" %ws? (list_items ","?)? %ws?"]")
- |} }) -> List
- list_items <- ((functioncall / expression) (list_sep list_items)?)
- list_sep <- %ws? "," %ws?
- indented_list <-
- (functioncall / expression) (((list_sep %new_line?) / %new_line) indented_list)?
- ]=]
- lingo = make_parser(lingo)
- local tree = lingo:match(str:gsub("\r", "") .. "\n")
- if self.debug then
- print("\nPARSE TREE:")
- self:print_tree(tree)
- end
- assert(tree, "Failed to parse: " .. tostring(str))
- return tree
- end,
- tree_to_value = function(self, tree)
- local code = "return (function(compiler, vars)\nreturn " .. tostring(self:tree_to_lua(tree)) .. "\nend)"
- local lua_thunk, err = load(code)
- if not lua_thunk then
- error("Failed to compile generated code:\n" .. tostring(code) .. "\n\n" .. tostring(err))
- end
- return (lua_thunk())(self, { })
- end,
- tree_to_lua = function(self, tree, kind)
- if kind == nil then
- kind = "Expression"
- end
- assert(tree, "No tree provided.")
- local indent = ""
- local buffer = { }
- local to_lua
- to_lua = function(t, kind)
- local ret = self:tree_to_lua(t, kind)
- 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 vars = { }
- local _list_0 = tree.value.body.value
- for _index_0 = 1, #_list_0 do
- local statement = _list_0[_index_0]
- local code = to_lua(statement)
- local lua_thunk, err = load("return (function(compiler, vars)\n" .. tostring(code) .. "\nend)")
- if not lua_thunk then
- error("Failed to compile generated code:\n" .. tostring(code) .. "\n\n" .. tostring(err))
- end
- local ok
- ok, err = pcall(lua_thunk)
- if not ok then
- error(err)
- end
- ok, err = pcall(err, self, vars)
- if not ok then
- self:error(err)
- end
- add(code)
- end
- add([[ return ret
- end)
- ]])
- elseif "Block" == _exp_0 then
- local _list_0 = tree.value
- for _index_0 = 1, #_list_0 do
- local statement = _list_0[_index_0]
- add(to_lua(statement))
- end
- elseif "Thunk" == _exp_0 then
- assert(tree.value.type == "Block", "Non-block value in Thunk")
- add([[ (function(compiler, vars)
- local ret]])
- add(to_lua(tree.value))
- add([[ 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*(.*)")))
- end
- else
- add("ret = " .. (to_lua(tree.value):match("%s*(.*)")))
- end
- elseif "Expression" == _exp_0 then
- add(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"))
- else
- local args
- do
- local _accum_0 = { }
- local _len_0 = 1
- local _list_0 = tree.value
- 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)
- _len_0 = _len_0 + 1
- end
- end
- args = _accum_0
- end
- table.insert(args, 1, utils.repr(name, true))
- add(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
- end))
- add(utils.repr(unescaped, true))
- elseif "Longstring" == _exp_0 then
- local result
- do
- local _accum_0 = { }
- local _len_0 = 1
- for line in tree.value:gmatch("[ \t]*|([^\n]*)") do
- _accum_0[_len_0] = line
- _len_0 = _len_0 + 1
- end
- result = _accum_0
- end
- add(utils.repr(table.concat(result, "\n"), true))
- elseif "Number" == _exp_0 then
- add(tree.value)
- elseif "List" == _exp_0 then
- if #tree.value == 0 then
- add("{}")
- elseif #tree.value == 1 then
- add("{" .. tostring(to_lua(tree.value[1])) .. "}")
- else
- add(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)
- _len_0 = _len_0 + 1
- end
- return _accum_0
- end)(), "}"))
- end
- elseif "Var" == _exp_0 then
- add("vars[" .. tostring(utils.repr(tree.value, true)) .. "]")
- else
- error("Unknown/unimplemented thingy: " .. tostring(tree.type))
- end
- buffer = table.concat(buffer, "\n")
- return buffer
- end,
- fn_name_from_tree = function(self, tree)
- assert(tree.type == "FunctionCall", "Attempt to get fn name from non-functioncall tree: " .. tostring(tree.type))
- local name_bits = { }
- local _list_0 = tree.value
- for _index_0 = 1, #_list_0 do
- local token = _list_0[_index_0]
- table.insert(name_bits, (function()
- if token.type == "Word" then
- return token.value
- else
- return "%"
- end
- end)())
- end
- return table.concat(name_bits, " ")
- end,
- run_macro = function(self, tree, kind)
- if kind == nil then
- kind = "Expression"
- end
- local name = self:fn_name_from_tree(tree)
- if not (self.defs[name] and self.defs[name].is_macro) then
- self:error("Macro not found: " .. tostring(name))
- end
- if not (self:check_permission(name)) then
- self:error("You do not have the authority to call: " .. tostring(name))
- end
- local fn, arg_names
- do
- local _obj_0 = self.defs[name]
- fn, arg_names = _obj_0.fn, _obj_0.arg_names
- end
- local args
- do
- local _accum_0 = { }
- local _len_0 = 1
- local _list_0 = tree.value
- for _index_0 = 1, #_list_0 do
- local a = _list_0[_index_0]
- if a.type ~= "Word" then
- _accum_0[_len_0] = a
- _len_0 = _len_0 + 1
- end
- end
- args = _accum_0
- end
- do
- local _tbl_0 = { }
- for i, name in ipairs(arg_names) do
- _tbl_0[name] = args[i]
- end
- args = _tbl_0
- end
- table.insert(self.callstack, name)
- local ret, manual_mode = fn(self, args, kind)
- table.remove(self.callstack)
- if not ret then
- self:error("No return value for macro: " .. tostring(name))
- end
- if kind == "Statement" and not manual_mode then
- ret = "ret = " .. ret
- end
- return ret
- end,
- _yield_tree = function(self, tree, indent_level)
- if indent_level == nil then
- indent_level = 0
- end
- local ind
- ind = function(s)
- return INDENT:rep(indent_level) .. s
- end
- local _exp_0 = tree.type
- if "File" == _exp_0 then
- coroutine.yield(ind("File:"))
- self:_yield_tree(tree.value.body, indent_level + 1)
- elseif "Errors" == _exp_0 then
- coroutine.yield(ind("Error:\n" .. tostring(tree.value)))
- elseif "Block" == _exp_0 then
- local _list_0 = tree.value
- for _index_0 = 1, #_list_0 do
- local chunk = _list_0[_index_0]
- self:_yield_tree(chunk, indent_level)
- end
- elseif "Thunk" == _exp_0 then
- coroutine.yield(ind("Thunk:"))
- self:_yield_tree(tree.value, indent_level + 1)
- elseif "Statement" == _exp_0 then
- self:_yield_tree(tree.value, indent_level)
- elseif "Expression" == _exp_0 then
- self:_yield_tree(tree.value, indent_level)
- elseif "FunctionCall" == _exp_0 then
- local name = self:fn_name_from_tree(tree)
- local args
- do
- local _accum_0 = { }
- local _len_0 = 1
- local _list_0 = tree.value
- for _index_0 = 1, #_list_0 do
- local a = _list_0[_index_0]
- if a.type ~= "Word" then
- _accum_0[_len_0] = a
- _len_0 = _len_0 + 1
- end
- end
- args = _accum_0
- end
- if #args == 0 then
- coroutine.yield(ind("Call [" .. tostring(name) .. "]!"))
- else
- coroutine.yield(ind("Call [" .. tostring(name) .. "]:"))
- for _index_0 = 1, #args do
- local a = args[_index_0]
- self:_yield_tree(a, indent_level + 1)
- end
- end
- elseif "String" == _exp_0 then
- coroutine.yield(ind(utils.repr(tree.value, true)))
- elseif "Longstring" == _exp_0 then
- coroutine.yield(ind(utils.repr(tree.value, true)))
- elseif "Number" == _exp_0 then
- coroutine.yield(ind(tree.value))
- elseif "List" == _exp_0 then
- if #tree.value == 0 then
- coroutine.yield(ind("<Empty List>"))
- else
- coroutine.yield(ind("List:"))
- local _list_0 = tree.value
- for _index_0 = 1, #_list_0 do
- local item = _list_0[_index_0]
- self:_yield_tree(item, indent_level + 1)
- end
- end
- elseif "Var" == _exp_0 then
- coroutine.yield(ind("Var[" .. tostring(utils.repr(tree.value)) .. "]"))
- else
- error("Unknown/unimplemented thingy: " .. tostring(tree.type))
- end
- return nil
- end,
- print_tree = function(self, tree)
- for line in coroutine.wrap(function()
- return self:_yield_tree(tree)
- end) do
- print(line)
- end
- end,
- stringify_tree = function(self, tree)
- local result = { }
- for line in coroutine.wrap(function()
- return self:_yield_tree(tree)
- end) do
- table.insert(result, line)
- end
- return table.concat(result, "\n")
- end,
- compile = function(self, src, output_file)
- if output_file == nil then
- output_file = nil
- end
- if self.debug then
- print("COMPILING:\n" .. tostring(src))
- end
- local tree = self:parse(src)
- assert(tree, "Tree failed to compile: " .. tostring(src))
- local code = self:tree_to_lua(tree)
- if output_file then
- local output = io.open(output_file, "w")
- output:write(code)
- end
- return code
- end,
- error = function(self, ...)
- print(...)
- print("Callstack:")
- for i = #self.callstack, 1, -1 do
- print(" " .. tostring(self.callstack[i]))
- end
- return error()
- end,
- test = function(self, src, expected)
- local i = 1
- while i ~= nil do
- local start, stop = src:find("\n\n", i)
- local test = src:sub(i, start)
- i = stop
- start, stop = test:find("===")
- if not start or not stop then
- self:error("WHERE'S THE ===? in:\n" .. tostring(test))
- end
- local test_src
- test_src, expected = test:sub(1, start - 1), test:sub(stop + 1, -1)
- expected = expected:match('[\n]*(.*[^\n])')
- local tree = self:parse(test_src)
- local got = self:stringify_tree(tree.value.body)
- if got ~= expected then
- self:error("TEST FAILED!\nSource:\n" .. tostring(test_src) .. "\nExpected:\n" .. tostring(expected) .. "\n\nGot:\n" .. tostring(got))
- end
- end
- end,
- initialize_core = function(self)
- local as_lua_code
- as_lua_code = function(self, str)
- local _exp_0 = str.type
- if "String" == _exp_0 then
- local escapes = {
- n = "\n",
- t = "\t",
- b = "\b",
- a = "\a",
- v = "\v",
- f = "\f",
- r = "\r"
- }
- local unescaped = str.value:gsub("\\(.)", (function(c)
- return escapes[c] or c
- end))
- return unescaped
- elseif "Longstring" == _exp_0 then
- local result
- do
- local _accum_0 = { }
- local _len_0 = 1
- for line in str.value:gmatch("[ \t]*|([^\n]*)") do
- _accum_0[_len_0] = line
- _len_0 = _len_0 + 1
- end
- result = _accum_0
- end
- return table.concat(result, "\n")
- else
- return self:tree_to_lua(str)
- end
- end
- self:defmacro([[lua block %lua_code]], function(self, vars, kind)
- if kind == "Expression" then
- error("Expected to be in statement.")
- end
- local lua_code = vars.lua_code.value
- local _exp_0 = lua_code.type
- if "List" == _exp_0 then
- return table.concat((function()
- local _accum_0 = { }
- local _len_0 = 1
- local _list_0 = lua_code.value
- for _index_0 = 1, #_list_0 do
- local i = _list_0[_index_0]
- _accum_0[_len_0] = as_lua_code(self, i.value)
- _len_0 = _len_0 + 1
- end
- return _accum_0
- end)()), true
- else
- return as_lua_code(self, lua_code), true
- end
- end)
- self:defmacro([[lua expr %lua_code]], function(self, vars, kind)
- local lua_code = vars.lua_code.value
- local _exp_0 = lua_code.type
- if "List" == _exp_0 then
- return table.concat((function()
- local _accum_0 = { }
- local _len_0 = 1
- local _list_0 = lua_code.value
- for _index_0 = 1, #_list_0 do
- local i = _list_0[_index_0]
- _accum_0[_len_0] = as_lua_code(self, i.value)
- _len_0 = _len_0 + 1
- end
- return _accum_0
- end)())
- else
- return as_lua_code(self, lua_code)
- end
- end)
- self:def("rule %spec %body", function(self, vars)
- return self:def(vars.spec, vars.body)
- end)
- self:defmacro([[macro %spec %body]], function(self, vars, kind)
- if kind == "Expression" then
- error("Macro definitions cannot be used as expressions.")
- end
- self:defmacro(self:tree_to_value(vars.spec), self:tree_to_value(vars.body))
- return "", true
- end)
- self:defmacro([[macro block %spec %body]], function(self, vars, kind)
- if kind == "Expression" then
- error("Macro definitions cannot be used as expressions.")
- end
- local invocation = self:tree_to_value(vars.spec)
- local fn = self:tree_to_value(vars.body)
- self:defmacro(invocation, (function(self, vars, kind)
- if kind == "Expression" then
- error("Macro: " .. tostring(invocation) .. " was defined to be a block, not an expression.")
- end
- return fn(self, vars, kind), true
- end))
- return "", true
- end)
- return self:def("run file %filename", function(self, vars)
- local file = io.open(vars.filename)
- return self:run(file:read('*a'))
- end)
- end
- }
- _base_0.__index = _base_0
- _class_0 = setmetatable({
- __init = function(self, parent)
- self.defs = setmetatable({ }, {
- __index = parent and parent.defs
- })
- self.callstack = { }
- self.debug = false
- return self:initialize_core()
- end,
- __base = _base_0,
- __name = "Compiler"
- }, {
- __index = _base_0,
- __call = function(cls, ...)
- local _self_0 = setmetatable({}, _base_0)
- cls.__init(_self_0, ...)
- return _self_0
- end
- })
- _base_0.__class = _class_0
- local self = _class_0
- self.comma_separated_items = function(self, open, items, close)
- return utils.accumulate("\n", function()
- local buffer = open
- local so_far = 0
- for i, item in ipairs(items) do
- if i < #items then
- item = item .. ", "
- end
- if so_far + #item >= 80 and #buffer > 0 then
- coroutine.yield(buffer)
- so_far = so_far - #buffer
- buffer = item
- else
- so_far = so_far + #item
- buffer = buffer .. item
- end
- end
- buffer = buffer .. close
- return coroutine.yield(buffer)
- end)
- end
- Compiler = _class_0
-end
-if arg[1] then
- local c = Compiler()
- local input = io.open(arg[1]):read("*a")
- local _print = print
- local _io_write = io.write
- if arg[2] == "-" then
- local nop
- nop = function() end
- print, io.write = nop, nop
- end
- local code = c:run(input)
- if arg[2] then
- local output
- if arg[2] == "-" then
- print, io.write = _print, _io_write
- output = io.output()
- else
- output = io.open(arg[2], 'w')
- end
- output:write([[ local load = function()
- ]])
- output:write(code)
- output:write([[
- end
- local utils = require('utils')
- local Compiler = require('nomic')
- local c = Compiler(require('core'))
- load()(c, {})
- ]])
- end
-end
-return Compiler