putting this in a git so i can post it
commit
13c5ca7783
|
@ -0,0 +1,51 @@
|
||||||
|
|
||||||
|
--[[
|
||||||
|
env is a table with
|
||||||
|
__p the parent env if there is one
|
||||||
|
__t a table of strings with the same keys as the env
|
||||||
|
entries in __t can be "special" or "macro"
|
||||||
|
if there isnt an entry it's assumed to be normal
|
||||||
|
--]]
|
||||||
|
|
||||||
|
-- todo: guard against setting / getting __t and __p ?
|
||||||
|
|
||||||
|
function e_create(env, sym, val, type, cont)
|
||||||
|
if not is_sym(sym) then
|
||||||
|
return tostr(sym) .. " is not a symbol"
|
||||||
|
end
|
||||||
|
|
||||||
|
env[sym] = none
|
||||||
|
return e_set(env, sym, val, type, cont)
|
||||||
|
end
|
||||||
|
|
||||||
|
function e_set(env, sym, val, type, cont)
|
||||||
|
if not is_sym(sym) then
|
||||||
|
return tostr(sym) .. " is not a symbol"
|
||||||
|
end
|
||||||
|
|
||||||
|
if env[sym] != nil then
|
||||||
|
env[sym] = val
|
||||||
|
env.__t[sym] = type
|
||||||
|
return cont(val, type)
|
||||||
|
elseif env.__p != nil then
|
||||||
|
return e_set(env.__p, sym, val, type, cont)
|
||||||
|
else
|
||||||
|
return tostr(sym) .. " sym unbound cant set it"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function e_get(env, sym, cont)
|
||||||
|
if not is_sym(sym) then
|
||||||
|
return tostr(sym) .. " is not a symbol"
|
||||||
|
end
|
||||||
|
|
||||||
|
if env[sym] != nil then
|
||||||
|
return cont(env[sym], env.__t[sym])
|
||||||
|
elseif env.__p != nil then
|
||||||
|
return e_get(env.__p, sym, cont)
|
||||||
|
else
|
||||||
|
return tostr(sym) .. " sym unbound cant get it"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,222 @@
|
||||||
|
-- eval.lua --
|
||||||
|
|
||||||
|
e_create(lib, "defmacro!", function(ast, env, cont)
|
||||||
|
-- (defmacro! name normal-function)
|
||||||
|
if #ast < 2 then
|
||||||
|
return "macro needs 2 args"
|
||||||
|
end
|
||||||
|
return eval(ast[2], env, function(val)
|
||||||
|
return e_create(env, ast[1], val, "macro", cont)
|
||||||
|
end)
|
||||||
|
end, "special", id)
|
||||||
|
|
||||||
|
e_create(lib, "quote", function(ast, env, cont)
|
||||||
|
return cont(deep_copy(ast[1])) -- no mutate
|
||||||
|
end, "special", id)
|
||||||
|
|
||||||
|
e_create(lib, "comma", function(ast, env, cont)
|
||||||
|
return "comma outside of backquote"
|
||||||
|
end, "special", id)
|
||||||
|
|
||||||
|
e_create(lib, "backquote", function(ast, env, cont)
|
||||||
|
if #ast < 1 then
|
||||||
|
return "backquote need arg"
|
||||||
|
end
|
||||||
|
ast = ast[1]
|
||||||
|
--todo: implement backquote, where we iterate on the quoted thing
|
||||||
|
--and look for invokations of (comma thing) in which we eval
|
||||||
|
--thing and replace comma thing with it
|
||||||
|
|
||||||
|
--todo: could i define backquote from within lisp now that i have
|
||||||
|
--macros ?????
|
||||||
|
|
||||||
|
return "nope lol oiuhre4swiuhsrgiuhjswegfoij oijerws"
|
||||||
|
end, "special", id)
|
||||||
|
|
||||||
|
e_create(lib, "set!", function(ast, env, cont)
|
||||||
|
-- (set! symbol value)
|
||||||
|
if #ast < 2 then
|
||||||
|
return "too few args for set!"
|
||||||
|
end
|
||||||
|
|
||||||
|
return eval(ast[2], env, function(val, type)
|
||||||
|
return e_set(env, ast[1], val, type, cont)
|
||||||
|
end)
|
||||||
|
end, "special", id)
|
||||||
|
|
||||||
|
e_create(lib, "def!", function(ast, env, cont)
|
||||||
|
-- (def! symbol value)
|
||||||
|
if #ast < 2 then
|
||||||
|
return "too few args for def!"
|
||||||
|
end
|
||||||
|
|
||||||
|
return eval(ast[2], env, function(val, type)
|
||||||
|
return e_create(env, ast[1], val, type, cont)
|
||||||
|
end)
|
||||||
|
end, "special", id)
|
||||||
|
|
||||||
|
e_create(lib, "let", function(ast, env, cont)
|
||||||
|
-- (let ((a 2) (b 4) (c 8)) ...)
|
||||||
|
if #ast < 2 then
|
||||||
|
return "let needs binds and body"
|
||||||
|
end
|
||||||
|
-- todo: check args to make sure it's a list of (bind expr)
|
||||||
|
if not is_tab(ast[1]) then
|
||||||
|
return "first args must be a list"
|
||||||
|
end
|
||||||
|
|
||||||
|
local new_env = { __p = env, __t = {}, }
|
||||||
|
local binds, body = ast[1], rest(ast)
|
||||||
|
|
||||||
|
local function do_body(idx, val)
|
||||||
|
if idx >= #body then
|
||||||
|
return cont(val)
|
||||||
|
end
|
||||||
|
return eval(body[idx + 1], new_env, bind(do_body, idx + 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function do_binds(idx, val)
|
||||||
|
return e_create(new_env, binds[idx][1], val, nil, function()
|
||||||
|
if idx == #binds then
|
||||||
|
return do_body(0, nil)
|
||||||
|
end
|
||||||
|
return eval(binds[idx + 1][2], env, bind(do_binds, idx + 1))
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
if #binds > 0 then
|
||||||
|
return eval(binds[1][2], env, bind(do_binds, 1))
|
||||||
|
end
|
||||||
|
return do_body(0, nil)
|
||||||
|
end, "special", id)
|
||||||
|
|
||||||
|
--todo: cond is more generic, replace this with cond ?
|
||||||
|
e_create(lib, "if", function(ast, env, cont)
|
||||||
|
-- (if cond a b)
|
||||||
|
if #ast < 2 then
|
||||||
|
return "if requires pred and body"
|
||||||
|
end
|
||||||
|
|
||||||
|
return eval(ast[1], env, function(pred)
|
||||||
|
if pred == false or pred == none then
|
||||||
|
if ast[3] then
|
||||||
|
return eval(ast[3], env, cont)
|
||||||
|
end
|
||||||
|
return cont(none)
|
||||||
|
end
|
||||||
|
return eval(ast[2], env, cont)
|
||||||
|
end)
|
||||||
|
end, "special", id)
|
||||||
|
|
||||||
|
e_create(lib, "\\", function(ast, env, cont)
|
||||||
|
-- (lam (a b c...) body...)
|
||||||
|
if #ast < 2 then
|
||||||
|
return "lam needs args and body"
|
||||||
|
end
|
||||||
|
if not is_tab(ast[1]) then
|
||||||
|
return "lam binds have to be list"
|
||||||
|
end
|
||||||
|
|
||||||
|
local binds, body = ast[1], rest(ast)
|
||||||
|
return cont(function(args, _, cont)
|
||||||
|
local lam_env = { __p = env, __t = {}, }
|
||||||
|
if #args < #binds then
|
||||||
|
return "lambda needs more args"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function do_body(idx, val)
|
||||||
|
if idx - 1 >= #body then
|
||||||
|
return cont(val)
|
||||||
|
end
|
||||||
|
return eval(body[idx], lam_env, bind(do_body, idx + 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function do_binds(idx)
|
||||||
|
if idx - 1 >= #binds then
|
||||||
|
return do_body(1, nil)
|
||||||
|
end
|
||||||
|
return e_create(lam_env, binds[idx], args[idx], nil, bind(do_binds, idx + 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
return do_binds(1)
|
||||||
|
end)
|
||||||
|
end, "special", id)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function eval_fun_call(ast, env, cont)
|
||||||
|
return eval(ast[1], env, function(fn)
|
||||||
|
if not is_fun(fn) then
|
||||||
|
return tostr(ast[1]) .. " is not a function"
|
||||||
|
end
|
||||||
|
|
||||||
|
-- todo: if we can avoid cloning args
|
||||||
|
-- and just bind args_length instead
|
||||||
|
-- this should be faster
|
||||||
|
local ast_args, zeroth = rest(ast), {}
|
||||||
|
local function eval_args(args, val)
|
||||||
|
if val != zeroth then
|
||||||
|
args = pack(unpack(args)) -- no mutate
|
||||||
|
if val == nil then
|
||||||
|
args[#args + 1] = none
|
||||||
|
else
|
||||||
|
args[#args + 1] = val
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #args == #ast_args then
|
||||||
|
return fn(args, env, cont)
|
||||||
|
end
|
||||||
|
return eval(ast_args[#args + 1], env, bind(eval_args, args))
|
||||||
|
end
|
||||||
|
|
||||||
|
return eval_args({}, zeroth)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- eval :: error : string or nil (on success)
|
||||||
|
function eval(ast, env, cont)
|
||||||
|
if ast == nil then
|
||||||
|
return "error ast is nil"
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_num(ast) or is_bool(ast) or is_str(ast)
|
||||||
|
or ast == none then
|
||||||
|
return cont(ast)
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_sym(ast) then
|
||||||
|
return e_get(env, ast, cont)
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_tab(ast) and #ast == 0 then
|
||||||
|
return "cannot eval empty list"
|
||||||
|
end
|
||||||
|
|
||||||
|
if is_tab(ast) then
|
||||||
|
if is_tab(ast[1]) then
|
||||||
|
return eval_fun_call(ast, env, cont)
|
||||||
|
end
|
||||||
|
return e_get(env, ast[1], function(val, type)
|
||||||
|
if type == "special" then
|
||||||
|
return val(rest(ast), env, cont)
|
||||||
|
elseif type == "macro" then
|
||||||
|
--todo: write macro-expand function ?
|
||||||
|
--todo: can we write this back into the ast ? (for SPEED)
|
||||||
|
return val(rest(ast), env, function(new_ast)
|
||||||
|
return eval(new_ast, env, cont)
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
return eval_fun_call(ast, env, cont)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
return "unimplemented ast: " .. tostr(ast)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,183 @@
|
||||||
|
-- lib.lua --
|
||||||
|
|
||||||
|
local lib = { __p = nil, __t = {}, }
|
||||||
|
|
||||||
|
-- todo: we can set these directly when we know that e_create works right
|
||||||
|
function id(a) return a end
|
||||||
|
|
||||||
|
e_create(lib, "call/cc", function(args, env, cont)
|
||||||
|
if not is_fun(args[1]) then
|
||||||
|
return "call/cc takes a function"
|
||||||
|
end
|
||||||
|
local function escape(args, env, _cont)
|
||||||
|
if args[1] == nil then
|
||||||
|
return cont("no value passed")
|
||||||
|
end
|
||||||
|
return cont(args[1])
|
||||||
|
end
|
||||||
|
return args[1]({escape}, env, cont)
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
e_create(lib, "do", function(args, env, cont)
|
||||||
|
return cont(args[#args])
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
-- todo: error on wrong arg type
|
||||||
|
e_create(lib, "+", function(args, env, cont)
|
||||||
|
local acc = 0
|
||||||
|
for i = 1, #args do
|
||||||
|
acc += args[i]
|
||||||
|
end
|
||||||
|
return cont(acc)
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
e_create(lib, "*", function(args, env, cont)
|
||||||
|
local acc = args[1]
|
||||||
|
for i = 2, #args do
|
||||||
|
acc *= args[i]
|
||||||
|
end
|
||||||
|
return cont(acc)
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
e_create(lib, "-", function(args, env, cont)
|
||||||
|
-- todo: return errors for bad types
|
||||||
|
-- todo: unary minus
|
||||||
|
local acc = args[1] or 0
|
||||||
|
for i = 2, #args do
|
||||||
|
acc -= args[i]
|
||||||
|
end
|
||||||
|
return cont(acc)
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
e_create(lib, "/", function(args, env, cont)
|
||||||
|
local acc = args[1] or 0
|
||||||
|
for i = 2, #args do
|
||||||
|
acc /= args[i]
|
||||||
|
end
|
||||||
|
return cont(acc)
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
e_create(lib, "even?", function(args, env, cont)
|
||||||
|
return cont(args[1] % 2 == 0)
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
e_create(lib, "?!", function(args, env, cont)
|
||||||
|
local s = ""
|
||||||
|
for i = 1, #args do
|
||||||
|
if is_str(args[i]) then
|
||||||
|
s = s .. sub(args[i], 2) .. " "
|
||||||
|
elseif args[i] == none then
|
||||||
|
s = s .. "[none] "
|
||||||
|
else
|
||||||
|
s = s .. tostr(args[i]) .. " "
|
||||||
|
end
|
||||||
|
end
|
||||||
|
print(s)
|
||||||
|
return cont(";" .. s)
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
e_create(lib, "<", function(args, env, cont)
|
||||||
|
local acc = -32768 -- lowest pico-8 value i think
|
||||||
|
for i = 1, #args do
|
||||||
|
if not (args[i] > acc) then
|
||||||
|
return cont(false)
|
||||||
|
end
|
||||||
|
acc = args[i]
|
||||||
|
end
|
||||||
|
return cont(true)
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
e_create(lib, "=", function(args, env, cont)
|
||||||
|
local acc = args[1]
|
||||||
|
for i = 2, #args do
|
||||||
|
if args[i] != acc then
|
||||||
|
return cont(false)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return cont(true)
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
e_create(lib, "list", function(args, env, cont)
|
||||||
|
return cont(args)
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
e_create(lib, "[]", function(args, env, cont)
|
||||||
|
if not is_tab(args[1]) then
|
||||||
|
return "[] 1st arg must be table"
|
||||||
|
end
|
||||||
|
return cont(args[1][args[2]])
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
e_create(lib, "len", function(args, env, cont)
|
||||||
|
if not is_tab(args[1]) then
|
||||||
|
return "len arg must be table"
|
||||||
|
end
|
||||||
|
return cont(#(args[1]))
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
e_create(lib, "join", function(args, env, cont)
|
||||||
|
local new, len = {}, 0
|
||||||
|
for i = 1, #args do
|
||||||
|
local arg = args[i]
|
||||||
|
if not is_tab(arg) then
|
||||||
|
len += 1
|
||||||
|
new[len] = arg
|
||||||
|
goto next
|
||||||
|
end
|
||||||
|
for j = 1, #arg do
|
||||||
|
new[len + j] = arg[j]
|
||||||
|
end
|
||||||
|
len += #arg
|
||||||
|
::next::
|
||||||
|
end
|
||||||
|
return cont(new)
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
e_create(lib, "fold", function(args, env, cont)
|
||||||
|
if not is_fun(args[1]) then
|
||||||
|
return "1st arg should be func"
|
||||||
|
elseif args[2] == nil then
|
||||||
|
return "2nd arg should be start val"
|
||||||
|
elseif not is_tab(args[3]) then
|
||||||
|
return "3rd arg should be table"
|
||||||
|
end
|
||||||
|
local fn, acc, list = args[1], args[2], args[3]
|
||||||
|
local len = #list
|
||||||
|
if len < 1 then
|
||||||
|
return "cant fold empty list"
|
||||||
|
end
|
||||||
|
|
||||||
|
local function do_fold(idx, val)
|
||||||
|
if idx == len then
|
||||||
|
return cont(val)
|
||||||
|
end
|
||||||
|
return fn({val, list[idx + 1]}, env, bind(do_fold, idx + 1))
|
||||||
|
end
|
||||||
|
|
||||||
|
return fn({acc, list[1]}, env, bind(do_fold, 1))
|
||||||
|
end, nil, id)
|
||||||
|
|
||||||
|
function wrap_fn(fn, name)
|
||||||
|
e_create(lib, name, function(args, env, cont)
|
||||||
|
return cont(fn(unpack(args)))
|
||||||
|
end, nil, id)
|
||||||
|
end
|
||||||
|
|
||||||
|
for i = 1, #wraps do
|
||||||
|
-- todo: should i / do i need to prefix these ??
|
||||||
|
-- todo: post these with ! since almost all of them can mutate
|
||||||
|
wrap_fn(wraps[i].v, wraps[i].k)
|
||||||
|
end
|
||||||
|
wraps = nil -- let there be garbage collection
|
||||||
|
|
||||||
|
for k, v in pairs({
|
||||||
|
["sym?"] = is_sym,
|
||||||
|
["num?"] = is_num,
|
||||||
|
["fun?"] = is_fun,
|
||||||
|
["tab?"] = is_tab,
|
||||||
|
["str?"] = is_str,
|
||||||
|
["bool?"] = is_bool,
|
||||||
|
}) do
|
||||||
|
wrap_fn(v, k)
|
||||||
|
end
|
||||||
|
|
|
@ -0,0 +1,580 @@
|
||||||
|
pico-8 cartridge // http://www.pico-8.com
|
||||||
|
version 32
|
||||||
|
__lua__
|
||||||
|
-- utils / globals
|
||||||
|
local none = {}
|
||||||
|
|
||||||
|
--have to do this before i make
|
||||||
|
--any functions
|
||||||
|
local wraps = {}
|
||||||
|
for k,v in pairs(_ENV) do
|
||||||
|
if type(v)=="function" then
|
||||||
|
wraps[#wraps + 1]={k=k, v=v,}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_sym(s)
|
||||||
|
return type(s) == "string"
|
||||||
|
and sub(s,1,1) != ";"
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_num(n)
|
||||||
|
return type(n) == "number"
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_fun(f)
|
||||||
|
return type(f) == "function"
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_tab(t)
|
||||||
|
return type(t) == "table"
|
||||||
|
and t != none
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_str(s)
|
||||||
|
return type(s) == "string"
|
||||||
|
and sub(s,1,1) == ";"
|
||||||
|
end
|
||||||
|
|
||||||
|
function is_bool(b)
|
||||||
|
return type(b) == "boolean"
|
||||||
|
end
|
||||||
|
|
||||||
|
--todo:
|
||||||
|
--can this be made faster ?
|
||||||
|
function rest(t)
|
||||||
|
local function r_1(fst, ...)
|
||||||
|
return {...}
|
||||||
|
end
|
||||||
|
return r_1(unpack(t))
|
||||||
|
end
|
||||||
|
|
||||||
|
function deep_copy(v)
|
||||||
|
if not is_tab(v) then
|
||||||
|
return v
|
||||||
|
end
|
||||||
|
|
||||||
|
local c = {}
|
||||||
|
for key = 1, #v do
|
||||||
|
--for key in pairs(v) do
|
||||||
|
c[key] = deep_copy(v[key])
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
--todo: this is limitted to 2
|
||||||
|
--args, it's kinda missleading
|
||||||
|
--ig, tho i doubt anyone else
|
||||||
|
--will be using this func
|
||||||
|
|
||||||
|
--todo: see if this needs to /
|
||||||
|
--can be spead up
|
||||||
|
function bind(func, ...)
|
||||||
|
local args = {...}
|
||||||
|
|
||||||
|
local function copy(t)
|
||||||
|
return pack(unpack(t))
|
||||||
|
end
|
||||||
|
|
||||||
|
return function(a, b)
|
||||||
|
local args_2 = copy(args)
|
||||||
|
args_2[#args + 1] = a
|
||||||
|
args_2[#args + 2] = b
|
||||||
|
return func(unpack(args_2))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function list_tostr(l, s)
|
||||||
|
if l == none then
|
||||||
|
return s .. "none"
|
||||||
|
end
|
||||||
|
if type(l)=="table" then
|
||||||
|
s = s .. "("
|
||||||
|
for i = 1, #l do
|
||||||
|
if(i > 1) s = s .. " "
|
||||||
|
s = list_tostr(l[i], s)
|
||||||
|
end
|
||||||
|
s = s .. ")"
|
||||||
|
return s
|
||||||
|
end
|
||||||
|
if is_str(l) then
|
||||||
|
return
|
||||||
|
s.."\""..sub(l,2).."\""
|
||||||
|
end
|
||||||
|
return s .. tostr(l)
|
||||||
|
end
|
||||||
|
|
||||||
|
function chr_size(c)
|
||||||
|
return ord(c) < 128 and 4 or 8
|
||||||
|
end
|
||||||
|
|
||||||
|
function replace(s, a, b)
|
||||||
|
local r = ""
|
||||||
|
for i = 1, #s do
|
||||||
|
local c = sub(s, i, i)
|
||||||
|
if c == a then
|
||||||
|
c = b
|
||||||
|
end
|
||||||
|
r = r .. c
|
||||||
|
end
|
||||||
|
return r
|
||||||
|
end
|
||||||
|
|
||||||
|
-->8
|
||||||
|
-- tokenizer
|
||||||
|
|
||||||
|
--[[ todo:
|
||||||
|
generisize token_str + com ?
|
||||||
|
--]]
|
||||||
|
|
||||||
|
--::tok,rst,type
|
||||||
|
--[[
|
||||||
|
"pun" = puncuation
|
||||||
|
"ws" = whitespace
|
||||||
|
"sym" = symbol
|
||||||
|
"num" = number
|
||||||
|
"end" = end of input
|
||||||
|
"str" = string
|
||||||
|
"com" = comment
|
||||||
|
--]]
|
||||||
|
function token_str(s, hk)
|
||||||
|
for i = 2, #s do
|
||||||
|
if(hk) hk(sub(s,i,i))
|
||||||
|
if sub(s,i,i) == "\"" then
|
||||||
|
return sub(s, 1, i),
|
||||||
|
sub(s,i + 1), "str"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return s, "", "str" --no end
|
||||||
|
end
|
||||||
|
|
||||||
|
function token_com(s, hk)
|
||||||
|
for i = 2, #s do
|
||||||
|
if(hk) hk(sub(s,i,i))
|
||||||
|
if sub(s,i,i) == "\n" then
|
||||||
|
return sub(s, 1, i),
|
||||||
|
sub(s,i + 1), "com"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return s, "", "com" --eof
|
||||||
|
end
|
||||||
|
|
||||||
|
function token_1(s, hk)
|
||||||
|
local fst,rst = sub(s,1,1),
|
||||||
|
sub(s,2)
|
||||||
|
|
||||||
|
if(hk) hk(fst)
|
||||||
|
|
||||||
|
if(s=="")return "","","end"
|
||||||
|
|
||||||
|
if fst == "\"" then
|
||||||
|
return token_str(s, hk)
|
||||||
|
end
|
||||||
|
if fst == ";" then
|
||||||
|
return token_com(s, hk)
|
||||||
|
end
|
||||||
|
|
||||||
|
if fst == " "
|
||||||
|
or fst == "\n"
|
||||||
|
or fst == "\t" then
|
||||||
|
local t,r,tp = token_1(rst,hk)
|
||||||
|
if tp == "ws" then
|
||||||
|
return fst..t, r, "ws"
|
||||||
|
end
|
||||||
|
return fst, rst, "ws"
|
||||||
|
end
|
||||||
|
|
||||||
|
if fst == "("
|
||||||
|
or fst == ")"
|
||||||
|
or fst == "'"
|
||||||
|
or fst == "`"
|
||||||
|
or fst == ","
|
||||||
|
or fst == "@" then
|
||||||
|
return fst, rst, "pun"
|
||||||
|
end
|
||||||
|
|
||||||
|
local t,r,tp = token_1(rst,hk)
|
||||||
|
if tp == "sym" then
|
||||||
|
return fst..t, r, "sym"
|
||||||
|
end
|
||||||
|
return fst,rst,"sym"
|
||||||
|
end
|
||||||
|
|
||||||
|
function token(s, hk)
|
||||||
|
local t,r,tp = token_1(s, hk)
|
||||||
|
|
||||||
|
if tonum(t) != nil then
|
||||||
|
return tonum(t),r,"num"
|
||||||
|
end
|
||||||
|
|
||||||
|
return t,r,tp
|
||||||
|
end
|
||||||
|
|
||||||
|
-->8
|
||||||
|
-- parser
|
||||||
|
|
||||||
|
--[[ todo:
|
||||||
|
collect line numbers ?
|
||||||
|
--]]
|
||||||
|
|
||||||
|
function parse(src)
|
||||||
|
local t, rst, tp = token(src)
|
||||||
|
|
||||||
|
if tp=="ws"
|
||||||
|
or tp=="com" then
|
||||||
|
return parse(rst) end
|
||||||
|
|
||||||
|
if t == "'" then
|
||||||
|
t, rst, tp = parse(rst)
|
||||||
|
return {"quote",t}, rst, tp
|
||||||
|
end
|
||||||
|
if t == "`" then
|
||||||
|
t, rst, tp = parse(rst)
|
||||||
|
return {"backquote",t}, rst, tp
|
||||||
|
end
|
||||||
|
if t == "," then
|
||||||
|
t, rst, tp = parse(rst)
|
||||||
|
return {"comma",t}, rst, tp
|
||||||
|
end
|
||||||
|
|
||||||
|
if tp == "str" then
|
||||||
|
return ";" .. sub(t,2,#t-1),
|
||||||
|
rst, tp
|
||||||
|
end
|
||||||
|
|
||||||
|
if t == "(" then
|
||||||
|
local list = {}
|
||||||
|
while true do
|
||||||
|
t, rst, tp = parse(rst)
|
||||||
|
if(t == ")") break
|
||||||
|
if tp == "end" then
|
||||||
|
print("err, unclosed paren")
|
||||||
|
break
|
||||||
|
end
|
||||||
|
add(list, t)
|
||||||
|
end
|
||||||
|
return list, rst, tp
|
||||||
|
end
|
||||||
|
|
||||||
|
return t, rst, tp
|
||||||
|
end
|
||||||
|
|
||||||
|
-->8
|
||||||
|
-- env
|
||||||
|
#include env.lua
|
||||||
|
|
||||||
|
-->8
|
||||||
|
-- lib
|
||||||
|
#include lib.lua
|
||||||
|
|
||||||
|
|
||||||
|
-->8
|
||||||
|
-- eval
|
||||||
|
#include eval.lua
|
||||||
|
|
||||||
|
eval(parse([[
|
||||||
|
(do
|
||||||
|
(def! push (\ (l a)
|
||||||
|
(join l (list a))))
|
||||||
|
|
||||||
|
(def! bq-fold (\ (acc ast)
|
||||||
|
(push acc
|
||||||
|
(if (tab? ast)
|
||||||
|
(if (= ([] ast 1) 'comma)
|
||||||
|
([] ast 2)
|
||||||
|
(fold bq-fold '(list) ast))
|
||||||
|
(list 'quote ast)))))
|
||||||
|
|
||||||
|
(defmacro! backquote (\ (ast)
|
||||||
|
(fold bq-fold '(list) ast))))
|
||||||
|
]]), lib, function(val)
|
||||||
|
--
|
||||||
|
end)
|
||||||
|
|
||||||
|
-->8
|
||||||
|
cls()
|
||||||
|
lisp_src = [[
|
||||||
|
|
||||||
|
;; edit example
|
||||||
|
(?! 69 "steamed hams") ;comment
|
||||||
|
(do
|
||||||
|
|
||||||
|
(def! add-or-sub (\ (func)
|
||||||
|
(func 10 18)))
|
||||||
|
|
||||||
|
(add-or-sub (\ (a b)
|
||||||
|
(?! a b)
|
||||||
|
(= a b))))
|
||||||
|
|
||||||
|
(do
|
||||||
|
(def! add-or-sub (\ (func)
|
||||||
|
(func 10 18)))
|
||||||
|
|
||||||
|
(add-or-sub (\ (a b)
|
||||||
|
(?! a b)
|
||||||
|
|
||||||
|
(= a b))))
|
||||||
|
|
||||||
|
(do
|
||||||
|
|
||||||
|
(def! farts (list 69 420 666))
|
||||||
|
|
||||||
|
(def! combo (\ (acc l)
|
||||||
|
(?! "combo:" acc l)
|
||||||
|
(+ acc l)))
|
||||||
|
|
||||||
|
(fold combo 0 farts))
|
||||||
|
|
||||||
|
(do
|
||||||
|
(def! thing 1)
|
||||||
|
(def! adder (\ (num)
|
||||||
|
|
||||||
|
; unamed second function
|
||||||
|
(\ (a)
|
||||||
|
|
||||||
|
; unamed third function
|
||||||
|
(\ (b)
|
||||||
|
(+ a b num)))
|
||||||
|
))
|
||||||
|
|
||||||
|
(def! crap (adder 4))
|
||||||
|
(def! dung (crap 2))
|
||||||
|
(dung 1)
|
||||||
|
;((adder 4) 2) -> dung
|
||||||
|
|
||||||
|
(dung 63))
|
||||||
|
|
||||||
|
(do
|
||||||
|
(def! cownter (let ((c 0))
|
||||||
|
(\ (a)
|
||||||
|
(set! c (+ c a))
|
||||||
|
(?! c))))
|
||||||
|
|
||||||
|
(cownter 1)
|
||||||
|
(cownter 5)
|
||||||
|
(cownter 2))
|
||||||
|
|
||||||
|
(do
|
||||||
|
|
||||||
|
(def! uwu (\ (x y)
|
||||||
|
(set! x (- 0 x))
|
||||||
|
(set! y (- 0 y))
|
||||||
|
(camera x y)
|
||||||
|
|
||||||
|
|
||||||
|
(color 5)
|
||||||
|
(line 10 98 10 88)
|
||||||
|
(line 10 98 50 98)
|
||||||
|
(line 50 88 50 98)
|
||||||
|
(line 50 88 40 88)
|
||||||
|
(line 20 88 10 88)
|
||||||
|
(line 20 88 20 60)
|
||||||
|
(line 40 88 40 60)
|
||||||
|
(line 40 60 20 60)
|
||||||
|
(line 40 70 20 70)
|
||||||
|
(line 30 65 30 60)))
|
||||||
|
|
||||||
|
(cls 1)
|
||||||
|
(uwu 50 0)
|
||||||
|
(uwu 0 0)
|
||||||
|
(uwu 25 -48))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
(do
|
||||||
|
(defmacro! bee
|
||||||
|
(let ((bees 0)) (\ (val)
|
||||||
|
(set! bees (+ 1 bees))
|
||||||
|
`(?! ,bees ,val))))
|
||||||
|
|
||||||
|
(def! a 6)
|
||||||
|
(def! b "trees")
|
||||||
|
|
||||||
|
(bee b)
|
||||||
|
(bee "yeet")
|
||||||
|
(bee ((\() "yeet")))
|
||||||
|
(bee "tank")
|
||||||
|
(bee "yank")
|
||||||
|
(bee "gank"))
|
||||||
|
|
||||||
|
|
||||||
|
(def! draw (let ()
|
||||||
|
(def! l (\ (c)
|
||||||
|
(def! x (rnd 128))
|
||||||
|
(def! y (rnd 128))
|
||||||
|
(def! u (rnd 128))
|
||||||
|
(def! v (rnd 128))
|
||||||
|
(line x y u v c)
|
||||||
|
(spr 1 (- x 4) (- y 4))
|
||||||
|
(circ u v 4)))
|
||||||
|
(def! jump 0)
|
||||||
|
(\ ()
|
||||||
|
(call/cc (\ (c)
|
||||||
|
(set! jump c)))
|
||||||
|
(cls 15)
|
||||||
|
(cursor 1 1)
|
||||||
|
(color 0)
|
||||||
|
(?! (stat 0))
|
||||||
|
(map 0 0)
|
||||||
|
(if (< 0 (btn))
|
||||||
|
(?! "hi"))
|
||||||
|
(l 1) (l 0)
|
||||||
|
(l 1) (l 0)
|
||||||
|
(l 1) (l 0)
|
||||||
|
(l 1) (l 0))))
|
||||||
|
]]
|
||||||
|
lisp_src = replace(lisp_src,
|
||||||
|
"\t", " ")
|
||||||
|
list,rst = parse(lisp_src)
|
||||||
|
|
||||||
|
print(list_tostr(list, ""))
|
||||||
|
|
||||||
|
local enviro = {
|
||||||
|
__p = lib,
|
||||||
|
__t = {},
|
||||||
|
["true"] = true,
|
||||||
|
["false"] = false,
|
||||||
|
["none"] = none,
|
||||||
|
}
|
||||||
|
|
||||||
|
local err = eval(list, enviro,
|
||||||
|
function(v)
|
||||||
|
print(list_tostr(v, "-> "))
|
||||||
|
end)
|
||||||
|
if(err) print("err: " .. tostr(err))
|
||||||
|
|
||||||
|
-->8
|
||||||
|
-- edit
|
||||||
|
|
||||||
|
--[[
|
||||||
|
todo:
|
||||||
|
--]]
|
||||||
|
|
||||||
|
function draw_line(s, y)
|
||||||
|
if y > 128 or y < -6 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local x = 0
|
||||||
|
local cols = {
|
||||||
|
str=3, com=13, num=12, sym=6,
|
||||||
|
bound=14, lib=11,
|
||||||
|
}
|
||||||
|
|
||||||
|
local t, rst, tp = token(s)
|
||||||
|
while tp != "end" do
|
||||||
|
color(7)
|
||||||
|
if cols[tp] then
|
||||||
|
color(cols[tp])
|
||||||
|
end
|
||||||
|
if lib[t] then
|
||||||
|
color(cols.lib)
|
||||||
|
end
|
||||||
|
if enviro[t] then
|
||||||
|
color(cols.bound)
|
||||||
|
end
|
||||||
|
|
||||||
|
x = print(t, x, y)
|
||||||
|
t, rst, tp = token(rst)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function draw_code(y)
|
||||||
|
cls(0)
|
||||||
|
|
||||||
|
local src=split(lisp_src, "\n")
|
||||||
|
|
||||||
|
for i = 1, #src do
|
||||||
|
draw_line(src[i], y+ i * 6 - 6)
|
||||||
|
--print(src[i])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-->8
|
||||||
|
-- draw
|
||||||
|
|
||||||
|
if enviro.draw then
|
||||||
|
function _draw()
|
||||||
|
local err = enviro.draw({},
|
||||||
|
enviro, function(v)end)
|
||||||
|
if err then
|
||||||
|
color(7)
|
||||||
|
?err
|
||||||
|
stop()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local scroll = 0
|
||||||
|
function _draw()
|
||||||
|
draw_code(scroll)
|
||||||
|
if(btn(⬆️))scroll += 6
|
||||||
|
if(btn(⬇️))scroll -= 6
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
__gfx__
|
||||||
|
00000000008888000033330000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000002200000000220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00700700002200000000220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00077000088aa8000036633000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00077000a88aa8a00636633600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00700700a88aa8a00636633600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000088888000033333000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000080080000003003000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
03333330333330003333330300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
33333333333333333333333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
33333333333333333332233300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
03332223332223233333333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
03333332333233333333232300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
33333333333332333333233300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
33332333323333333333333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
33333233322333333333333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
03333323333333333333333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
03333333333333333332333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
33233333333222332333333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
33333333223333333333333000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
32323233233333333332333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
33333333333322323333333000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
33323333333332233333333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
00333333333333333332333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
33333333333333333322333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
33333333333333333333333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
33333333332332333333323300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
32323322223333333332333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
33223333323333233233333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
33333333333333333332333300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
03332333333333333333333000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
30333303330033300333333000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
__map__
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000002021220000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000003031320000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000004041420000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000202121212200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||||
|
0000000000404141414200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
Loading…
Reference in New Issue