1 import 'dart:collection';
4 abstract class MalType {
5 bool get isMacro => false;
11 abstract class MalIterable extends MalType
12 with ListMixin<MalType>
13 implements List<MalType> {
14 final List<MalType> elements;
16 MalIterable(this.elements);
18 MalType operator [](int index) => elements[index];
19 void operator []=(int index, MalType value) {
20 elements[index] = value;
23 int get length => elements.length;
24 void set length(int newLength) {
25 elements.length = newLength;
28 bool operator ==(other) {
29 if (other is! MalIterable) return false;
31 // apparently (= (list) nil) should be false...
32 if (other is MalNil) return false;
34 if (elements.length != other.elements.length) return false;
35 for (var i = 0; i < elements.length; i++) {
36 if (elements[i] != other.elements[i]) return false;
45 class MalList extends MalIterable {
46 MalList(List<MalType> elements) : super(elements);
50 return new MalList(elements.toList());
54 class MalVector extends MalIterable {
55 MalVector(List<MalType> elements) : super(elements);
59 return new MalVector(elements.toList());
63 class MalHashMap extends MalType {
64 final Map<MalType, MalType> value;
66 MalHashMap(this.value);
68 MalHashMap.fromSequence(List<MalType> elements)
69 : value = _mapFromSequence(elements);
71 static Map<MalType, MalType> _mapFromSequence(List<MalType> elements) {
72 var result = <MalType, MalType>{};
74 var readingKey = true;
76 for (var malType in elements) {
78 if (malType is MalString || malType is MalKeyword) {
81 throw new ArgumentError('hash-map keys must be strings or keywords');
84 result[pendingKey] = malType;
86 readingKey = !readingKey;
92 bool operator ==(other) {
93 if (other is! MalHashMap) return false;
94 var otherMap = (other as MalHashMap).value;
95 if (otherMap.length != value.length) return false;
96 for (var key in value.keys) {
97 if (!otherMap.containsKey(key)) return false;
98 if (value[key] != otherMap[key]) return false;
105 return new MalHashMap(new Map.from(value));
109 class MalInt extends MalType {
114 bool operator ==(other) {
115 if (other is! MalInt) return false;
116 return other.value == value;
121 return new MalInt(value);
125 class MalSymbol extends MalType {
128 MalSymbol(this.value);
130 int get hashCode => value.hashCode;
132 bool operator ==(other) {
133 if (other is! MalSymbol) return false;
134 return value == other.value;
139 return new MalSymbol(value);
143 class MalKeyword extends MalType {
146 MalKeyword(this.value);
148 int get hashCode => value.hashCode;
150 bool operator ==(other) {
151 if (other is! MalKeyword) return false;
152 return value == other.value;
157 return new MalKeyword(value);
161 class MalString extends MalType {
164 MalString(this.value);
166 int get hashCode => value.hashCode;
168 bool operator ==(other) {
169 if (other is! MalString) return false;
170 return other.value == value;
175 return new MalString(value);
179 class MalBool extends MalType {
184 bool operator ==(other) {
185 if (other is! MalBool) return false;
186 return other.value == value;
191 return new MalBool(value);
195 class MalNil extends MalIterable {
196 MalNil() : super(const <MalType>[]);
198 bool operator ==(other) => other is MalNil;
206 class MalAtom extends MalType {
213 return new MalAtom(value);
217 abstract class MalCallable extends MalType {
218 MalType call(List<MalType> args);
220 bool get isMacro => false;
223 typedef MalType BuiltinFunc(List<MalType> args);
225 class MalBuiltin extends MalCallable {
226 final BuiltinFunc func;
228 MalBuiltin(this.func);
230 MalType call(List<MalType> args) {
236 return new MalBuiltin(func);
240 typedef MalType EvalFun(MalType ast, Env env);
242 class MalClosure extends MalCallable {
243 final List<MalSymbol> params;
249 bool isMacro = false;
251 MalClosure(this.params, this.ast, this.env, this.func);
253 MalType call(List<MalType> args) {
260 new MalClosure(this.params.toList(), this.ast, this.env, this.func);
261 closure.isMacro = this.isMacro;
266 class MalException implements Exception {
269 MalException(this.value);