328 lines
8.6 KiB
Lua
328 lines
8.6 KiB
Lua
require("interpret")
|
|
|
|
function B(scope,abstract,callback)
|
|
scope:insert(
|
|
Binding(
|
|
interpret(abstract),
|
|
callback
|
|
)
|
|
)
|
|
end
|
|
function R(scope,expression,chain,name)
|
|
name = name or "?"
|
|
assert_meta(Expression)(expression,"Arg 'expression' #2: %s")
|
|
assert_meta(Chain)(chain,"Arg 'chain' #3: %s")
|
|
local chain = Chain(expression:link(name)):from(chain)
|
|
return scope:run(expression,chain,scope)
|
|
end
|
|
|
|
NelliScope = Scope()
|
|
local ns = NelliScope
|
|
B(ns,"print (text)",function(s,e,c)
|
|
log(R(s,e.text,c,"print: text"))
|
|
end)
|
|
B(ns,"text (literal)",function(s,e,c)
|
|
return e.literal:text()
|
|
end)
|
|
-- Replace all :text() occurrences with ones in 'exp_map'
|
|
local function substitute(target,exp_map)
|
|
local text = target:text()
|
|
if text then -- Replace the parameter
|
|
local map = exp_map[text]
|
|
if map then
|
|
return Expression({map})
|
|
else
|
|
return target
|
|
end
|
|
else
|
|
local new = Expression()
|
|
for sub in iterate(target.items) do
|
|
local t = type_of(sub)
|
|
if t == "string" then
|
|
new:insert(sub)
|
|
elseif t == Expression then
|
|
new:insert(substitute(sub,exp_map))
|
|
end
|
|
end
|
|
return new
|
|
end
|
|
end
|
|
-- Iterate over all :text() occurrences
|
|
local function traverse(expression,callback)
|
|
for sub in iterate(expression.items) do
|
|
if type_of("sub") == Expression then
|
|
traverse(sub,callback)
|
|
else
|
|
callback(sub)
|
|
end
|
|
end
|
|
end
|
|
local function Bmeans(s,e,c)
|
|
local scope
|
|
if e.scope then
|
|
scope = R(s,e.scope,c,"means: using: scope: %s")
|
|
end
|
|
local bound = {}
|
|
for sub in iterate(e.abstract.items) do
|
|
local t = type_of(sub)
|
|
if t == Expression then
|
|
local text = sub:text()
|
|
if not text:match("'.+'") then
|
|
--[[error(string.format(
|
|
"nel: Abstract parameter \"%s\" not in 'quotes'.",
|
|
text
|
|
))]]
|
|
else
|
|
table.insert(bound,text)
|
|
end
|
|
end
|
|
end
|
|
return Binding(e.abstract,function(_s,_e,_c)
|
|
local map = {}
|
|
for binding in iterate(bound) do
|
|
map[binding] = _e[binding]
|
|
end
|
|
local expanded = substitute(e.expression,map)
|
|
return R(scope or _s,expanded,_c,"means: "..tostring(expanded))
|
|
end)
|
|
end
|
|
B(ns,"(abstract) means (expression) using (scope)",Bmeans)
|
|
local function Bdo(s,e,c)
|
|
local scope
|
|
if e.scope then
|
|
scope = R(s,e.scope,c,"do: scope")
|
|
else
|
|
scope = Scope()
|
|
scope.parent = s
|
|
end
|
|
local res
|
|
for item in iterate(e.expressions.items) do
|
|
if type_of(item) ~= Expression then
|
|
error(
|
|
string.format(
|
|
"Unexpected words '%s' in 'do' expression.",
|
|
tostring(item)
|
|
)
|
|
)
|
|
end
|
|
res = R(scope,item,c,"do: line")
|
|
end
|
|
return res
|
|
end
|
|
B(ns,"do (expressions)",Bdo)
|
|
B(ns,"do (expression) in (scope)",function(s,e,c)
|
|
local scope = R(s,e.scope,c,"do: scope")
|
|
assert_meta(Scope)(scope,"nel: (do: scope): %s")
|
|
R(scope,e.expression,c,"do: expression")
|
|
end)
|
|
B(ns,"error (text)",function(s,e,c)
|
|
error("nel: "..R(s,e.text,c,"error: message"))
|
|
end)
|
|
B(ns,"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(ns,"true",function(s,e,c) return true end)
|
|
B(ns,"false",function(s,e,c) return false end)
|
|
B(ns,"constant (constant) = (expression)",function(s,e,c)
|
|
local value = R(s,e.expression,c,"constant: expression")
|
|
e.constant:text()
|
|
s:insert(
|
|
Binding(e.constant,function(s,e,c)
|
|
return value
|
|
end)
|
|
)
|
|
end)
|
|
B(ns,"format (string) with (terms)",function(s,e,c)
|
|
local items = {}
|
|
for expression in iterate(e.terms.items) do
|
|
table.insert(items,R(s,expression),c,"format: term")
|
|
end
|
|
return string.format(
|
|
R(s,e.string,c,"format: string"),
|
|
table.unpack(items)
|
|
)
|
|
end)
|
|
B(ns,"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(ns,"repeat (expression) while (predicate)",function(s,e,c)
|
|
while true do
|
|
R(s,e.expression,c,"repeat: expression")
|
|
if not R(s,e.predicate,c,"repeat: predicate") then
|
|
break
|
|
end
|
|
end
|
|
end)
|
|
B(ns,"repeat (expression) until (predicate)",function(s,e,c)
|
|
while true do
|
|
R(s,e.expression,c,"repeat: expression")
|
|
if R(s,e.predicate,c,"repeat: predicate") then
|
|
break
|
|
end
|
|
end
|
|
end)
|
|
B(ns,"new table",function(s,e,c)
|
|
return {}
|
|
end)
|
|
B(ns,"(index) of (table)",function(s,e,c)
|
|
return (R(s,e.table,"of: index"))[R(s,e.index,c,"of: table")]
|
|
end)
|
|
B(ns,"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(ns,"remove (index) of (table)",function(s,e,c)
|
|
(R(s,e.table,"remove: table"))[R(s,e.index,c,"remove: index")] = nil
|
|
end)
|
|
B(ns,"nothing",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(ns,"here",function(s,e,c)
|
|
return s
|
|
end)
|
|
B(ns,"return (object)",function(s,e,c)
|
|
return R(s,e.object,c,"return: object")
|
|
end)
|
|
B(ns,"this scope",function(s,e,c)
|
|
return s
|
|
end)
|
|
B(ns,"in scope (scope) (expressions)",function(s,e,c)
|
|
return R(R(s,e.scope,c,"in scope: scope"),e.scope,c,"in scope: expression")
|
|
end)
|
|
|
|
local function Bdef(s,e,c)
|
|
if e.scope then
|
|
s = R(s,e.scope,c,"define: scope")
|
|
end
|
|
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,string.format(
|
|
"define: param: \"%s\"",
|
|
identifier
|
|
))
|
|
)
|
|
)
|
|
end
|
|
return R(scope,e.expression,_c,string.format(
|
|
"define: expression:\n\t\t%s\n\t",
|
|
table.concat(c:flatten(),"\n\t")
|
|
))
|
|
end))
|
|
end
|
|
B(ns,"define (abstract) as (expression)",Bdef)
|
|
B(ns,"define (abstract) as (expression) in (scope)",Bdef)
|
|
-- Create a constant binding
|
|
B(ns,"(abstract) is (expression)",function(s,e,c)
|
|
local result = R(s,e.expression,c,"be: expression")
|
|
return Binding(e.abstract,result)
|
|
end)
|
|
-- Insert a binding into the current scope
|
|
B(ns,"here (bindings)",function(s,e,c)
|
|
for meaning in e.binding:iterate() do
|
|
for sub in e.binding:iterate() do
|
|
local t = type_of(sub)
|
|
if t ~= Expression then
|
|
print(t,getmetatable(t))
|
|
error(string.format(
|
|
"nel: (here: bindings): %s%s\n\t%s",
|
|
"Expected subexpressions only got: ",
|
|
tostring(sub),
|
|
"Note: Are you using '{...}' style brackets?"
|
|
))
|
|
else
|
|
local bind = R(s,sub,c,"here: binding")
|
|
assert_meta(Binding)(bind,"nel: (here: binding): %s")
|
|
s:insert(bind)
|
|
end
|
|
end
|
|
end
|
|
end)
|
|
-- Insert a binding into a scope
|
|
B(ns,"in (scope) let (binding)",function(s,e,c)
|
|
assert_meta(Binding)(e.binding,"nel: (here: binding): %s")
|
|
assert_meta(Scope)(e.scope,"nel: (here: scope): %s")
|
|
R(s,e.scope,c,"let: scope"):insert(R(s,e.binding,c,"let: binding"))
|
|
end)
|
|
B(ns,[[
|
|
define (abstract)
|
|
as (expression)
|
|
in (scope)
|
|
using (parameter_scope)
|
|
]],Bdef)
|
|
local List = class("List")
|
|
function List:new(...)
|
|
self.items = {...}
|
|
end
|
|
B(ns,"new list",function(s,e,c)
|
|
return List()
|
|
end)
|
|
B(ns,"insert (item) into (list)",function(s,e,c)
|
|
table.insert(R(s,e.list).items,R(s,e.item),c,c)
|
|
end)
|
|
B(ns,"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(ns,"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(ns,"remove from (haystack) at (index)",function(s,e,c)
|
|
table.remove(R(s,e.list),R(s,e.index),c,c)
|
|
end)
|
|
-- Create a scope parented to the current scope as an object
|
|
B(ns,"new scope here",function(s,e,c)
|
|
local scope = Scope
|
|
scope.parent = s
|
|
return scope
|
|
end)
|
|
-- Create a scope with nothing in it as an object (weird)
|
|
B(ns,"new scope",function(s,e,c)
|
|
return Scope()
|
|
end)
|
|
-- Read a file in the current directly, more for compiling
|
|
B(ns,"read (path)",function(s,e,c)
|
|
return read(R(s,e.path,c,"read: path"))
|
|
end)
|
|
-- Take some text and interpret it into an expression
|
|
B(ns,"include (text)",function(s,e,c)
|
|
return R(s,interpret(R(s,e.text,c,"include: source")),c,"include: result")
|
|
end)
|
|
|
|
interpret([[
|
|
here {
|
|
(here ('name') is ('value'))
|
|
means
|
|
(here {
|
|
('name') is ('value')
|
|
});
|
|
|
|
(here ('abstract') means ('expression'))
|
|
means
|
|
(here {
|
|
('abstract') means ('expression')
|
|
});
|
|
|
|
(here ('abstract') means ('expression') using ('scope'))
|
|
means
|
|
(here {
|
|
('abstract') means ('expression')
|
|
} using ('scope'))
|
|
}
|
|
]])
|
|
|
|
return ns
|