1 if (typeof module
!== 'undefined') {
2 var types
= require('./types');
3 var readline
= require('./node_readline');
4 var reader
= require('./reader');
5 var printer
= require('./printer');
6 var Env
= require('./env').Env
;
7 var core
= require('./core');
8 var interop
= require('./interop');
13 return reader
.read_str(str
);
18 return types
._sequential_Q(x
) && x
.length
> 0;
21 function quasiquote(ast
) {
23 return [types
._symbol("quote"), ast
];
24 } else if (types
._symbol_Q(ast
[0]) && ast
[0].value
=== 'unquote') {
26 } else if (is_pair(ast
[0]) && ast
[0][0].value
=== 'splice-unquote') {
27 return [types
._symbol("concat"),
29 quasiquote(ast
.slice(1))];
31 return [types
._symbol("cons"),
33 quasiquote(ast
.slice(1))];
37 function is_macro_call(ast
, env
) {
38 return types
._list_Q(ast
) &&
39 types
._symbol_Q(ast
[0]) &&
41 env
.get(ast
[0])._ismacro_
;
44 function macroexpand(ast
, env
) {
45 while (is_macro_call(ast
, env
)) {
46 var mac
= env
.get(ast
[0]);
47 ast
= mac
.apply(mac
, ast
.slice(1));
52 function eval_ast(ast
, env
) {
53 if (types
._symbol_Q(ast
)) {
55 } else if (types
._list_Q(ast
)) {
56 return ast
.map(function(a
) { return EVAL(a
, env
); });
57 } else if (types
._vector_Q(ast
)) {
58 var v
= ast
.map(function(a
) { return EVAL(a
, env
); });
59 v
.__isvector__
= true;
61 } else if (types
._hash_map_Q(ast
)) {
64 new_hm
[EVAL(k
, env
)] = EVAL(ast
[k
], env
);
72 function _EVAL(ast
, env
) {
75 //printer.println("EVAL:", printer._pr_str(ast, true));
76 if (!types
._list_Q(ast
)) {
77 return eval_ast(ast
, env
);
81 ast
= macroexpand(ast
, env
);
82 if (!types
._list_Q(ast
)) {
83 return eval_ast(ast
, env
);
86 var a0
= ast
[0], a1
= ast
[1], a2
= ast
[2], a3
= ast
[3];
89 var res
= EVAL(a2
, env
);
90 return env
.set(a1
, res
);
92 var let_env
= new Env(env
);
93 for (var i
=0; i
< a1
.length
; i
+=2) {
94 let_env
.set(a1
[i
], EVAL(a1
[i
+1], let_env
));
102 ast
= quasiquote(a1
);
105 var func
= EVAL(a2
, env
);
106 func
._ismacro_
= true;
107 return env
.set(a1
, func
);
109 return macroexpand(a1
, env
);
111 return eval(a1
.toString());
113 var el
= eval_ast(ast
.slice(2), env
),
114 r
= interop
.resolve_js(a1
.toString()),
115 obj
= r
[0], f
= r
[1];
116 var res
= f
.apply(obj
, el
);
117 console
.log("DEBUG3:", res
);
118 return interop
.js_to_mal(res
);
121 return EVAL(a1
, env
);
123 if (a2
&& a2
[0].value
=== "catch*") {
124 if (exc
instanceof Error
) { exc
= exc
.message
; }
125 return EVAL(a2
[2], new Env(env
, [a2
[1]], [exc
]));
131 eval_ast(ast
.slice(1, -1), env
);
132 ast
= ast
[ast
.length
-1];
135 var cond
= EVAL(a1
, env
);
136 if (cond
=== null || cond
=== false) {
137 ast
= (typeof a3
!== "undefined") ? a3
: null;
143 return types
._function(EVAL
, Env
, a2
, env
, a1
);
145 var el
= eval_ast(ast
, env
), f
= el
[0];
148 env
= f
.__gen_env__(el
.slice(1));
150 return f
.apply(f
, el
.slice(1));
157 function EVAL(ast
, env
) {
158 var result
= _EVAL(ast
, env
);
159 return (typeof result
!== "undefined") ? result
: null;
163 function PRINT(exp
) {
164 return printer
._pr_str(exp
, true);
168 var repl_env
= new Env();
169 var rep = function(str
) { return PRINT(EVAL(READ(str
), repl_env
)); };
171 // core.js: defined using javascript
172 for (var n
in core
.ns
) { repl_env
.set(types
._symbol(n
), core
.ns
[n
]); }
173 repl_env
.set(types
._symbol('eval'), function(ast
) {
174 return EVAL(ast
, repl_env
); });
175 repl_env
.set(types
._symbol('*ARGV*'), []);
177 // core.mal: defined using the language itself
178 rep("(def! *host-language* \"javascript\")")
179 rep("(def! not (fn* (a) (if a false true)))");
180 rep("(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \")\")))))");
181 rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))");
182 rep("(def! *gensym-counter* (atom 0))");
183 rep("(def! gensym (fn* [] (symbol (str \"G__\" (swap! *gensym-counter* (fn* [x] (+ 1 x)))))))");
184 rep("(defmacro! or (fn* (& xs) (if (empty? xs) nil (if (= 1 (count xs)) (first xs) (let* (condvar (gensym)) `(let* (~condvar ~(first xs)) (if ~condvar ~condvar (or ~@(rest xs)))))))))");
186 if (typeof process
!== 'undefined' && process
.argv
.length
> 2) {
187 repl_env
.set(types
._symbol('*ARGV*'), process
.argv
.slice(3));
188 rep('(load-file "' + process
.argv
[2] + '")');
193 if (typeof require
!== 'undefined' && require
.main
=== module
) {
194 // Synchronous node.js commandline mode
195 rep("(println (str \"Mal [\" *host-language* \"]\"))");
197 var line
= readline
.readline("user> ");
198 if (line
=== null) { break; }
200 if (line
) { printer
.println(rep(line
)); }
202 if (exc
instanceof reader
.BlankException
) { continue; }
203 if (exc
.stack
) { printer
.println(exc
.stack
); }
204 else { printer
.println(exc
); }