Introduce is_a() and stop checking `class` field explicitly.
Chris Pressey
1 year, 8 months ago
132 | 132 | |
133 | 133 | * Interned strings and modules? Hash-consing, even? |
134 | 134 | * Tracebacks, or at least line/column, or at least "in function..." |
135 | * isa instead of .class == | |
136 | 135 | |
137 | 136 | ### Compiler |
138 | 137 | |
152 | 151 | an "implementation module" written in language X will be used when |
153 | 152 | the code is compiled to X. But the module defines the semantics. |
154 | 153 | |
154 | ### Desugar | |
155 | ||
156 | * cond -> nested if's | |
157 | * let* -> nested let1's | |
158 | ||
155 | 159 | ### Forms |
156 | 160 | |
157 | 161 | * `if` |
30 | 30 | |
31 | 31 | local emit_symbols = function(sexp) |
32 | 32 | while sexp ~= Nil do |
33 | if sexp.class == Cons then | |
33 | if is_a(sexp, Cons) then | |
34 | 34 | emit_symbol(sexp.head()) |
35 | 35 | if sexp.tail() ~= Nil then |
36 | 36 | emit(",") |
43 | 43 | end |
44 | 44 | |
45 | 45 | fields.compile_expr = function(ast) |
46 | if ast.class == Cons then | |
46 | if is_a(ast, Cons) then | |
47 | 47 | local head = ast.head() |
48 | if head.class == Symbol then | |
48 | if is_a(head, Symbol) then | |
49 | 49 | if head.text() == "quote" then |
50 | 50 | fields.compile_quote(ast.tail()) |
51 | 51 | elseif head.text() == "let*" then |
64 | 64 | else |
65 | 65 | error("Can't compile application not in A-normal form: " .. depict(ast)) |
66 | 66 | end |
67 | elseif ast.class == Symbol then | |
67 | elseif is_a(ast, Symbol) then | |
68 | 68 | fields.compile_lookup(ast) |
69 | elseif ast.class == String or ast.class == Number or ast.class == Boolean then | |
69 | elseif is_a(ast, String) or is_a(ast, Number) or is_a(ast, Boolean) then | |
70 | 70 | fields.compile_literal(ast) |
71 | 71 | else |
72 | 72 | error("Unsupported form for compilation: " .. depict(ast)) |
75 | 75 | |
76 | 76 | fields.compile_exprs = function(sexp, inter) |
77 | 77 | while sexp ~= Nil do |
78 | if sexp.class == Cons then | |
78 | if is_a(sexp, Cons) then | |
79 | 79 | fields.compile_expr(sexp.head()) |
80 | 80 | if sexp.tail() ~= Nil then |
81 | 81 | inter() |
115 | 115 | |
116 | 116 | fields.compile_bindings = function(sexp) |
117 | 117 | while sexp ~= Nil do |
118 | if sexp.class == Cons then | |
118 | if is_a(sexp, Cons) then | |
119 | 119 | local pair = sexp.head() |
120 | 120 | debug("compiler", depict(pair)) |
121 | 121 | fields.compile_binding(pair.head(), pair.tail().head()) |
36 | 36 | |
37 | 37 | bind_all = function(bindings, env) |
38 | 38 | local binding, value |
39 | while bindings.class ~= Nil do | |
39 | while bindings ~= Nil do | |
40 | 40 | binding = bindings.head() |
41 | 41 | value = eval_expr(binding.tail().head(), env) |
42 | 42 | env = bind(binding.head(), value, env) |
47 | 47 | |
48 | 48 | eval_exprs = function(sexp, env) |
49 | 49 | local exprs = {} |
50 | while sexp.class ~= Nil do | |
51 | if sexp.class == Cons then | |
50 | while sexp ~= Nil do | |
51 | if is_a(sexp, Cons) then | |
52 | 52 | table.insert(exprs, eval_expr(sexp.head(), env)) |
53 | 53 | else |
54 | 54 | error("assertion failed: not a Cons") |
59 | 59 | end |
60 | 60 | |
61 | 61 | eval_expr = function(ast, env) |
62 | if ast.class == Cons then | |
62 | if is_a(ast, Cons) then | |
63 | 63 | local head = ast.head() |
64 | if head.class == Symbol then | |
64 | if is_a(head, Symbol) then | |
65 | 65 | if head.text() == "quote" then |
66 | 66 | return ast.tail().head() |
67 | 67 | elseif head.text() == "let*" then |
79 | 79 | while branch.class ~= Nil do |
80 | 80 | local b = branch.head() |
81 | 81 | local test = b.head() |
82 | if test.class == Symbol and test.text() == "else" then | |
82 | if is_a(test, Symbol) and test.text() == "else" then | |
83 | 83 | return eval_expr(b.tail().head(), env) |
84 | 84 | else |
85 | 85 | local result = eval_expr(test, env) |
86 | if result.class == Boolean and result.value() then | |
86 | if is_a(result, Boolean) and result.value() then | |
87 | 87 | return eval_expr(b.tail().head(), env) |
88 | 88 | end |
89 | 89 | end |
116 | 116 | fn = eval_expr(ast.head(), env) |
117 | 117 | return fn(eval_exprs(ast.tail(), env)) |
118 | 118 | end |
119 | elseif ast.class == Symbol then | |
119 | elseif is_a(ast, Symbol) then | |
120 | 120 | local value = env[ast.text()] |
121 | 121 | if value == nil then |
122 | 122 | error("Unbound symbol: " .. ast.text()) |
123 | 123 | end |
124 | 124 | return value |
125 | elseif ast.class == String or ast.class == Number or ast.class == Boolean then | |
125 | elseif is_a(ast, String) or is_a(ast, Number) or is_a(ast, Boolean) then | |
126 | 126 | return ast |
127 | 127 | else |
128 | 128 | error("Unsupported form for evaluation: " .. depict(ast)) |
80 | 80 | local s = "" |
81 | 81 | if type(sexp) == "function" then |
82 | 82 | return "<<" .. tostring(sexp) .. ">>" |
83 | elseif sexp.class == Nil then | |
83 | elseif sexp == Nil then | |
84 | 84 | return "()" |
85 | elseif sexp.class == Cons then | |
85 | elseif is_a(sexp, Cons) then | |
86 | 86 | s = s .. "(" |
87 | 87 | s = s .. depict(sexp.head()) |
88 | 88 | sexp = sexp.tail() |
89 | 89 | local done = false |
90 | 90 | while not done do |
91 | if sexp.class == Cons then | |
91 | if is_a(sexp, Cons) then | |
92 | 92 | s = s .. " " |
93 | 93 | s = s .. depict(sexp.head()) |
94 | 94 | sexp = sexp.tail() |
101 | 101 | end |
102 | 102 | s = s .. ")" |
103 | 103 | return s |
104 | elseif sexp.class == Symbol then | |
104 | elseif is_a(sexp, Symbol) then | |
105 | 105 | return sexp.text() |
106 | elseif sexp.class == String then | |
106 | elseif is_a(sexp, String) then | |
107 | 107 | return "\"" .. sexp.text() .. "\"" |
108 | elseif sexp.class == Number then | |
108 | elseif is_a(sexp, Number) then | |
109 | 109 | return tostring(sexp.value()) |
110 | elseif sexp.class == Boolean then | |
110 | elseif is_a(sexp, Boolean) then | |
111 | 111 | if sexp.value() then return "#t" else return "#f" end |
112 | 112 | else |
113 | 113 | error("Invalid lua representation of s-expression: " .. render(sexp) .. ": " .. type(sexp)) |
30 | 30 | list_p = function(value) |
31 | 31 | if type(value) == "function" then |
32 | 32 | return False |
33 | elseif value.class == Nil then | |
33 | elseif value == Nil then | |
34 | 34 | return True |
35 | elseif value.class == Cons then | |
35 | elseif is_a(value, Cons) then | |
36 | 36 | return list_p(value.tail()) |
37 | 37 | else |
38 | 38 | return False |
48 | 48 | return False |
49 | 49 | elseif a.class ~= b.class then |
50 | 50 | return False |
51 | elseif a.class == Nil then | |
51 | elseif a == Nil then | |
52 | 52 | return True |
53 | elseif a.class == String or a.class == Symbol then | |
53 | elseif is_a(a, String) or is_a(a, Symbol) then | |
54 | 54 | return Boolean.value(a.text() == b.text()) |
55 | elseif a.class == Number or a.class == Boolean then | |
55 | elseif is_a(a, Number) or is_a(a, Boolean) then | |
56 | 56 | return Boolean.value(a.value() == b.value()) |
57 | elseif a.class == Cons then | |
57 | elseif is_a(a, Cons) then | |
58 | 58 | return equal_p(a.head(), b.head()) and equal_p(a.tail(), b.tail()) |
59 | 59 | else |
60 | 60 | return False |
183 | 183 | end |
184 | 184 | |
185 | 185 | fields.eval_toplevel = function(expr, env, module) |
186 | if expr.class == Cons then | |
187 | if expr.head().class == Symbol then | |
186 | if is_a(expr, Cons) then | |
187 | if is_a(expr.head(), Symbol) then | |
188 | 188 | if expr.head().text() == "define" then |
189 | 189 | local name = expr.tail().head() |
190 | 190 | local dexpr = expr.tail().tail().head() |