crystal: add seq and string?
[jackhill/mal.git] / es6 / step2_eval.js
1 import { readline } from './node_readline'
2 import { _symbol, _symbol_Q, _list_Q, _vector, _vector_Q,
3 _hash_map_Q } from './types'
4 import { BlankException, read_str } from './reader'
5 import { pr_str } from './printer'
6
7 // read
8 const READ = (str) => read_str(str)
9
10 // eval
11 const eval_ast = (ast, env) => {
12 if (_symbol_Q(ast)) {
13 if (ast in env) {
14 return env[ast]
15 } else {
16 throw Error(`'${Symbol.keyFor(ast)}' not found`)
17 }
18 } else if (_list_Q(ast)) {
19 return ast.map((x) => EVAL(x, env))
20 } else if (_vector_Q(ast)) {
21 return _vector(...ast.map((x) => EVAL(x, env)))
22 } else if (_hash_map_Q(ast)) {
23 let new_hm = new Map()
24 for (let [k, v] of ast) {
25 new_hm.set(EVAL(k, env), EVAL(v, env))
26 }
27 return new_hm
28 } else {
29 return ast
30 }
31 }
32
33 const EVAL = (ast, env) => {
34 if (!_list_Q(ast)) { return eval_ast(ast, env) }
35
36 const [f, ...args] = eval_ast(ast, env)
37 return f(...args)
38 }
39
40 // print
41 const PRINT = (exp) => pr_str(exp, true)
42
43 // repl
44 var repl_env = {[_symbol('+')]: (a,b) => a+b,
45 [_symbol('-')]: (a,b) => a-b,
46 [_symbol('*')]: (a,b) => a*b,
47 [_symbol('/')]: (a,b) => a/b}
48 const REP = (str) => PRINT(EVAL(READ(str), repl_env))
49
50 while (true) {
51 let line = readline('user> ')
52 if (line == null) break
53 try {
54 if (line) { console.log(REP(line)); }
55 } catch (exc) {
56 if (exc instanceof BlankException) { continue; }
57 if (exc.stack) { console.log(exc.stack); }
58 else { console.log(`Error: ${exc}`); }
59 }
60 }