| 1 | readline = require "./node_readline.coffee" |
| 2 | types = require "./types.coffee" |
| 3 | reader = require "./reader.coffee" |
| 4 | printer = require "./printer.coffee" |
| 5 | Env = require("./env.coffee").Env |
| 6 | core = require("./core.coffee") |
| 7 | |
| 8 | # read |
| 9 | READ = (str) -> reader.read_str str |
| 10 | |
| 11 | # eval |
| 12 | eval_ast = (ast, env) -> |
| 13 | if types._symbol_Q(ast) then env.get ast |
| 14 | else if types._list_Q(ast) then ast.map((a) -> EVAL(a, env)) |
| 15 | else if types._vector_Q(ast) |
| 16 | types._vector(ast.map((a) -> EVAL(a, env))...) |
| 17 | else if types._hash_map_Q(ast) |
| 18 | new_hm = {} |
| 19 | new_hm[k] = EVAL(ast[k],env) for k,v of ast |
| 20 | new_hm |
| 21 | else ast |
| 22 | |
| 23 | EVAL = (ast, env) -> |
| 24 | #console.log "EVAL:", printer._pr_str ast |
| 25 | if !types._list_Q ast then return eval_ast ast, env |
| 26 | if ast.length == 0 then return ast |
| 27 | |
| 28 | # apply list |
| 29 | [a0, a1, a2, a3] = ast |
| 30 | switch a0.name |
| 31 | when "def!" |
| 32 | env.set(a1, EVAL(a2, env)) |
| 33 | when "let*" |
| 34 | let_env = new Env(env) |
| 35 | for k,i in a1 when i %% 2 == 0 |
| 36 | let_env.set(a1[i], EVAL(a1[i+1], let_env)) |
| 37 | EVAL(a2, let_env) |
| 38 | when "do" |
| 39 | el = eval_ast(ast[1..], env) |
| 40 | el[el.length-1] |
| 41 | when "if" |
| 42 | cond = EVAL(a1, env) |
| 43 | if cond == null or cond == false |
| 44 | if a3? then EVAL(a3, env) else null |
| 45 | else |
| 46 | EVAL(a2, env) |
| 47 | when "fn*" |
| 48 | (args...) -> EVAL(a2, new Env(env, a1, args)) |
| 49 | else |
| 50 | [f, args...] = eval_ast ast, env |
| 51 | f(args...) |
| 52 | |
| 53 | |
| 54 | # print |
| 55 | PRINT = (exp) -> printer._pr_str exp, true |
| 56 | |
| 57 | # repl |
| 58 | repl_env = new Env() |
| 59 | rep = (str) -> PRINT(EVAL(READ(str), repl_env)) |
| 60 | |
| 61 | # core.coffee: defined using CoffeeScript |
| 62 | repl_env.set types._symbol(k), v for k,v of core.ns |
| 63 | |
| 64 | # core.mal: defined using the language itself |
| 65 | rep("(def! not (fn* (a) (if a false true)))"); |
| 66 | |
| 67 | # repl loop |
| 68 | while (line = readline.readline("user> ")) != null |
| 69 | continue if line == "" |
| 70 | try |
| 71 | console.log rep line |
| 72 | catch exc |
| 73 | continue if exc instanceof reader.BlankException |
| 74 | if exc.stack? and exc.stack.length > 2000 |
| 75 | console.log exc.stack.slice(0,1000) + "\n ..." + exc.stack.slice(-1000) |
| 76 | else if exc.stack? console.log exc.stack |
| 77 | else console.log exc |
| 78 | |
| 79 | # vim: ts=2:sw=2 |