Added more bindings and error tracebacks.
This commit is contained in:
191
main.lua
191
main.lua
@@ -9,17 +9,23 @@ local function B(abstract,callback)
|
||||
)
|
||||
)
|
||||
end
|
||||
B("print (text)",function(s,e)
|
||||
log(s:evaluate(e.text))
|
||||
local function R(scope,expression,chain,name)
|
||||
name = name or "?"
|
||||
assert_meta(Chain)(chain,"Arg 'chain' #1: %s")
|
||||
local chain = Chain(expression:link(name)):from(chain)
|
||||
return scope:run(expression,chain)
|
||||
end
|
||||
B("print (text)",function(s,e,c)
|
||||
log(R(s,e.text,c,"print: text"))
|
||||
end)
|
||||
B("text (literal)",function(s,e)
|
||||
B("text (literal)",function(s,e,c)
|
||||
return e.literal:text()
|
||||
end)
|
||||
B("do (expressions)",function(s,e)
|
||||
B("do (expressions)",function(s,e,c)
|
||||
--assert_meta(Chain)(chain,"Arg 'chain' #3: %s")
|
||||
scope = Scope()
|
||||
scope.parent = s
|
||||
local res
|
||||
print(e.expressions)
|
||||
for item in iterate(e.expressions.items) do
|
||||
if type_of(item) ~= Expression then
|
||||
error(
|
||||
@@ -29,99 +35,122 @@ B("do (expressions)",function(s,e)
|
||||
)
|
||||
)
|
||||
end
|
||||
res = scope:evaluate(item)
|
||||
res = R(s,item,c,"do: line")
|
||||
end
|
||||
return res
|
||||
end)
|
||||
B("if (predicate) then (expression)",function(s,e)
|
||||
if s:evaluate(e.predicate) then
|
||||
return s:evaluate(e.expression)
|
||||
B("error (text)",function(s,e,c)
|
||||
error("nel: "..R(s,e.text,c,"error: message"))
|
||||
end)
|
||||
B("if (predicate) then (expression)",function(s,e,c)
|
||||
if R(s,e.predicate,c,"if: predicate") then
|
||||
return R(s,e.expression,c,"if: result")
|
||||
end
|
||||
end)
|
||||
B("true",function(s,e) return true end)
|
||||
B("false",function(s,e) return false end)
|
||||
B("(constant) = (expression)",function(s,e)
|
||||
local value = s:evaluate(e.expression)
|
||||
B("true",function(s,e,c) return true end)
|
||||
B("false",function(s,e,c) return false end)
|
||||
B("(constant) = (expression)",function(s,e,c)
|
||||
local value = R(s,e.expression,c,"constant: expression")
|
||||
s:insert(
|
||||
Binding(e.constant:text(),function(s,e)
|
||||
Binding(e.constant:text(),function(s,e,c)
|
||||
return value
|
||||
end)
|
||||
)
|
||||
end)
|
||||
B("format (string) with (terms)",function(s,e)
|
||||
B("format (string) with (terms)",function(s,e,c)
|
||||
local items = {}
|
||||
for expression in iterate(e.terms.items) do
|
||||
table.insert(items,s:evaluate(expression))
|
||||
table.insert(items,R(s,expression),c,"format: term")
|
||||
end
|
||||
return string.format(
|
||||
s:evaluate(e.string),
|
||||
R(s,e.string,c,"format: string"),
|
||||
table.unpack(items)
|
||||
)
|
||||
end)
|
||||
B("while (predicate) (expression)",function(s,e)
|
||||
while s:evaluate(e.predicate) do
|
||||
s:evaluate(e.expression)
|
||||
B("while (predicate) (expression)",function(s,e,c)
|
||||
while R(s,e.predicate,c,"while: predicate") do
|
||||
R(s,e.expression,c,"while: loop")
|
||||
end
|
||||
end)
|
||||
B("repeat (expression) while (predicate)",function(s,e)
|
||||
B("repeat (expression) while (predicate)",function(s,e,c)
|
||||
while true do
|
||||
s:evaluate(e.expression)
|
||||
if not s:evaluate(e.predicate) then
|
||||
R(s,e.expression,c,"repeat: expression")
|
||||
if not R(s,e.predicate,c,"repeat: predicate") then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
B("repeat (expression) until (predicate)",function(s,e)
|
||||
end)
|
||||
B("repeat (expression) until (predicate)",function(s,e,c)
|
||||
while true do
|
||||
s:evaluate(e.expression)
|
||||
if s:evaluate(e.predicate) then
|
||||
R(s,e.expression,c,"repeat: expression")
|
||||
if R(s,e.predicate,c,"repeat: predicate") then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
B("new table",function(s,e)
|
||||
end)
|
||||
B("new table",function(s,e,c)
|
||||
return {}
|
||||
end)
|
||||
B("(index) of (table)",function(s,e)
|
||||
return s:evaluate(e.table)[s:evaluate(e.index)]
|
||||
B("(index) of (table)",function(s,e,c)
|
||||
return (R(s,e.table,"of: index"))[R(s,e.index,c,"of: table")]
|
||||
end)
|
||||
B("set (index) of (table) to (item)",function(s,e)
|
||||
s:evaluate(e.table)[s:evaluate(e.index)]
|
||||
B("set (index) of (table) to (item)",function(s,e,c)
|
||||
R(s,e.table,c,"of-to: index")[R(s,e.index,c,"of-to: table")] = s:run(e.item,c,"of-to: item")
|
||||
end)
|
||||
B("macro (macro) expands to (expression)",function(s,e)
|
||||
s:insert(Binding(e.abstract,function(_s,_e)
|
||||
B("remove (index) of (table)",function(s,e,c)
|
||||
(R(s,e.table,"remove: table"))[R(s,e.index,c,"remove: index")] = nil
|
||||
end)
|
||||
B("nil",function(s,e,c)
|
||||
return nil
|
||||
end)
|
||||
--[[ Note
|
||||
A macro executes in the same scope of the callee.
|
||||
A defintion executes in the scope it was defined.
|
||||
I would argue that macros are more unpredictable!
|
||||
However, they allow for some very clean code.
|
||||
--]]
|
||||
B("macro (macro) expands to (expression)",function(s,e,c)
|
||||
s:insert(Binding(e.abstract,function(_s,_e,_c)
|
||||
local scope = Scope()
|
||||
scope.parent = _s
|
||||
for identifier,expression in pairs(_e) do
|
||||
|
||||
scope:insert(Binding(Expression({identifier}),R(_s,expression,_c)))
|
||||
end
|
||||
_s:evaluate(e.expression)
|
||||
end)
|
||||
return R(scope,e.expression,_c,"macro: expression")
|
||||
end))
|
||||
end)
|
||||
B("define (abstract) as (expression)",function(s,e)
|
||||
s:insert(Binding(e.abstract,function(_s,_e)
|
||||
return s:evaluate(e.expression)
|
||||
B("define (abstract) as (expression)",function(s,e,c)
|
||||
s:insert(Binding(e.abstract,function(_s,_e,_c)
|
||||
local scope = Scope()
|
||||
scope.parent = s
|
||||
for identifier,expression in pairs(_e) do
|
||||
scope:insert(Binding(Expression({identifier}),R(_s,expression,_c)))
|
||||
end
|
||||
return R(scope,e.expression,_c,"define: expression")
|
||||
end))
|
||||
end)
|
||||
local List = class("List")
|
||||
function List:new(...) do
|
||||
function List:new(...)
|
||||
self.items = {...}
|
||||
end
|
||||
B("new list",function(s,e)
|
||||
B("new list",function(s,e,c)
|
||||
return List()
|
||||
end)
|
||||
B("insert (item) into (list)",function(s,e)
|
||||
|
||||
B("insert (item) into (list)",function(s,e,c)
|
||||
table.insert(R(s,e.list).items,R(s,e.item),c,c)
|
||||
end)
|
||||
B("insert (item) into (list) at (index)",function(s,e)
|
||||
|
||||
B("insert (item) into (list) at (index)",function(s,e,c)
|
||||
table.insert(s:evaulate(e.list).items,R(s,e.index),R(s,item),c,c)
|
||||
end)
|
||||
B("remove (needle) from (haystack)",function(s,e)
|
||||
|
||||
B("remove (needle) from (haystack)",function(s,e,c)
|
||||
local tab = R(s,e.haystack,c)
|
||||
table.remove(tab,table.find(tab,R(s,e.needle)),c)
|
||||
end)
|
||||
B("remove from (haystack) at (index)",function(s,e)
|
||||
s:evaluate(e.haystack)
|
||||
B("remove from (haystack) at (index)",function(s,e,c)
|
||||
table.remove(R(s,e.list),R(s,e.index),c,c)
|
||||
end)
|
||||
|
||||
local Variable = class()
|
||||
local Variable = class("Variable")
|
||||
function Variable:new()
|
||||
end
|
||||
function Variable:set(item)
|
||||
@@ -130,36 +159,66 @@ end
|
||||
function Variable:get()
|
||||
return self.data
|
||||
end
|
||||
B("let (variable)",function(s,e)
|
||||
B("let (variable)",function(s,e,c)
|
||||
local variable = Variable()
|
||||
s:insert(
|
||||
Binding(e.variable,function(s,e)
|
||||
Binding(e.variable,function(s,e,c)
|
||||
return variable
|
||||
end)
|
||||
)
|
||||
return variable
|
||||
end)
|
||||
B("set (variable) to (expression)",function(s,e)
|
||||
local var = s:evaluate(e.variable)
|
||||
local value = s:evaluate(e.expression)
|
||||
B("set (variable) to (expression)",function(s,e,c)
|
||||
local var = R(s,e.variable,c,"set: identifier")
|
||||
local value = R(s,e.expression,c,"set: expression")
|
||||
assert_meta(Variable)(var)
|
||||
var:set(value)
|
||||
end)
|
||||
B("get (variable)",function(s,e)
|
||||
local var = s:evaluate(e.variable)
|
||||
assert_meta(Variable)(var)
|
||||
B("get (variable)",function(s,e,c)
|
||||
local var = R(s,e.variable,c)
|
||||
return var:get(value)
|
||||
end)
|
||||
for item in iterate(nelli_scope.bindings) do
|
||||
print(item.template)
|
||||
end
|
||||
|
||||
local args = {...}
|
||||
local function main()
|
||||
-- Take arguments as neli files to read and interpret
|
||||
for _,parameter in pairs(args) do
|
||||
local root = interpret(read(parameter))
|
||||
nelli_scope:evaluate(root)
|
||||
local last
|
||||
local root = Chain(
|
||||
string.format(
|
||||
"in cmd 'nel {%s}'",
|
||||
table.concat(args,";")
|
||||
)
|
||||
)
|
||||
local success,result = xpcall(function()
|
||||
for _,parameter in pairs(args) do
|
||||
last = parameter
|
||||
local chain = Chain(
|
||||
string.format("in 'call: root' @'%s'",parameter)
|
||||
):from(root)
|
||||
local root = interpret(
|
||||
read(parameter),
|
||||
parameter,
|
||||
chain
|
||||
)
|
||||
assert_meta(Chain)(chain,"?")
|
||||
nelli_scope:run(root,chain)
|
||||
end
|
||||
end,function(msg)
|
||||
-- If this is a 'nel:' error, strip the line responsible
|
||||
-- Otherwise just return the whole traceback since something went really bad
|
||||
local match = msg:match("nel:%s(.*)")
|
||||
if match then
|
||||
return match
|
||||
else
|
||||
return "internal: "..debug.traceback(msg,2)
|
||||
end
|
||||
end)
|
||||
if not success then
|
||||
log(string.format(
|
||||
"nel: %s\nNEL traceback:\n\t%s",
|
||||
result,
|
||||
table.concat(root:flatten(),"\n\t")
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Reference in New Issue
Block a user