4 - prompt, input, READ, EVAL, PRINT, output
6 - display prompt, read line of input
8 - get your language compiler/interpreter running
9 - create step0_repl.EXT
10 - loop that reads input, calls rep, writes output, exits
12 - rep calls PRINT(EVAL(READ(str)))
13 - READ, EVAL, PRINT just return input parameter
14 - modify toplevel Makefile
15 - add language (directory name) to IMPLS
16 - add <lang>_STEP_TO_PROG entry
17 - add <lang>_RUNSTEP entry
18 - for a compiled language, add <lang>/Makefile
19 - targets: all, step*, stats, stats-lisp,
21 - use native eval in EVAL if available
23 - libedit/GNU readline:
24 - use existing lib, wrap shell call or implement
25 - load history file on first call
26 - add non-blank lines to history
27 - append to history file
31 - add boxed types if no language equivalent:
32 - nil, true, false, symbol, integer, string, list
33 - error types if necessary
35 - stateful reader object
36 - alternative: mutate token list
37 - tokenize (if regex available)
38 - standard regex pattern: "/[\s,]*(~@|[\[\]{}()'`~^@]|\"(?:\\.|[^\\\"])*\"|;.*|[^\s\[\]{}('\"`,;)]*)/"
40 - read_form(new Reader(tokenize(str)))
43 - call read_list or read_atom
46 - return array (boxed)
47 - read_atom (not atom type)
48 - return scalar boxed type:
49 - nil, true, false, symbol, integer, string
53 - stringify boxed types to their Mal representations
54 - list/array is recursive
57 - catch errors, print them and continue
58 - impls without exception handling will need to have a global
59 variable with checks for it at the beginning of critical
62 - copy step0_repl.EXT to step1_read_print.EXT
63 - modify Makefile if compiled
64 - call reader.read_str from READ
65 - pass through type returned from read_str through
68 - if regex support (much easier) then tokenize with this:
69 /[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"|;.*|[^\s\[\]{}('"`,;)]*)/g
72 - handle blank line (exceptions, return code, global
73 depending on lang features)
74 - read_str -> read_form -> {read_list, read_atom}
75 - mutable reader thing
77 - _pr_str function which basically reverses read_str and
78 returns a string representation
79 - run `make test^EXT^step1`. Much of the basics should pass up
81 - implement read_hash_map (can refactor read_list)
83 - probably want to define types for List and Vector in
84 types.EXT that extend or wrap native arrays
85 - run `make test^EXT^step1`. All mandatory should pass
90 - Basically: two array types that retain their boxed types, can be
91 challenging depending on the language (e.g. JS, PHP: no clean
92 way to derive new array types).
94 - add vector boxed type
95 - derived from array if possible
101 - re-use read_list but with different constructor, delims
105 - re-use read_list function and apply that using hash-map
109 - hash-map, map?, assoc, dissoc, get, contains?, keys,
110 vals (probably assoc! and dissoc! for internal)
111 - eval_map: eval the keys and values of hash_maps
113 - if hash_map, call eval_map on it
117 - symbol?, list? (if no simple idiomatic impl type check)
118 - first, rest, nth on list
120 - if symbol, return value of looking up in env
121 - if list, eval each item, return new list
122 - otherwise, just return unchanged ast
124 - if not a list, call eval_ast
125 - otherwise, apply first item to eval_ast of (rest ast)
126 - repl_env as simple one level hash map (assoc. array)
127 - store function as hash_map value
129 - copy step1_read_print.EXT to step2_eval.EXT
130 - create repl_env hash_map) with +, -, *, /
131 - store anon func as values if possible
133 - implement symbol? (symbol_Q) and list? (list_Q)
134 - add env param to EVAL and add to rep EVAL call
136 - if not list call eval_ast
137 - otherwise eval_ast, and call first arg with rest
139 - if symbol?, lookup in env
140 - if List, EVAL each and return eval's list
141 - otherwise, return original
142 - optional: handle vector and hash-map in eval_ast
145 - eval each item, return new vector
148 - eval each value, return new hash_map
152 - may need function type if HashMap is strongly typed (e.g. Java)
154 - find, set, get (no binds/exprs in constructor yet)
156 - def! - mutate current environment
157 - let* - create new environment with bindings
159 - cp step2_eval.EXT to step3_env.EXT
160 - add env.EXT if lang support file dep cycles, otherwise, add
163 - find, get, set methods/functions
164 - use Env type instead of map/assoc. array
165 - eval_ast: use method for lookup
167 - switch on first symbol
169 - set env[a1] to EVAL(a2, env)
171 - loop through let building up let_env
173 - move apply to default
177 - function type if no closures in impl language
178 - _equal_Q function (recursive)
182 - print_readably option for pr_str
183 - add function printing to pr_str
184 - string escaping in pr_str
185 - core module (export via core_ns):
186 - export equal_Q from types as =
187 - move arith operations here
188 - add arith comparison functions
189 - pr_str, str, prn, println
190 - list, list?, count, empty?
192 - add binds/exprs handling to Env constructor with variable arity
197 - simple if language supports closures
198 - otherwise needs a way of representing functions that can
199 have associated metadata
200 - define "not" using REP/RE
202 - cp step3_env.EXT to step4_env.EXT
203 - modify Makefile if compiled
205 - add binds and exprs args. Create new environments with
206 exprs bound to binds. If & symbol, bind rest of exprs to
210 - eval_ast [1:], then return last eval'd element
214 - else EVAL(a3), unless no a3 then return nil
216 - if available use function closures to return a new
217 native function that calls EVAL(a2, Env(env, a1, fargs))
219 - create ns object to hold core namespace
220 - move numeric operators here
221 - add compison operators
222 - add list, list?, empty?, count, not
223 - run make test^EXT^step4
224 - implement equal?/equal_Q in types.EXT and refer in core.ns
225 - implement not as rep("(def! not (fn* (a) (if a false true)))")
226 - run make test^EXT^step4: should pass everything except
228 - implement: pr-str, str, prn, println in core.EXT and
230 - should leverage pr-str from printer.EXT
231 - add reader/printer string quote/unquote
236 - stores: eval, exp, env, params
237 - eval is EVAL in native mal case (needed for map function
238 later), otherwise reference to platform function
239 - if metadata support, then store exp, env, params as
242 - add printing of mal function type
244 - while loop around whole thing
245 - cases where we directly return result of EVAL, instead set
246 ast and env to what would be put in the EVAL, then loop.
249 - if mal function type
250 - set env to new Env based on properties on the function
251 - if native function, same as before
254 - create Mal function type to store eval, exp, env, params
255 - cp step4_if_fn_do.EXT to step5_tco.EXT
256 - wrap EVAL in infinite while loop
257 - in let*, do, and if:
258 - set ast and env and loop (no return)
259 - in fn* create Mal function type
260 - if compiled, update Makefile
261 - in apply, test if Mal function type:
262 - if so, generate new env from stored env, args and callee
264 - set ast to stored ast
269 - read-string, slurp functions
270 - define eval and load-file functions
272 - if files on command line, use load-file to run first argument
273 using rest as arguments
275 - cp step5_tco.EXT to step6_file.EXT
276 - if compiled update Makefile
277 - add eval to repl_env
278 - add empty *ARGV* list to repl_env
281 - wrap printer.read-str as read-string
282 - implement load-file using rep
284 (load-file "../tests/inc.mal")
286 - implement command line execution
288 ./step6_file ../tests/incA.mal
290 - implement comments in reader.EXT (ignore in tokenize)
293 - add is_pair and quasiquote functions
294 - rewrite ast using cons/concat functions
295 - if vectors, use sequential? instead of list? in is_pair
297 - add 'quote', 'quasiquote' cases
299 - add cons and concat functions
301 - add reader macros to read_form for quote, unquote,
302 splice-unquote and quasiquote
304 - cp step6_file.EXT to step6_quote.EXT
305 - if compiled update Makefile
306 - add is_pair and quasiquote
307 - add quote and quasiquote cases to EVAL
308 - implement reader macros (', `, ~, ~@) in reader
309 - retest make test^go^step1
310 - implement cons and concat in core.EXT
311 - retest test^go^step7
315 - capability to store ismacro property in function
317 - add first, rest, nth functions
318 - add is_macro_call and macroexpand
319 - recursively macroexpand lists
320 - if applying a macro function, run it on the ast first before
322 - call macroexpand apply in EVAL before apply
324 - add 'defmacro!' and 'macroexpand'
325 - set ismacro property on function
328 - convert returned data to mal data
329 - recursive, similar to pr_str
334 - apply, map functions: should not directly call EVAL, which
335 requires the function object to be runnable
337 - nil?, true?, false?
339 - try*/catch*: for normal exceptions, extracts string
340 otherwise extracts full value
341 - set and print *host-language*
342 - define cond and or macros using REP/RE
344 - Extra defintions needed for self-hosting
346 - symbol?, sequential? (if not already)
355 - @a reader macro -> (deref a)
358 - atom type, atom, atom?, deref, reset!, swap!
362 - ^ reader macro reads ^meta obj -> (with-meta obj meta)
364 - support meta property on collections: lists, vectors,
365 hash-maps, functions, atoms
366 - clone/copy of collections
368 - add with-meta, meta functions