Added more bindings and error tracebacks.
This commit is contained in:
12
helper.lua
12
helper.lua
@@ -8,6 +8,13 @@ end
|
|||||||
function log(...)
|
function log(...)
|
||||||
old_print(...)
|
old_print(...)
|
||||||
end
|
end
|
||||||
|
function map(tab,func)
|
||||||
|
local new = {}
|
||||||
|
for index,item in pairs(tab) do
|
||||||
|
new[index] = func(item)
|
||||||
|
end
|
||||||
|
return new
|
||||||
|
end
|
||||||
-- HELPER FUNCTIONS
|
-- HELPER FUNCTIONS
|
||||||
-- Insert every item in t1 into t0
|
-- Insert every item in t1 into t0
|
||||||
function just(...)
|
function just(...)
|
||||||
@@ -105,7 +112,8 @@ end
|
|||||||
-- Runs a function
|
-- Runs a function
|
||||||
function assert_meta(...)
|
function assert_meta(...)
|
||||||
local metas = {...}
|
local metas = {...}
|
||||||
return function(x,raise)
|
return function(x,raise,handler)
|
||||||
|
handler = handler or error
|
||||||
local meta = getmetatable(x)
|
local meta = getmetatable(x)
|
||||||
for tab in iterate(metas) do
|
for tab in iterate(metas) do
|
||||||
if meta == tab then return end
|
if meta == tab then return end
|
||||||
@@ -124,7 +132,7 @@ function assert_meta(...)
|
|||||||
level = 3
|
level = 3
|
||||||
msg = string.format(raise,msg)
|
msg = string.format(raise,msg)
|
||||||
end
|
end
|
||||||
error(msg,level)
|
handler(msg,level)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ require("parse")
|
|||||||
-- TODO: This should really be a separate API and module
|
-- TODO: This should really be a separate API and module
|
||||||
-- please break it out
|
-- please break it out
|
||||||
-- Interpret some text
|
-- Interpret some text
|
||||||
function interpret(content)
|
function interpret(content,uri,chain)
|
||||||
-- LOCALS
|
-- LOCALS
|
||||||
-- The pattern for words inbetween expressions
|
-- The pattern for words inbetween expressions
|
||||||
local expressionWordPattern = "(.*)"
|
local expressionWordPattern = "(.*)"
|
||||||
@@ -26,8 +26,17 @@ function interpret(content)
|
|||||||
consumeText,
|
consumeText,
|
||||||
consumeNumber
|
consumeNumber
|
||||||
|
|
||||||
local baseExpression = Expression()
|
|
||||||
local consumer = Consumer(content)
|
local consumer = Consumer(content)
|
||||||
|
local function expression(...)
|
||||||
|
return Expression(...):locate(
|
||||||
|
string.format(
|
||||||
|
"%i:%i",
|
||||||
|
consumer.row,
|
||||||
|
consumer.col
|
||||||
|
),uri)
|
||||||
|
end
|
||||||
|
local baseExpression = expression()
|
||||||
|
|
||||||
-- FUNCTIONS
|
-- FUNCTIONS
|
||||||
-- Consume an expression, with its sub expressions
|
-- Consume an expression, with its sub expressions
|
||||||
@@ -37,7 +46,7 @@ function interpret(content)
|
|||||||
return function(words,_)
|
return function(words,_)
|
||||||
current:insert(words,consumer:consume({
|
current:insert(words,consumer:consume({
|
||||||
[match] = function(words,_)
|
[match] = function(words,_)
|
||||||
return Expression({"text",Expression({words})})
|
return expression({"text",Expression({words})})
|
||||||
end
|
end
|
||||||
}))
|
}))
|
||||||
end
|
end
|
||||||
@@ -51,7 +60,7 @@ function interpret(content)
|
|||||||
error("Incomplete string literal")
|
error("Incomplete string literal")
|
||||||
end,
|
end,
|
||||||
[match] = function(words,_)
|
[match] = function(words,_)
|
||||||
return Expression({"text",Expression({words})})
|
return expression({"text",Expression({words})})
|
||||||
end
|
end
|
||||||
}))
|
}))
|
||||||
end
|
end
|
||||||
@@ -62,7 +71,7 @@ function interpret(content)
|
|||||||
return function(words,_)
|
return function(words,_)
|
||||||
current:insert(words,consumer:consume({
|
current:insert(words,consumer:consume({
|
||||||
["[\n\r]"] = function()
|
["[\n\r]"] = function()
|
||||||
error("Incomplete URI literal")
|
current:error("Incomplete URI literal")
|
||||||
end,
|
end,
|
||||||
[match] = function(path)
|
[match] = function(path)
|
||||||
return read(path)
|
return read(path)
|
||||||
@@ -77,7 +86,7 @@ function interpret(content)
|
|||||||
end
|
end
|
||||||
function consumeBlock()
|
function consumeBlock()
|
||||||
local expressions = {}
|
local expressions = {}
|
||||||
local current = Expression()
|
local current = expression()
|
||||||
local loop = true
|
local loop = true
|
||||||
while loop do
|
while loop do
|
||||||
local expr = consumer:consume({
|
local expr = consumer:consume({
|
||||||
@@ -94,7 +103,7 @@ function interpret(content)
|
|||||||
error("Extravenous semicolon.")
|
error("Extravenous semicolon.")
|
||||||
end
|
end
|
||||||
table.insert(expressions,current)
|
table.insert(expressions,current)
|
||||||
current = Expression()
|
current = expression()
|
||||||
end,
|
end,
|
||||||
[blockClosePattern] = function(words,_)
|
[blockClosePattern] = function(words,_)
|
||||||
current:insert(words)
|
current:insert(words)
|
||||||
@@ -105,10 +114,10 @@ function interpret(content)
|
|||||||
if #current.items ~= 0 then
|
if #current.items ~= 0 then
|
||||||
table.insert(expressions,current)
|
table.insert(expressions,current)
|
||||||
end
|
end
|
||||||
return Expression(expressions)
|
return expression(expressions)
|
||||||
end
|
end
|
||||||
function consumeExpression()
|
function consumeExpression()
|
||||||
local current = Expression()
|
local current = expression()
|
||||||
-- Loop, adding new expressions and words,
|
-- Loop, adding new expressions and words,
|
||||||
-- until closing that is
|
-- until closing that is
|
||||||
local loop = true
|
local loop = true
|
||||||
@@ -116,7 +125,7 @@ function interpret(content)
|
|||||||
local remaining = consumer:remaining()
|
local remaining = consumer:remaining()
|
||||||
local expr = consumer:consume({
|
local expr = consumer:consume({
|
||||||
[uriOpenPattern] = URIMeal(current,uriClosePattern),
|
[uriOpenPattern] = URIMeal(current,uriClosePattern),
|
||||||
[expressionOpenPattern] = expressionMeal(remaining),
|
[expressionOpenPattern] = expressionMeal(current),
|
||||||
[multiLineStringOpenPattern] =
|
[multiLineStringOpenPattern] =
|
||||||
multiLineStringMeal(
|
multiLineStringMeal(
|
||||||
current,multiLineStringClosePattern),
|
current,multiLineStringClosePattern),
|
||||||
|
|||||||
189
main.lua
189
main.lua
@@ -9,17 +9,23 @@ local function B(abstract,callback)
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
B("print (text)",function(s,e)
|
local function R(scope,expression,chain,name)
|
||||||
log(s:evaluate(e.text))
|
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)
|
end)
|
||||||
B("text (literal)",function(s,e)
|
B("text (literal)",function(s,e,c)
|
||||||
return e.literal:text()
|
return e.literal:text()
|
||||||
end)
|
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 = Scope()
|
||||||
scope.parent = s
|
scope.parent = s
|
||||||
local res
|
local res
|
||||||
print(e.expressions)
|
|
||||||
for item in iterate(e.expressions.items) do
|
for item in iterate(e.expressions.items) do
|
||||||
if type_of(item) ~= Expression then
|
if type_of(item) ~= Expression then
|
||||||
error(
|
error(
|
||||||
@@ -29,99 +35,122 @@ B("do (expressions)",function(s,e)
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
res = scope:evaluate(item)
|
res = R(s,item,c,"do: line")
|
||||||
end
|
end
|
||||||
return res
|
return res
|
||||||
end)
|
end)
|
||||||
B("if (predicate) then (expression)",function(s,e)
|
B("error (text)",function(s,e,c)
|
||||||
if s:evaluate(e.predicate) then
|
error("nel: "..R(s,e.text,c,"error: message"))
|
||||||
return s:evaluate(e.expression)
|
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
|
||||||
end)
|
end)
|
||||||
B("true",function(s,e) return true end)
|
B("true",function(s,e,c) return true end)
|
||||||
B("false",function(s,e) return false end)
|
B("false",function(s,e,c) return false end)
|
||||||
B("(constant) = (expression)",function(s,e)
|
B("(constant) = (expression)",function(s,e,c)
|
||||||
local value = s:evaluate(e.expression)
|
local value = R(s,e.expression,c,"constant: expression")
|
||||||
s:insert(
|
s:insert(
|
||||||
Binding(e.constant:text(),function(s,e)
|
Binding(e.constant:text(),function(s,e,c)
|
||||||
return value
|
return value
|
||||||
end)
|
end)
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
B("format (string) with (terms)",function(s,e)
|
B("format (string) with (terms)",function(s,e,c)
|
||||||
local items = {}
|
local items = {}
|
||||||
for expression in iterate(e.terms.items) do
|
for expression in iterate(e.terms.items) do
|
||||||
table.insert(items,s:evaluate(expression))
|
table.insert(items,R(s,expression),c,"format: term")
|
||||||
end
|
end
|
||||||
return string.format(
|
return string.format(
|
||||||
s:evaluate(e.string),
|
R(s,e.string,c,"format: string"),
|
||||||
table.unpack(items)
|
table.unpack(items)
|
||||||
)
|
)
|
||||||
end)
|
end)
|
||||||
B("while (predicate) (expression)",function(s,e)
|
B("while (predicate) (expression)",function(s,e,c)
|
||||||
while s:evaluate(e.predicate) do
|
while R(s,e.predicate,c,"while: predicate") do
|
||||||
s:evaluate(e.expression)
|
R(s,e.expression,c,"while: loop")
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
B("repeat (expression) while (predicate)",function(s,e)
|
B("repeat (expression) while (predicate)",function(s,e,c)
|
||||||
while true do
|
while true do
|
||||||
s:evaluate(e.expression)
|
R(s,e.expression,c,"repeat: expression")
|
||||||
if not s:evaluate(e.predicate) then
|
if not R(s,e.predicate,c,"repeat: predicate") then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
B("repeat (expression) until (predicate)",function(s,e)
|
B("repeat (expression) until (predicate)",function(s,e,c)
|
||||||
while true do
|
while true do
|
||||||
s:evaluate(e.expression)
|
R(s,e.expression,c,"repeat: expression")
|
||||||
if s:evaluate(e.predicate) then
|
if R(s,e.predicate,c,"repeat: predicate") then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end)
|
||||||
B("new table",function(s,e)
|
B("new table",function(s,e,c)
|
||||||
return {}
|
return {}
|
||||||
end)
|
end)
|
||||||
B("(index) of (table)",function(s,e)
|
B("(index) of (table)",function(s,e,c)
|
||||||
return s:evaluate(e.table)[s:evaluate(e.index)]
|
return (R(s,e.table,"of: index"))[R(s,e.index,c,"of: table")]
|
||||||
end)
|
end)
|
||||||
B("set (index) of (table) to (item)",function(s,e)
|
B("set (index) of (table) to (item)",function(s,e,c)
|
||||||
s:evaluate(e.table)[s:evaluate(e.index)]
|
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)
|
end)
|
||||||
B("macro (macro) expands to (expression)",function(s,e)
|
B("remove (index) of (table)",function(s,e,c)
|
||||||
s:insert(Binding(e.abstract,function(_s,_e)
|
(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
|
for identifier,expression in pairs(_e) do
|
||||||
|
scope:insert(Binding(Expression({identifier}),R(_s,expression,_c)))
|
||||||
end
|
end
|
||||||
_s:evaluate(e.expression)
|
return R(scope,e.expression,_c,"macro: expression")
|
||||||
end)
|
end))
|
||||||
end)
|
end)
|
||||||
B("define (abstract) as (expression)",function(s,e)
|
B("define (abstract) as (expression)",function(s,e,c)
|
||||||
s:insert(Binding(e.abstract,function(_s,_e)
|
s:insert(Binding(e.abstract,function(_s,_e,_c)
|
||||||
return s:evaluate(e.expression)
|
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))
|
||||||
end)
|
end)
|
||||||
local List = class("List")
|
local List = class("List")
|
||||||
function List:new(...) do
|
function List:new(...)
|
||||||
self.items = {...}
|
self.items = {...}
|
||||||
end
|
end
|
||||||
B("new list",function(s,e)
|
B("new list",function(s,e,c)
|
||||||
return List()
|
return List()
|
||||||
end)
|
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)
|
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)
|
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)
|
end)
|
||||||
B("remove from (haystack) at (index)",function(s,e)
|
B("remove from (haystack) at (index)",function(s,e,c)
|
||||||
s:evaluate(e.haystack)
|
table.remove(R(s,e.list),R(s,e.index),c,c)
|
||||||
end)
|
end)
|
||||||
|
|
||||||
local Variable = class()
|
local Variable = class("Variable")
|
||||||
function Variable:new()
|
function Variable:new()
|
||||||
end
|
end
|
||||||
function Variable:set(item)
|
function Variable:set(item)
|
||||||
@@ -130,36 +159,66 @@ end
|
|||||||
function Variable:get()
|
function Variable:get()
|
||||||
return self.data
|
return self.data
|
||||||
end
|
end
|
||||||
B("let (variable)",function(s,e)
|
B("let (variable)",function(s,e,c)
|
||||||
local variable = Variable()
|
local variable = Variable()
|
||||||
s:insert(
|
s:insert(
|
||||||
Binding(e.variable,function(s,e)
|
Binding(e.variable,function(s,e,c)
|
||||||
return variable
|
return variable
|
||||||
end)
|
end)
|
||||||
)
|
)
|
||||||
return variable
|
return variable
|
||||||
end)
|
end)
|
||||||
B("set (variable) to (expression)",function(s,e)
|
B("set (variable) to (expression)",function(s,e,c)
|
||||||
local var = s:evaluate(e.variable)
|
local var = R(s,e.variable,c,"set: identifier")
|
||||||
local value = s:evaluate(e.expression)
|
local value = R(s,e.expression,c,"set: expression")
|
||||||
assert_meta(Variable)(var)
|
assert_meta(Variable)(var)
|
||||||
var:set(value)
|
var:set(value)
|
||||||
end)
|
end)
|
||||||
B("get (variable)",function(s,e)
|
B("get (variable)",function(s,e,c)
|
||||||
local var = s:evaluate(e.variable)
|
local var = R(s,e.variable,c)
|
||||||
assert_meta(Variable)(var)
|
|
||||||
return var:get(value)
|
return var:get(value)
|
||||||
end)
|
end)
|
||||||
for item in iterate(nelli_scope.bindings) do
|
|
||||||
print(item.template)
|
|
||||||
end
|
|
||||||
|
|
||||||
local args = {...}
|
local args = {...}
|
||||||
local function main()
|
local function main()
|
||||||
-- Take arguments as neli files to read and interpret
|
-- Take arguments as neli files to read and interpret
|
||||||
|
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
|
for _,parameter in pairs(args) do
|
||||||
local root = interpret(read(parameter))
|
last = parameter
|
||||||
nelli_scope:evaluate(root)
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
115
parse.lua
115
parse.lua
@@ -1,4 +1,5 @@
|
|||||||
require("helper")
|
require("helper")
|
||||||
|
|
||||||
-- CLASS DEFINITIONS
|
-- CLASS DEFINITIONS
|
||||||
-- A stream of text (kind of)
|
-- A stream of text (kind of)
|
||||||
-- with some helping methods
|
-- with some helping methods
|
||||||
@@ -128,13 +129,32 @@ function Expression:text()
|
|||||||
if type(text) ~= "string" then return end
|
if type(text) ~= "string" then return end
|
||||||
return text
|
return text
|
||||||
end
|
end
|
||||||
|
function Expression:locate(str,uri)
|
||||||
|
self.location = str
|
||||||
|
self.source = uri
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
function Expression:link(msg)
|
||||||
|
return string.format(
|
||||||
|
"in '%s' @%s (%s)",
|
||||||
|
msg,
|
||||||
|
tostring(self),
|
||||||
|
tostring(self.location or "?"),
|
||||||
|
tostring(self.source or "?.nel")
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
Consumer = class("Consumer")
|
Consumer = class("Consumer")
|
||||||
function Consumer:new(content)
|
function Consumer:new(content)
|
||||||
self.range = Range(Reader(content))
|
self.range = Range(Reader(content))
|
||||||
|
self.col = 1
|
||||||
|
self.row = 1
|
||||||
end
|
end
|
||||||
function Consumer:remaining()
|
function Consumer:remaining()
|
||||||
return self.range:text()
|
return self.range:text()
|
||||||
|
end
|
||||||
|
function Consumer:mark()
|
||||||
|
|
||||||
end
|
end
|
||||||
-- From a table of actions of patterns,
|
-- From a table of actions of patterns,
|
||||||
-- consume the earliest pattern (index)
|
-- consume the earliest pattern (index)
|
||||||
@@ -149,6 +169,7 @@ function Consumer:consume(t)
|
|||||||
assert_type("string")(index,"Bad 't' index: %s")
|
assert_type("string")(index,"Bad 't' index: %s")
|
||||||
assert_type("function")(func,"Bad 't' item: %s")
|
assert_type("function")(func,"Bad 't' item: %s")
|
||||||
end
|
end
|
||||||
|
local origin = self.range.first or 1
|
||||||
-- Get the next earliest match
|
-- Get the next earliest match
|
||||||
local findex,ffinal,fpattern,ffunc,fexcess
|
local findex,ffinal,fpattern,ffunc,fexcess
|
||||||
for pattern,new_func in pairs(t) do
|
for pattern,new_func in pairs(t) do
|
||||||
@@ -173,8 +194,20 @@ function Consumer:consume(t)
|
|||||||
end
|
end
|
||||||
assert(findex) assert(ffinal)
|
assert(findex) assert(ffinal)
|
||||||
self.range:move(ffinal+1) -- Move range to after the match
|
self.range:move(ffinal+1) -- Move range to after the match
|
||||||
|
local fmatch = self.range.reader:match(fpattern,findex)
|
||||||
-- Pass back consumed result to
|
-- Pass back consumed result to
|
||||||
return ffunc(fexcess,self.range.reader:match(fpattern,findex))
|
local sum = self.range.reader:get(origin+1,self.range.first)
|
||||||
|
:gsub("\r\n","\n")
|
||||||
|
:gsub("\r","\n")
|
||||||
|
for char in sum:gmatch(".") do
|
||||||
|
if char == "\n" then
|
||||||
|
self.row = self.row + 1
|
||||||
|
self.col = 1
|
||||||
|
else
|
||||||
|
self.col = self.col + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return ffunc(fexcess,fmatch)
|
||||||
end
|
end
|
||||||
|
|
||||||
Binding = class("Binding")
|
Binding = class("Binding")
|
||||||
@@ -182,12 +215,20 @@ Binding = class("Binding")
|
|||||||
-- note that you must wrap this definition in "(<def>)"!
|
-- note that you must wrap this definition in "(<def>)"!
|
||||||
function Binding:new(expression,callback)
|
function Binding:new(expression,callback)
|
||||||
assert_meta(Expression)(expression,"Arg 'expression' #1: %s")
|
assert_meta(Expression)(expression,"Arg 'expression' #1: %s")
|
||||||
assert_type("function")(callback,"Arg 'callback' #2: %s")
|
if type_of(callback) == "function" then
|
||||||
self.template = expression:abstract(true)
|
|
||||||
self.callback = callback
|
self.callback = callback
|
||||||
|
else
|
||||||
|
self.value = callback
|
||||||
|
end
|
||||||
|
self.template = expression:abstract(true)
|
||||||
end
|
end
|
||||||
function Binding:call(scope,binds)
|
function Binding:string()
|
||||||
return self.callback(scope,binds)
|
return string.format("Binding %s: %s",self.template,tostring(self.value or self.callback))
|
||||||
|
end
|
||||||
|
function Binding:call(s,e,c)
|
||||||
|
assert_meta(Scope)(s)
|
||||||
|
assert_meta(Chain)(c)
|
||||||
|
return self.value or self.callback(s,e,c)
|
||||||
end
|
end
|
||||||
function Binding:check(expression)
|
function Binding:check(expression)
|
||||||
assert_meta(Expression)(expression,"Arg 'expression' #1: %s")
|
assert_meta(Expression)(expression,"Arg 'expression' #1: %s")
|
||||||
@@ -228,6 +269,29 @@ function Binding:check(expression)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Chain = class("Chain")
|
||||||
|
function Chain:new(data)
|
||||||
|
assert_type("string")(data,"Arg 'data' #1: %s")
|
||||||
|
self.data = data
|
||||||
|
end
|
||||||
|
function Chain:from(previous)
|
||||||
|
assert_meta(Chain)(previous,"Arg 'previous' #1: %s")
|
||||||
|
previous.next = self
|
||||||
|
self.previous = previous
|
||||||
|
return self
|
||||||
|
end
|
||||||
|
function Chain:string()
|
||||||
|
return string.format("Chain:%s",table.concat(self:flatten(),", "))
|
||||||
|
end
|
||||||
|
function Chain:flatten(tab)
|
||||||
|
tab = tab or {}
|
||||||
|
if self.next then
|
||||||
|
self.next:flatten(tab)
|
||||||
|
end
|
||||||
|
table.insert(tab,self.data)
|
||||||
|
return tab
|
||||||
|
end
|
||||||
|
|
||||||
-- The scope of a neli expression under evaluation
|
-- The scope of a neli expression under evaluation
|
||||||
-- without exact faith to traditional language scopes
|
-- without exact faith to traditional language scopes
|
||||||
Scope = class("Scope")
|
Scope = class("Scope")
|
||||||
@@ -237,13 +301,22 @@ function Scope:new(bindings)
|
|||||||
self:insert(binding)
|
self:insert(binding)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
function Scope:string()
|
||||||
|
return string.format("Scope: {\n\t%s\n}",table.concat(map(self.bindings,tostring),"\n\t"))
|
||||||
|
end
|
||||||
function Scope:insert(binding)
|
function Scope:insert(binding)
|
||||||
assert_meta(binding,Binding)
|
assert_meta(Binding)(binding,"Arg 'binding' #1: %s")
|
||||||
|
for competitor in iterate(self.bindings) do
|
||||||
|
if competitor:check(binding.template) then
|
||||||
|
nerror("Conflicting sibling bindings in scope.")
|
||||||
|
end
|
||||||
|
end
|
||||||
table.insert(self.bindings,binding)
|
table.insert(self.bindings,binding)
|
||||||
end
|
end
|
||||||
function Scope:evaluate(expression)
|
function Scope:run(expression,chain,original)
|
||||||
|
original = original or self
|
||||||
assert_meta(Expression)(expression,"Arg 'expression' #1: %s")
|
assert_meta(Expression)(expression,"Arg 'expression' #1: %s")
|
||||||
local parent = self.parent
|
assert_meta(Chain)(chain,"Arg 'chain' #2: %s")
|
||||||
-- Could be multiple bindings so make a table
|
-- Could be multiple bindings so make a table
|
||||||
local binds = {}
|
local binds = {}
|
||||||
for binding in iterate(self.bindings) do
|
for binding in iterate(self.bindings) do
|
||||||
@@ -254,13 +327,23 @@ function Scope:evaluate(expression)
|
|||||||
local binding,bind = next(binds)
|
local binding,bind = next(binds)
|
||||||
-- Check for multiple
|
-- Check for multiple
|
||||||
if not bind then
|
if not bind then
|
||||||
if parent then
|
if self.parent then
|
||||||
parent:evaluate(expression)
|
return self.parent:run(expression,chain,self)
|
||||||
else
|
else
|
||||||
|
local extra = ""
|
||||||
|
if #expression.items == 1 then
|
||||||
|
local item = expression.items[1]
|
||||||
|
if type_of(item) == Expression then
|
||||||
|
extra = extra .. "\nNote: This expression is formed (just bracketed) of another single expression. Maybe too many brackets were used here?"
|
||||||
|
else
|
||||||
|
extra = extra .. "\n\tNote: This is a 'text' expression, it has no subexpressions. It is most likely that an expected object definition was not bound to the scope or there is a typo."
|
||||||
|
end
|
||||||
|
end
|
||||||
error(
|
error(
|
||||||
string.format(
|
string.format(
|
||||||
"No binding for '%s' in transitive scope.",
|
"nel: No binding for '%s' in scope.",
|
||||||
tostring(expression)
|
tostring(expression:abstract()),
|
||||||
|
extra
|
||||||
),3
|
),3
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
@@ -272,13 +355,17 @@ function Scope:evaluate(expression)
|
|||||||
end
|
end
|
||||||
error(
|
error(
|
||||||
string.format(
|
string.format(
|
||||||
"Ambiguous bindings in scope for '%s': %s",
|
"nel: Ambiguous bindings in scope for '%s': %s",
|
||||||
tostring(expression:abstract()),
|
tostring(expression:abstract()),
|
||||||
table.concat(candidates)
|
table.concat(candidates)
|
||||||
)
|
)
|
||||||
,2)
|
,2)
|
||||||
else
|
else
|
||||||
return binding:call(self,bind)
|
return binding:call(
|
||||||
|
original,
|
||||||
|
bind,
|
||||||
|
chain
|
||||||
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return _G
|
return _G
|
||||||
|
|||||||
205
session.vim
Normal file
205
session.vim
Normal file
@@ -0,0 +1,205 @@
|
|||||||
|
let SessionLoad = 1
|
||||||
|
let s:so_save = &g:so | let s:siso_save = &g:siso | setg so=0 siso=0 | setl so=-1 siso=-1
|
||||||
|
let v:this_session=expand("<sfile>:p")
|
||||||
|
silent only
|
||||||
|
silent tabonly
|
||||||
|
cd ~/Programming/nel/1
|
||||||
|
if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == ''
|
||||||
|
let s:wipebuf = bufnr('%')
|
||||||
|
endif
|
||||||
|
let s:shortmess_save = &shortmess
|
||||||
|
if &shortmess =~ 'A'
|
||||||
|
set shortmess=aoOA
|
||||||
|
else
|
||||||
|
set shortmess=aoO
|
||||||
|
endif
|
||||||
|
badd +167 main.lua
|
||||||
|
badd +27 parse.lua
|
||||||
|
badd +0 term://~/Programming/nel/1//1946:/usr/bin/zsh
|
||||||
|
badd +0 interpret.lua
|
||||||
|
badd +0 test.nel
|
||||||
|
badd +191 helper.lua
|
||||||
|
argglobal
|
||||||
|
%argdel
|
||||||
|
$argadd ~/Programming/nel/1
|
||||||
|
edit parse.lua
|
||||||
|
let s:save_splitbelow = &splitbelow
|
||||||
|
let s:save_splitright = &splitright
|
||||||
|
set splitbelow splitright
|
||||||
|
wincmd _ | wincmd |
|
||||||
|
vsplit
|
||||||
|
1wincmd h
|
||||||
|
wincmd _ | wincmd |
|
||||||
|
split
|
||||||
|
1wincmd k
|
||||||
|
wincmd _ | wincmd |
|
||||||
|
vsplit
|
||||||
|
1wincmd h
|
||||||
|
wincmd w
|
||||||
|
wincmd w
|
||||||
|
wincmd w
|
||||||
|
wincmd _ | wincmd |
|
||||||
|
split
|
||||||
|
1wincmd k
|
||||||
|
wincmd w
|
||||||
|
let &splitbelow = s:save_splitbelow
|
||||||
|
let &splitright = s:save_splitright
|
||||||
|
wincmd t
|
||||||
|
let s:save_winminheight = &winminheight
|
||||||
|
let s:save_winminwidth = &winminwidth
|
||||||
|
set winminheight=0
|
||||||
|
set winheight=1
|
||||||
|
set winminwidth=0
|
||||||
|
set winwidth=1
|
||||||
|
exe '1resize ' . ((&lines * 24 + 19) / 39)
|
||||||
|
exe 'vert 1resize ' . ((&columns * 60 + 90) / 181)
|
||||||
|
exe '2resize ' . ((&lines * 24 + 19) / 39)
|
||||||
|
exe 'vert 2resize ' . ((&columns * 60 + 90) / 181)
|
||||||
|
exe '3resize ' . ((&lines * 12 + 19) / 39)
|
||||||
|
exe 'vert 3resize ' . ((&columns * 121 + 90) / 181)
|
||||||
|
exe '4resize ' . ((&lines * 24 + 19) / 39)
|
||||||
|
exe 'vert 4resize ' . ((&columns * 59 + 90) / 181)
|
||||||
|
exe '5resize ' . ((&lines * 12 + 19) / 39)
|
||||||
|
exe 'vert 5resize ' . ((&columns * 59 + 90) / 181)
|
||||||
|
argglobal
|
||||||
|
setlocal foldmethod=manual
|
||||||
|
setlocal foldexpr=v:lua.vim.treesitter.foldexpr()
|
||||||
|
setlocal foldmarker={{{,}}}
|
||||||
|
setlocal foldignore=#
|
||||||
|
setlocal foldlevel=0
|
||||||
|
setlocal foldminlines=1
|
||||||
|
setlocal foldnestmax=20
|
||||||
|
setlocal foldenable
|
||||||
|
silent! normal! zE
|
||||||
|
let &fdl = &fdl
|
||||||
|
let s:l = 267 - ((8 * winheight(0) + 12) / 24)
|
||||||
|
if s:l < 1 | let s:l = 1 | endif
|
||||||
|
keepjumps exe s:l
|
||||||
|
normal! zt
|
||||||
|
keepjumps 267
|
||||||
|
normal! 019|
|
||||||
|
lcd ~/Programming/nel/1
|
||||||
|
wincmd w
|
||||||
|
argglobal
|
||||||
|
if bufexists(fnamemodify("~/Programming/nel/1/interpret.lua", ":p")) | buffer ~/Programming/nel/1/interpret.lua | else | edit ~/Programming/nel/1/interpret.lua | endif
|
||||||
|
if &buftype ==# 'terminal'
|
||||||
|
silent file ~/Programming/nel/1/interpret.lua
|
||||||
|
endif
|
||||||
|
balt ~/Programming/nel/1/parse.lua
|
||||||
|
setlocal foldmethod=manual
|
||||||
|
setlocal foldexpr=v:lua.vim.treesitter.foldexpr()
|
||||||
|
setlocal foldmarker={{{,}}}
|
||||||
|
setlocal foldignore=#
|
||||||
|
setlocal foldlevel=0
|
||||||
|
setlocal foldminlines=1
|
||||||
|
setlocal foldnestmax=20
|
||||||
|
setlocal foldenable
|
||||||
|
silent! normal! zE
|
||||||
|
let &fdl = &fdl
|
||||||
|
let s:l = 58 - ((15 * winheight(0) + 12) / 24)
|
||||||
|
if s:l < 1 | let s:l = 1 | endif
|
||||||
|
keepjumps exe s:l
|
||||||
|
normal! zt
|
||||||
|
keepjumps 58
|
||||||
|
normal! 034|
|
||||||
|
lcd ~/Programming/nel/1
|
||||||
|
wincmd w
|
||||||
|
argglobal
|
||||||
|
if bufexists(fnamemodify("term://~/Programming/nel/1//1946:/usr/bin/zsh", ":p")) | buffer term://~/Programming/nel/1//1946:/usr/bin/zsh | else | edit term://~/Programming/nel/1//1946:/usr/bin/zsh | endif
|
||||||
|
if &buftype ==# 'terminal'
|
||||||
|
silent file term://~/Programming/nel/1//1946:/usr/bin/zsh
|
||||||
|
endif
|
||||||
|
balt ~/Programming/nel/1/parse.lua
|
||||||
|
setlocal foldmethod=manual
|
||||||
|
setlocal foldexpr=0
|
||||||
|
setlocal foldmarker={{{,}}}
|
||||||
|
setlocal foldignore=#
|
||||||
|
setlocal foldlevel=0
|
||||||
|
setlocal foldminlines=1
|
||||||
|
setlocal foldnestmax=20
|
||||||
|
setlocal foldenable
|
||||||
|
let s:l = 947 - ((11 * winheight(0) + 6) / 12)
|
||||||
|
if s:l < 1 | let s:l = 1 | endif
|
||||||
|
keepjumps exe s:l
|
||||||
|
normal! zt
|
||||||
|
keepjumps 947
|
||||||
|
normal! 040|
|
||||||
|
lcd ~/Programming/nel/1
|
||||||
|
wincmd w
|
||||||
|
argglobal
|
||||||
|
if bufexists(fnamemodify("~/Programming/nel/1/main.lua", ":p")) | buffer ~/Programming/nel/1/main.lua | else | edit ~/Programming/nel/1/main.lua | endif
|
||||||
|
if &buftype ==# 'terminal'
|
||||||
|
silent file ~/Programming/nel/1/main.lua
|
||||||
|
endif
|
||||||
|
balt ~/Programming/nel/1/helper.lua
|
||||||
|
setlocal foldmethod=manual
|
||||||
|
setlocal foldexpr=v:lua.vim.treesitter.foldexpr()
|
||||||
|
setlocal foldmarker={{{,}}}
|
||||||
|
setlocal foldignore=#
|
||||||
|
setlocal foldlevel=0
|
||||||
|
setlocal foldminlines=1
|
||||||
|
setlocal foldnestmax=20
|
||||||
|
setlocal foldenable
|
||||||
|
silent! normal! zE
|
||||||
|
let &fdl = &fdl
|
||||||
|
let s:l = 178 - ((21 * winheight(0) + 12) / 24)
|
||||||
|
if s:l < 1 | let s:l = 1 | endif
|
||||||
|
keepjumps exe s:l
|
||||||
|
normal! zt
|
||||||
|
keepjumps 178
|
||||||
|
normal! 012|
|
||||||
|
lcd ~/Programming/nel/1
|
||||||
|
wincmd w
|
||||||
|
argglobal
|
||||||
|
if bufexists(fnamemodify("~/Programming/nel/1/test.nel", ":p")) | buffer ~/Programming/nel/1/test.nel | else | edit ~/Programming/nel/1/test.nel | endif
|
||||||
|
if &buftype ==# 'terminal'
|
||||||
|
silent file ~/Programming/nel/1/test.nel
|
||||||
|
endif
|
||||||
|
balt ~/Programming/nel/1/main.lua
|
||||||
|
setlocal foldmethod=manual
|
||||||
|
setlocal foldexpr=0
|
||||||
|
setlocal foldmarker={{{,}}}
|
||||||
|
setlocal foldignore=#
|
||||||
|
setlocal foldlevel=0
|
||||||
|
setlocal foldminlines=1
|
||||||
|
setlocal foldnestmax=20
|
||||||
|
setlocal foldenable
|
||||||
|
silent! normal! zE
|
||||||
|
let &fdl = &fdl
|
||||||
|
let s:l = 5 - ((4 * winheight(0) + 6) / 12)
|
||||||
|
if s:l < 1 | let s:l = 1 | endif
|
||||||
|
keepjumps exe s:l
|
||||||
|
normal! zt
|
||||||
|
keepjumps 5
|
||||||
|
normal! 0
|
||||||
|
lcd ~/Programming/nel/1
|
||||||
|
wincmd w
|
||||||
|
3wincmd w
|
||||||
|
exe '1resize ' . ((&lines * 24 + 19) / 39)
|
||||||
|
exe 'vert 1resize ' . ((&columns * 60 + 90) / 181)
|
||||||
|
exe '2resize ' . ((&lines * 24 + 19) / 39)
|
||||||
|
exe 'vert 2resize ' . ((&columns * 60 + 90) / 181)
|
||||||
|
exe '3resize ' . ((&lines * 12 + 19) / 39)
|
||||||
|
exe 'vert 3resize ' . ((&columns * 121 + 90) / 181)
|
||||||
|
exe '4resize ' . ((&lines * 24 + 19) / 39)
|
||||||
|
exe 'vert 4resize ' . ((&columns * 59 + 90) / 181)
|
||||||
|
exe '5resize ' . ((&lines * 12 + 19) / 39)
|
||||||
|
exe 'vert 5resize ' . ((&columns * 59 + 90) / 181)
|
||||||
|
tabnext 1
|
||||||
|
if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0 && getbufvar(s:wipebuf, '&buftype') isnot# 'terminal'
|
||||||
|
silent exe 'bwipe ' . s:wipebuf
|
||||||
|
endif
|
||||||
|
unlet! s:wipebuf
|
||||||
|
set winheight=1 winwidth=20
|
||||||
|
let &shortmess = s:shortmess_save
|
||||||
|
let &winminheight = s:save_winminheight
|
||||||
|
let &winminwidth = s:save_winminwidth
|
||||||
|
let s:sx = expand("<sfile>:p:r")."x.vim"
|
||||||
|
if filereadable(s:sx)
|
||||||
|
exe "source " . fnameescape(s:sx)
|
||||||
|
endif
|
||||||
|
let &g:so = s:so_save | let &g:siso = s:siso_save
|
||||||
|
set hlsearch
|
||||||
|
doautoall SessionLoadPost
|
||||||
|
unlet SessionLoad
|
||||||
|
" vim: set ft=vim :
|
||||||
Reference in New Issue
Block a user