aboutsummaryrefslogtreecommitdiff
path: root/process/step7_quote.txt
blob: 58360f27006f6dc6bbe1837d430f6978d5baf5ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
--- step7_quote ---------------------------------
import types, reader, printer, env, core

READ(str): return reader.read_str(str)

pair?(ast): return ... // true if non-empty sequence
quasiquote(ast): return ... // quasiquote

eval_ast(ast,env):
  switch type(ast):
    symbol:      return env.get(ast)
    list,vector: return ast.map((x) -> EVAL(x,env))
    hash:        return ast.map((k,v) -> list(k, EVAL(v,env)))
    _default_:   return ast

EVAL(ast,env):
  while true:
    if not list?(ast): return eval_ast(ast, env)
    switch ast[0]:
      'def!:        return env.set(ast[1], EVAL(ast[2], env))
      'let*:        env = ...; ast = ast[2] // TCO
      'quote:       return ast[1]
      'quasiquote:  ast = quasiquote(ast[1]) // TCO
      'do:          ast = eval_ast(ast[1..-1], env)[-1] // TCO
      'if:          EVAL(ast[1], env) ? ast = ast[2] : ast = ast[3] // TCO
      'fn*:         return new MalFunc(...)
      _default_:    f, args = eval_ast(ast, env)
                    if malfunc?(f): ast = f.fn; env = ... // TCO
                    else:           return apply(f, args)

PRINT(exp): return printer.pr_str(exp)

repl_env = new Env()
rep(str): return PRINT(EVAL(READ(str),repl_env))

;; core.EXT: defined using Racket
core.ns.map((k,v) -> (repl_env.set(k, v)))
repl_env.set('eval, (ast) -> EVAL(ast, repl-env))
repl_env.set('*ARGV*, cmdline_args[1..])

;; core.mal: defined using the language itself
rep("(def! not (fn* (a) (if a false true)))")
rep("(def! load-file (fn* (f) ...))")

if cmdline_args: rep("(load-file \"" + args[0] + "\")"); exit 0

main loop:
  try:      println(rep(readline("user> ")))
  catch e:  println("Error: ", e)

--- env module ----------------------------------
class Env (outer=null,binds=[],exprs=[])
    data = hash_map()
    foreach b, i in binds:
      if binds[i] == '&: data[binds[i+1]] = exprs.drop(i); break
      else: data[binds[i]] = exprs[i]
  set(k,v): return data.set(k,v)
  find(k): return data.has(k) ? this : (if outer ? find(outer) : null)
  get(k): return data.find(k).get(k) OR raise "'" + k + "' not found"

--- core module ---------------------------------
ns = {'=:        equal?,

      'pr-str:   (a) -> a.map(|s| pr_str(e,true)).join(" ")),
      'str:      (a) -> a.map(|s| pr_str(e,false)).join("")),
      'prn:      (a) -> println(a.map(|s| pr_str(e,true)).join(" ")),
      'println:  (a) -> println(a.map(|s| pr_str(e,false)).join(" ")),
      'read-string: read_str,
      'slurp     read-file,

      '<:        lt,
      '<=:       lte,
      '>:        gt,
      '>=:       gte,
      '+:        add,
      '-:        sub,
      '*:        mult,
      '/:        div,

      'list:     list,
      'list?:    list?,

      'cons:     (a) -> concat([a[0]], a[1]),
      'concat:   (a) -> reduce(concat, [], a),
      'empty?:   empty?,
      'count:    count}