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 vec
= ast as Mal
.Vector
;
42 var result
= new Mal
.Vector
.with_size(vec
.length
);
43 var root
= new GC
.Root(result
); (void)root
;
44 for (var i
= 0; i
< vec
.length
; i
++)
45 result
[i
] = EVAL(vec
[i
], env
);
48 if (ast is Mal
.Hashmap
) {
49 var result
= new Mal
.Hashmap();
50 var root
= new GC
.Root(result
); (void)root
;
51 var map
= (ast as Mal
.Hashmap
).vs
;
52 foreach (var key
in map
.get_keys())
53 result
.insert(key
, EVAL(map
[key
], env
));
59 private static Mal
.Val
define_eval(Mal
.Val key
, Mal
.Val value
,
62 var rootk
= new GC
.Root(key
); (void)rootk
;
63 var roote
= new GC
.Root(env
); (void)roote
;
64 var symkey
= key as Mal
.Sym
;
66 throw new Mal
.Error
.BAD_PARAMS(
67 "let*: expected a symbol to define");
68 var val
= EVAL(value
, env
);
73 public static Mal
.Val
EVAL(Mal
.Val ast
, Mal
.Env env
)
75 var ast_root
= new GC
.Root(ast
); (void)ast_root
;
76 var env_root
= new GC
.Root(env
); (void)env_root
;
77 GC
.Core
.maybe_collect();
79 if (ast is Mal
.List
) {
80 unowned GLib
.List
<Mal
.Val
> list
= (ast as Mal
.List
).vs
;
81 if (list
.first() == null)
84 var first
= list
.first().data
;
85 if (first is Mal
.Sym
) {
86 var sym
= first as Mal
.Sym
;
89 if (list
.length() != 3)
90 throw new Mal
.Error
.BAD_PARAMS(
91 "def!: expected two values");
92 return define_eval(list
.next
.data
, list
.next
.next
.data
,
95 if (list
.length() != 3)
96 throw new Mal
.Error
.BAD_PARAMS(
97 "let*: expected two values");
98 var defns
= list
.nth(1).data
;
99 var newenv
= new Mal
.Env
.within(env
);
101 if (defns is Mal
.List
) {
102 for (unowned GLib
.List
<Mal
.Val
> iter
=
103 (defns as Mal
.List
).vs
;
104 iter
!= null; iter
= iter
.next
.next
) {
105 if (iter
.next
== null)
106 throw new Mal
.Error
.BAD_PARAMS(
107 "let*: expected an even-length list" +
109 define_eval(iter
.data
, iter
.next
.data
, newenv
);
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
);
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
);