10 string
print(bool readable
) const;
11 bool is_truthy() const { return true; }
17 MalType
with_meta(MalType new_meta
);
25 class MalNil
: MalType
, HasSeq
27 override string
print(bool readable
) const { return "nil"; }
28 override bool is_truthy() const { return false; }
29 override bool opEquals(Object o
) { return (cast(MalNil
)(o
) !is null); }
30 override MalType
seq() { return this; }
33 class MalFalse
: MalType
35 override string
print(bool readable
) const { return "false"; }
36 override bool is_truthy() const { return false; }
37 override bool opEquals(Object o
) { return (cast(MalFalse
)(o
) !is null); }
40 class MalTrue
: MalType
42 override string
print(bool readable
) const { return "true"; }
43 override bool opEquals(Object o
) { return (cast(MalTrue
)(o
) !is null); }
53 mal_false
= new MalFalse
;
54 mal_true
= new MalTrue
;
57 MalType
bool_to_mal(in bool b
)
59 return b ? mal_true
: mal_false
;
62 class MalSymbol
: MalType
65 this(in string token
) { name
= token
; }
66 override string
print(bool readable
) const { return name
; }
68 override size_t
toHash()
70 return typeid(name
).getHash(&name
);
73 override int opCmp(Object other
)
75 MalSymbol o
= cast(MalSymbol
) other
;
76 return cmp(name
, o
.name
);
79 override bool opEquals(Object other
)
81 auto o
= cast(MalSymbol
) other
;
82 return (o
!is null && name
== o
.name
);
86 class MalInteger
: MalType
89 this(string token
) { val
= to
!long(token
); }
90 this(long v
) { val
= v
; }
91 override string
print(bool readable
) const { return to
!string(val
); }
93 override bool opEquals(Object o
)
95 auto oint
= cast(MalInteger
)(o
);
96 return (oint
!is null && val
== oint
.val
);
100 class MalString
: MalType
, HasSeq
103 this(in string token
) { val
= token
; }
104 override string
print(bool readable
) const
106 if (is_keyword()) return ":" ~ val
[2..$];
109 string escaped
= val
.replace("\\", "\\\\")
110 .replace("\"", "\\\"")
111 .replace("\n", "\\n");
112 return "\"" ~ escaped
~ "\"";
120 bool is_keyword() const
122 return val
.length
> 1 && val
[0..2] == "\u029e";
125 override bool opEquals(Object o
)
127 auto ostr
= cast(MalString
)(o
);
128 return (ostr
!is null && val
== ostr
.val
);
131 override MalType
seq() {
132 if (is_keyword() || val
.length
== 0) return mal_nil
;
133 auto chars
= val
.map
!(c
=> cast(MalType
)(new MalString(to
!string(c
))));
134 return new MalList(array(chars
));
138 abstract class MalSequential
: MalType
, HasSeq
, MalMeta
143 this(MalType
[] lst
) {
148 override bool opEquals(Object o
)
150 auto oseq
= cast(MalSequential
)(o
);
151 return (oseq
!is null && elements
== oseq
.elements
);
154 MalSequential
conj(MalType element
);
157 if (elements
.length
== 0) return mal_nil
;
158 return new MalList(elements
);
162 class MalList
: MalSequential
, MalMeta
164 this(MalType
[] lst
) { super(lst
); }
165 this(MalList that
, MalType new_meta
)
167 super(that
.elements
);
171 override string
print(bool readable
) const
173 auto items_strs
= elements
.map
!(e
=> e
.print(readable
));
174 return "(" ~ array(items_strs
).join(" ") ~ ")";
177 override MalSequential
conj(MalType element
)
179 return new MalList([element
] ~ elements
);
182 override MalType
meta() { return meta_val
; }
183 override MalType
with_meta(MalType new_meta
)
185 return new MalList(this, new_meta
);
189 class MalVector
: MalSequential
, MalMeta
191 this(MalType
[] lst
) { super(lst
); }
192 this(MalVector that
, MalType new_meta
)
194 super(that
.elements
);
198 override string
print(bool readable
) const
200 auto items_strs
= elements
.map
!(e
=> e
.print(readable
));
201 return "[" ~ array(items_strs
).join(" ") ~ "]";
204 override MalSequential
conj(MalType element
)
206 return new MalVector(elements
~ [element
]);
209 override MalType
meta() { return meta_val
; }
210 override MalType
with_meta(MalType new_meta
)
212 return new MalVector(this, new_meta
);
216 class MalHashmap
: MalType
, MalMeta
218 MalType
[string
] data
;
221 this(MalType
[string
] map
)
231 this(MalHashmap that
, MalType new_meta
)
237 bool contains(in MalType key
)
239 auto valp
= (make_hash_key(key
) in data
);
240 return valp
!is null;
243 MalType
get(in MalType key
)
245 auto valp
= (make_hash_key(key
) in data
);
246 return valp
is null ? mal_nil
: *valp
;
249 void remove(in MalType key
)
251 data
.remove(make_hash_key(key
));
254 void put(in MalType key
, MalType val
)
256 data
[make_hash_key(key
)] = val
;
259 void put_kv_list(MalType
[] lst
)
261 foreach (kv
; chunks(lst
, 2))
263 if (kv
.length
< 2) throw new Exception("requires even number of elements");
268 private string
make_hash_key(in MalType key
)
270 return verify_cast
!MalString(key
).val
;
273 override string
print(bool readable
) const
278 parts
~= (new MalString(k
)).print(readable
);
279 parts
~= v
.print(readable
);
281 return "{" ~ parts
.join(" ") ~ "}";
284 override bool opEquals(Object o
)
286 auto ohm
= cast(MalHashmap
)(o
);
287 return (ohm
!is null && data
== ohm
.data
);
290 override MalType
meta() { return meta_val
; }
291 override MalType
with_meta(MalType new_meta
)
293 return new MalHashmap(this, new_meta
);
297 alias BuiltinStaticFuncType
= MalType
function(MalType
[] a
...);
298 alias BuiltinFuncType
= MalType
delegate(MalType
[] a
...);
300 class MalBuiltinFunc
: MalType
, MalMeta
302 const BuiltinFuncType fn
;
306 this(in BuiltinFuncType fn_v
, in string name_v
)
313 this(in BuiltinStaticFuncType static_fn_v
, in string name_v
)
315 fn
= toDelegate(static_fn_v
);
320 this(MalBuiltinFunc that
, MalType new_meta
)
327 override string
print(bool readable
) const
329 return "<BuiltinFunc:" ~ name
~ ">";
332 override MalType
meta() { return meta_val
; }
334 override MalType
with_meta(MalType new_meta
)
336 return new MalBuiltinFunc(this, new_meta
);
340 class MalFunc
: MalType
, MalMeta
348 this(MalType
[] arg_names_v
, MalType func_body_v
, Env def_env_v
)
350 arg_names
= arg_names_v
;
351 func_body
= func_body_v
;
357 this(MalFunc that
, MalType new_meta
)
359 arg_names
= that
.arg_names
;
360 func_body
= that
.func_body
;
361 def_env
= that
.def_env
;
362 is_macro
= that
.is_macro
;
366 override string
print(bool readable
) const
368 return "<Function:args=" ~ array(arg_names
.map
!(e
=> e
.print(true))).join(",") ~ ">";
371 override MalType
meta() { return meta_val
; }
373 override MalType
with_meta(MalType new_meta
)
375 return new MalFunc(this, new_meta
);
379 class MalAtom
: MalType
, MalMeta
390 this(MalAtom that
, MalType new_meta
)
396 override string
print(bool readable
) const
398 return "(atom " ~ val
.print(readable
) ~ ")";
401 override bool opEquals(Object other
)
403 auto o
= cast(MalAtom
) other
;
404 return (o
!is null && val
== o
.val
);
407 override MalType
meta() { return meta_val
; }
409 override MalType
with_meta(MalType new_meta
)
411 return new MalAtom(this, new_meta
);
415 class MalException
: Exception
421 super("MalException");
426 T
verify_cast(T
)(in MalType v
)
428 if (T res
= cast(T
) v
) return res
;
429 throw new Exception("Expected " ~ typeid(T
).name
);
432 MalType
mal_type_q(T
)(in MalType
[] a
)
434 verify_args_count(a
, 1);
435 T res
= cast(T
) a
[0];
436 return bool_to_mal(res
!is null);
439 inout(MalType
[]) verify_args_count(inout MalType
[] args
, in int expected_length
)
441 if (args
.length
!= expected_length
)
443 throw new Exception("Expected " ~ to
!string(expected_length
) ~ " arguments");
448 void verify_min_args_count(in MalType
[] args
, in int min_expected_length
)
450 if (args
.length
< min_expected_length
)
452 throw new Exception("Expected at least " ~ to
!string(min_expected_length
) ~ " arguments");