git @ Cat's Eye Technologies Decoy / 9757724
Replace `nil` usage with singleton Nil table. All tests pass! Chris Pressey 1 year, 9 months ago
4 changed file(s) with 29 addition(s) and 25 deletion(s). Raw diff Collapse all Expand all
8484 In the Decoy evaluator written in Lua, the following mapping is used for the
8585 types:
8686
87 empty list nil
8887 lambda function function
88 empty list Nil (singleton table)
8989 cons cell Cons (table)
9090 string String (table)
9191 symbol Symbol (table)
9292 boolean Boolean (table)
9393 number Number (table)
9494
95 The first two are not tables like the latter ones so you cannot access
96 `.class` on them.
97
98 This is really problematic for the `nil` actually (because e.g. that's
99 what empty entries in a table are) and this needs to be replaced by
100 a `Nil` table (singleton tho).
95 The first one is not a table like the latter ones so you cannot access
96 `.class` on it. When splitting into cases, test for it first.
99 --[[ ========== EVALUATOR ========== ]]--
1010
1111 list_p = function(value)
12 if value == nil then
12 if type(value) == "function" then
13 return false
14 elseif value.class == Nil then
1315 return true
14 elseif type(value) == "function" then
15 return false
1616 elseif value.class == Cons then
1717 return list_p(value.tail())
1818 else
2121 end
2222
2323 equal_p = function(a, b)
24 if a == nil and b == nil then
24 if type(a) == "function" or type(b) == "function" then
25 return false
26 elseif a.class ~= b.class then
27 return false
28 elseif a.class == Nil then
2529 return true
26 elseif a == nil or b == nil then
27 return false
28 elseif a.class ~= b.class then
29 return false
3030 elseif a.class == String or a.class == Symbol then
3131 return a.text() == b.text()
3232 elseif a.class == Number or a.class == Boolean then
6666
6767 bind_all = function(bindings, env)
6868 local binding, value
69 while bindings ~= nil do
69 while bindings.class ~= Nil do
7070 binding = bindings.head()
7171 value = eval_expr(binding.tail().head(), env)
7272 env = bind(binding.head(), value, env)
7777
7878 eval_exprs = function(sexp, env)
7979 local exprs = {}
80 while sexp ~= nil do
80 while sexp.class ~= Nil do
8181 if sexp.class == Cons then
8282 table.insert(exprs, eval_expr(sexp.head(), env))
8383 else
8989 end
9090
9191 eval_expr = function(ast, env)
92 if ast == nil then
93 return nil
92 -- TODO: isn't this an "illegal empty application"?
93 if ast.class == Nil then
94 return Nil
9495 elseif ast.class == Cons then
9596 local head = ast.head()
9697 if head.class == Symbol then
123124 return eval_expr(body, new_env)
124125 elseif head.text() == "cond" then
125126 local branch = ast.tail()
126 while branch ~= nil do
127 while branch.class ~= Nil do
127128 local b = branch.head()
128129 local test = b.head()
129130 if test.class == Symbol and test.text() == "else" then
170171 elseif ast.class == Symbol then
171172 local value = env[ast.text()]
172173 if value == nil then
173 -- FIXME: this is not quite right as 'nil' is also a Decoy value
174174 error("Unbound symbol: " .. ast.text())
175175 end
176176 return value
2121 end
2222
2323 return fields
24 end
25
26
27 Nil = {}
28 local nil_fields = {}
29 nil_fields.class = Nil
30 Nil.new = function()
31 return nil_fields
2432 end
2533
2634
8088
8189 depict = function(sexp)
8290 local s = ""
83 if sexp == nil then
91 if type(sexp) == "function" then
92 return "<<" .. tostring(sexp) .. ">>"
93 elseif sexp.class == Nil then
8494 return "()"
85 elseif type(sexp) == "function" then
86 return "<<" .. tostring(sexp) .. ">>"
8795 elseif sexp.class == Cons then
8896 s = s .. "("
8997 s = s .. depict(sexp.head())
202202 end
203203
204204 fields.parse_expr = function()
205 local e = nil
205 local e = Nil.new()
206206 if scanner.consume("(") then
207207 local es = {}
208208 local count = 0