1
1
mirror of https://github.com/kanaka/mal.git synced 2024-09-20 10:07:45 +03:00
mal/haxe/types/Types.hx

235 lines
6.3 KiB
Haxe

package types;
import env.Env;
class MalAtomContainer {
}
enum MalType {
MalNil;
MalTrue;
MalFalse;
MalInt(val:Int);
MalString(val:String);
MalSymbol(val:String);
MalList(val:Array<MalType>);
MalVector(val:Array<MalType>);
MalHashMap(val:Map<String,MalType>);
MalAtom(val:{val:MalType});
MalFunc(val:(Array<MalType>)->MalType,
ast:MalType,
env:Env,
params:MalType,
ismacro:Bool,
meta:MalType);
}
class Types {
public static var nil:MalType = MalNil;
public static function _equal_Q(a:MalType, b:MalType) {
return switch [a, b] {
case [MalInt(va), MalInt(vb)]: va == vb;
case [MalString(va), MalString(vb)] |
[MalSymbol(va), MalSymbol(vb)]: va == vb;
case [MalList(la), MalList(lb)] |
[MalList(la), MalVector(lb)] |
[MalVector(la), MalList(lb)] |
[MalVector(la), MalVector(lb)]:
if (la.length != lb.length) { return false; }
for (i in 0...la.length) {
if (!_equal_Q(la[i], lb[i])) {
false;
}
}
true;
case [MalHashMap(ma), MalHashMap(mb)]:
var maks = ma.keys(),
mbks = mb.keys(),
malen = 0,
mblen = 0;
for (k in maks) {
malen += 1;
if ((!mb.exists(k)) || !_equal_Q(ma[k], mb[k])) {
return false;
}
}
for (k in mbks) { mblen += 1; }
if (malen != mblen) { return false; }
true;
case _: a == b;
}
}
public static function _clone(a:MalType) {
return switch (a) {
case MalHashMap(m):
var new_m = new Map<String,MalType>();
for (k in m.keys()) {
new_m[k] = m[k];
}
return new_m;
case _: throw "unsupported clone call";
}
}
public static function _macro_Q(x:MalType) {
return switch (x) {
case MalFunc(_,_,_,_,ismacro,_): ismacro;
case _: false;
}
}
public static function nil_Q(x:MalType) {
return switch (x) {
case MalNil: true;
case _: false;
}
}
public static function true_Q(x:MalType) {
return switch (x) {
case MalTrue: true;
case _: false;
}
}
public static function false_Q(x:MalType) {
return switch (x) {
case MalFalse: true;
case _: false;
}
}
public static function symbol_Q(x:MalType) {
return switch (x) {
case MalSymbol(_): true;
case _: false;
}
}
public static function keyword_Q(x:MalType) {
return switch (x) {
case MalString(s):
s.charAt(0) == "\x7f";
case _: false;
}
}
// Sequence operations
public static function list_Q(x:MalType) {
return switch (x) {
case MalList(_): true;
case _: false;
}
}
public static function vector_Q(x:MalType) {
return switch (x) {
case MalVector(_): true;
case _: false;
}
}
public static function first(seq:MalType) {
return switch (seq) {
case MalList(l) | MalVector(l):
if (l.length == 0) { nil; }
else { l[0]; }
case MalNil: MalNil;
case _: throw "first called on non-sequence";
}
}
public static function rest(seq:MalType) {
return switch (seq) {
case MalList(l) | MalVector(l):
if (l.length <= 1) { MalList([]); }
else { MalList(l.slice(1)); }
case MalNil: MalList([]);
case _: throw "rest called on non-sequence";
}
}
public static function _nth(seq:MalType, idx:Int) {
return switch (seq) {
case MalList(l) | MalVector(l):
if (l.length > idx) {
l[idx];
} else {
throw "nth index out of bounds";
}
case _: throw "nth called on non-sequence";
}
}
public static function _list(seq:MalType) {
return switch (seq) {
case MalList(l) | MalVector(l): l;
case _: throw "_array called on non-sequence";
}
}
public static function _map(hm:MalType) {
return switch (hm) {
case MalHashMap(m): m;
case _: throw "_map called on non-hash-map";
}
}
public static function last(seq:MalType) {
return switch (seq) {
case MalList(l) | MalVector(l):
if (l.length == 0) { nil; }
else { l[l.length-1]; }
case _: throw "last called on non-sequence";
}
}
public static function hash_map(kvs:Array<MalType>) {
var m = new Map<String,MalType>();
return MalHashMap(assoc_BANG(m, kvs));
}
public static function assoc_BANG(m:Map<String,MalType>,
kvs:Array<MalType>) {
for (i in 0...kvs.length) {
if (i % 2 > 0) { continue; }
switch (kvs[i]) {
case MalString(k):
m[k] = kvs[i+1];
case _: throw "invalid assoc! call";
}
}
return m;
}
public static function dissoc_BANG(m:Map<String,MalType>,
ks:Array<MalType>) {
for (i in 0...ks.length) {
switch (ks[i]) {
case MalString(k):
m.remove(k);
case _: throw "invalid dissoc! call";
}
}
return m;
}
public static function hash_map_Q(x:MalType) {
return switch (x) {
case MalHashMap(_): true;
case _: false;
}
}
public static function atom_Q(x:MalType) {
return switch (x) {
case MalAtom(_): true;
case _: false;
}
}
}