af3fc57
Branches > main > af3fc57 > files / org / faddle / lang / eval.lua
commit EVERYTHING I can never remeber to commit shit
Commit: af3fc57c2ca99cbb43155891d3b956146cebb35f
Parent: 5e1b1bd
7 changed files:
org/faddle.fdl view file
@@ -1,4 +1,8 @@ (module :org.faddle) (def __rt (require :org.faddle.lang.rt))-(def plus (fn [x y] (__rt:plus x y)))+; TODO remove rt from packages?+; Or just have some notion of private modules in their own table+(def plus __rt:plus)+; . is a placeholder for nothing, so it can be the result of calling a function that doesn't return anything+(def . ((fn [])))org/faddle/lang/compile.lua view file
@@ -1,42 +1,92 @@ local LIST = require("org.faddle.lang.list") local is_list = LIST.is_list-local cons = LIST.cons local count = LIST.count local first = LIST.first local rest = LIST.rest-local apply = LIST.apply-local empty = LIST.empty local symbol = require("org.faddle.lang.symbol") local is_symbol = symbol.is_symbol local intern = symbol.intern+local munge = symbol.munge+local module = symbol.module++local lisp_print = require("org.faddle.lang.print").print -- Still bad :p local FN = intern("fn")+local LET = intern("let")+local DO = intern("do") local compile -local function compile_fn(form)+local gensym_number = 0+local function gensym()+ gensym_number = gensym_number + 1+ return "G__" .. gensym_number+end++local function ret(statement)+ return statement and "return " or ""+end++local function compile_fn(form, statement) local args = rest(form) local fn_args = first(args) local body = rest(args) assert(#fn_args == 0) assert(count(body) == 1)- return "function() return " .. compile(first(body)) .. " end"+ return ret(statement) .. "function() " .. compile(first(body), true) .. " end"+end++-- If I'm just using the same lexical stuff as Lua, how do builtin Lua modules work?+-- In Lua you can just say `io`, but I'd like to wrap these libraries in something like `lua.io`+-- to make it clear where they're coming from...+-- Not sure how I could do that+-- I also want to check locals and fail during compilation if you reference a non-existent local+-- Well `io` is just something you'd have to import in Faddle, since the compiler can just look at what+-- modules have been imported, and `io` won't be one of them.+-- So then `lua.io` or whatever can be defined by Faddle, and map to `io`.+local function compile_let(form, statement)+ local args = rest(form)+ local bindings = first(args)+ local body = rest(args)+ assert(type(bindings) == "table" and #bindings % 2 == 0, "Let requires an even number of binding forms")+ assert(#bindings == 2)+ assert(count(body) == 1)+ local sym = bindings[1]+ local binding = bindings[2]+ if statement then+ return "local " .. munge(sym) .. "=" .. compile(binding) .. ";" .. compile(first(body), true)+ else+ return "return (function()" .. compile_let(form, not statement) .. " end)()"+ end end --- Returns a string of Lua source code from the form-compile = function(form)+-- TODO needs to compile returns vs not returns, I think...+-- So this may need to encode the context of whether this is in an expression or statement context+compile = function(form, statement) if is_list(form) then- if count(form) == 0 then return "__rt.list()" end- if first(form) == FN then return compile_fn(form) end+ -- if count(form) == 0 then return "__rt.list()" end+ if count(form) == 0 then return ret(statement) .. "require('org.faddle').list()" end+ -- If it's a literal number or string you can compile directly to a lookup+ -- Symbols still need to be checked whether they resolve to a string or number though+ if first(form) == FN then return compile_fn(form, statement) end+ if first(form) == LET then return compile_let(form, statement) end+ print(lisp_print(form))+ assert(count(form) == 1, "uhhh")+ return ret(statement) .. compile(first(form)) .. "()" -- macro expansion :D- -- rt functions?+ -- core functions+ -- vars that are local, however you're supposed to know that :p+ elseif is_symbol(form) then+ assert(not module(form), "can't compile symbols with modules yet :(")+ return ret(statement) .. munge(form) else local t = type(form) if t == "number" or t == "nil" or t == "boolean" then- return tostring(form)+ return ret(statement) .. tostring(form) elseif t == "string" then- return string.format("%q", form)+ return ret(statement) .. string.format("%q", form) else error("Cannot compile form of type '" .. t .. "'") end@@ -46,7 +96,9 @@ local loadfn = loadstring or load local function execute(lua_source, chunk_name)- local chunk, err = loadfn("local __rt = require('org.faddle.lang.rt');return " .. lua_source, chunk_name)+ -- Really, needs to just have all of the std library loaded :p+ print(lua_source)+ local chunk, err = loadfn("local __rt = require('org.faddle.lang.rt');" .. lua_source, chunk_name) if not chunk then error(err) elseorg/faddle/lang/eval.lua view file
@@ -59,6 +59,7 @@ local MODULE = intern("module") local QUOTE = intern("quote") local FN = intern("fn")+local LET = intern("let") -- Should eventually be in core/boot ofc they're just here now so I can test functions before figuring out modules local temp_vars =@@ -81,16 +82,22 @@ -- Should fail if you're looking up a non-existent local, but not otherwise -- There's currently no way to tell the difference between an undefined local and a nil local return temp_vars[sym] or modules[env.current_module][munge(sym)]++ -- This is always looking up a global+ -- So this is either a symbol with a module or a simple symbol that's been referred...+ -- If the sym refers to a macro, error saying you can't do that end --- Not quite sure how to do this...--- Do tables need to be compiled into Lua?--- Not simple ones, but others may benefit, I'm not sure. local function eval_table(t, env) local ret = {} for k, v in pairs(t) do -- Could end up with holes, but that's the user's fault- ret[eval(k, env)] = eval(v, env)+ local eval_k = eval(k, env)+ if eval_k == nil then+ error("Table key must be a value, but nothing was provided")+ else+ ret[eval_k] = eval(v, env)+ end end return ret end@@ -132,7 +139,8 @@ if f == QUOTE then return second(form) end if f == MODULE then return module(second(form), env) end if f == DEF then return def(second(form), rest(rest(form)), env) end- if f == FN then return execute(compile(form), "eval_fn") end+ if f == FN then return execute(compile(form, true), "eval_fn") end+ if f == LET then return execute(compile(form, true), "eval_let") end form = map_eval(form, env) return call(first(form), rest(form))org/faddle/lang/read.lua view file
@@ -26,7 +26,7 @@ local function read(s) local pos = 1- -- If #s returns the number of bytes this would be wrong+ -- TODO If #s returns the number of bytes this would be wrong? local len = #s local read_valueorg/faddle/lang/rt.lua view file
@@ -2,5 +2,7 @@ local LIST = require("org.faddle.lang.list") local list = LIST.list+local type = type -return {list = list}+return {list = list,+ type = type}org/faddle/lang/symbol.lua view file
@@ -30,7 +30,7 @@ local function name(sym) if is_symbol(sym) then- return sym[NAME]+ return assert(sym[NAME]) else error("Cannot get the symbol name of type " .. type(sym), 2) end@@ -40,7 +40,7 @@ if is_symbol(sym) then return sym[MODULE] else- error("Cannot get the symbol table of type " .. type(sym), 2)+ error("Cannot get the symbol module of type " .. type(sym), 2) end end test.lua view file
@@ -8,7 +8,7 @@ local apply = LIST.apply local lisp_print = require("org.faddle.lang.print").print --- Returns whether 2 objects are structurally equal at the point of calling, even if they are mutable+--- Returns whether 2 objects are structurally equal at the point of calling, even if they are mutable (i.e. tables) local function eq(x,y) if x == y then return true end if is_list(x) and is_list(y) then@@ -143,4 +143,18 @@ teq(read_eval("(plus)"), 0) teq(read_eval("(plus 1 2 3)"), 6) +-- local compiler = require("org.faddle.lang.compile")+-- local execute = compiler.execute+-- local compile = compiler.compile++teq(read_eval("(let [x 42] 42)"), 42)+teq(read_eval("((fn [] 42))"), 42)+teq(read_eval("(let [f (fn [] 42)] (f))"), 42)++-- Later+-- teq(read_eval("(let [x 1 y 2] [x y])"), {1, 2})+-- teq(read_eval("((fn [x] x) :abc)"), :abc)++---+ print("Yay it worked")