1 class Mal
.Main
: GLib
.Object
{
8 public static Mal
.Val?
READ() {
9 string? line
= Readline
.readline("user> ");
12 Readline
.History
.add(line
);
15 return Reader
.read_str(line
);
16 } catch (Mal
.Error err
) {
17 GLib
.stderr
.printf("%s\n", err
.message
);
27 public static Mal
.Val
eval_ast(Mal
.Val ast
, Mal
.Env env
)
29 var roota
= new GC
.Root(ast
); (void)roota
;
30 var roote
= new GC
.Root(env
); (void)roote
;
32 return env
.get(ast as Mal
.Sym
);
33 if (ast is Mal
.List
) {
34 var result
= new Mal
.List
.empty();
35 var root
= new GC
.Root(result
); (void)root
;
36 foreach (var elt
in (ast as Mal
.List
).vs
)
37 result
.vs
.append(EVAL(elt
, env
));
40 if (ast is Mal
.Vector
) {
41 var results
= new GLib
.List
<Mal
.Val
>();
42 for (var iter
= (ast as Mal
.Vector
).iter();
43 iter
.nonempty(); iter
.step())
44 results
.append(EVAL(iter
.deref(), env
));
45 return new Mal
.Vector
.from_list(results
);
47 if (ast is Mal
.Hashmap
) {
48 var result
= new Mal
.Hashmap();
49 var root
= new GC
.Root(result
); (void)root
;
50 var map
= (ast as Mal
.Hashmap
).vs
;
51 foreach (var key
in map
.get_keys())
52 result
.insert(key
, EVAL(map
[key
], env
));
58 private static Mal
.Val
define_eval(Mal
.Val key
, Mal
.Val value
,
59 Mal
.Env eval_env
, Mal
.Env def_env
)
61 var rootk
= new GC
.Root(key
); (void)rootk
;
62 var roote
= new GC
.Root(def_env
); (void)roote
;
63 var symkey
= key as Mal
.Sym
;
65 throw new Mal
.Error
.BAD_PARAMS(
66 "let*: expected a symbol to define");
67 var val
= EVAL(value
, eval_env
);
68 def_env
.set(symkey
, val
);
72 public static Mal
.Val
EVAL(Mal
.Val ast
, Mal
.Env env
)
74 var ast_root
= new GC
.Root(ast
); (void)ast_root
;
75 var env_root
= new GC
.Root(env
); (void)env_root
;
76 GC
.Core
.maybe_collect();
78 if (ast is Mal
.List
) {
79 unowned GLib
.List
<Mal
.Val
> list
= (ast as Mal
.List
).vs
;
80 if (list
.first() == null)
83 var first
= list
.first().data
;
84 if (first is Mal
.Sym
) {
85 var sym
= first as Mal
.Sym
;
88 if (list
.length() != 3)
89 throw new Mal
.Error
.BAD_PARAMS(
90 "def!: expected two values");
91 return define_eval(list
.next
.data
, list
.next
.next
.data
,
94 if (list
.length() != 3)
95 throw new Mal
.Error
.BAD_PARAMS(
96 "let*: expected two values");
97 var defns
= list
.nth(1).data
;
98 var newenv
= new Mal
.Env
.within(env
);
100 if (defns is Mal
.List
) {
101 for (unowned GLib
.List
<Mal
.Val
> iter
=
102 (defns as Mal
.List
).vs
;
103 iter
!= null; iter
= iter
.next
.next
) {
104 if (iter
.next
== null)
105 throw new Mal
.Error
.BAD_PARAMS(
106 "let*: expected an even-length list" +
108 define_eval(iter
.data
, iter
.next
.data
,
111 } else if (defns is Mal
.Vector
) {
112 var vec
= defns as Mal
.Vector
;
113 if (vec
.length
% 2 != 0)
114 throw new Mal
.Error
.BAD_PARAMS(
115 "let*: expected an even-length vector" +
117 for (var i
= 0; i
< vec
.length
; i
+= 2)
118 define_eval(vec
[i
], vec
[i
+1], newenv
, newenv
);
120 throw new Mal
.Error
.BAD_PARAMS(
121 "let*: expected a list or vector of definitions");
123 return EVAL(list
.nth(2).data
, newenv
);
125 Mal
.Val result
= null;
126 for (list
= list
.next
; list
!= null; list
= list
.next
)
127 result
= EVAL(list
.data
, env
);
129 throw new Mal
.Error
.BAD_PARAMS(
130 "do: expected at least one argument");
133 if (list
.length() != 3 && list
.length() != 4)
134 throw new Mal
.Error
.BAD_PARAMS(
135 "if: expected two or three arguments");
137 var cond
= EVAL(list
.data
, env
);
139 if (!cond
.truth_value()) {
140 // Skip to the else clause, which defaults to nil.
143 return new Mal
.Nil();
145 return EVAL(list
.data
, env
);
147 if (list
.length() != 3)
148 throw new Mal
.Error
.BAD_PARAMS(
149 "fn*: expected two arguments");
150 var binds
= list
.next
.data as Mal
.Listlike
;
151 var body
= list
.next
.next
.data
;
153 throw new Mal
.Error
.BAD_PARAMS(
154 "fn*: expected a list of parameter names");
155 for (var iter
= binds
.iter(); iter
.nonempty(); iter
.step())
156 if (!(iter
.deref() is Mal
.Sym
))
157 throw new Mal
.Error
.BAD_PARAMS(
158 "fn*: expected parameter name to be "+
160 return new Mal
.Function(binds
, body
, env
);
164 var newlist
= eval_ast(ast
, env
) as Mal
.List
;
165 unowned GLib
.List
<Mal
.Val
> firstlink
= newlist
.vs
.first();
166 Mal
.Val firstdata
= firstlink
.data
;
167 newlist
.vs
.remove_link(firstlink
);
169 if (firstdata is Mal
.BuiltinFunction
) {
170 return (firstdata as Mal
.BuiltinFunction
).call(newlist
);
171 } else if (firstdata is Mal
.Function
) {
172 var fn
= firstdata as Mal
.Function
;
173 var newenv
= new Mal
.Env
.funcall(
174 fn
.env
, fn
.parameters
, newlist
);
175 return EVAL(fn
.body
, newenv
);
177 throw new Mal
.Error
.CANNOT_APPLY(
178 "bad value at start of list");
181 return eval_ast(ast
, env
);
185 public static void PRINT(Mal
.Val value
) {
186 stdout
.printf("%s\n", pr_str(value
));
189 public static void rep(Mal
.Env env
) throws Mal
.Error
{
190 Mal
.Val? val
= READ();
192 val
= EVAL(val
, env
);
197 public static int main(string[] args
) {
198 var env
= new Mal
.Env();
199 var root
= new GC
.Root(env
); (void)root
;
202 foreach (var key
in Mal
.Core
.ns
.get_keys())
203 env
.set(new Mal
.Sym(key
), Mal
.Core
.ns
[key
]);
206 EVAL(Mal
.Reader
.read_str("(def! not (fn* (a) (if a false true)))"),
208 } catch (Mal
.Error err
) {
209 assert(false); // shouldn't happen
215 } catch (Mal
.Error err
) {
216 GLib
.stderr
.printf("%s\n", err
.message
);