1
1
mirror of https://github.com/kanaka/mal.git synced 2024-08-17 17:50:24 +03:00
mal/impls/vala/types.vala
Nicolas Boulenguez fbfe6784d2 Change quasiquote algorithm
- Add a `vec` built-in function in step7 so that `quasiquote` does not
  require `apply` from step9.
- Introduce quasiquoteexpand special in order to help debugging step7.
  This may also prepare newcomers to understand step8.
- Add soft tests.
- Do not quote numbers, strings and so on.

Should ideally have been in separate commits:
- elisp: simplify and fix (keyword :k)
- factor: fix copy/paste error in let*/step7, simplify eval-ast.
- guile: improve list/vector types
- haskell: revert evaluation during quasiquote
- logo, make: cosmetic issues
2020-08-11 01:01:56 +02:00

289 lines
8.3 KiB
Vala

public errordomain Mal.Error {
BAD_TOKEN,
PARSE_ERROR,
HASH_KEY_TYPE_ERROR,
ENV_LOOKUP_FAILED,
BAD_PARAMS,
CANNOT_APPLY,
EXCEPTION_THROWN,
NOT_IMPLEMENTED_IN_THIS_STEP,
}
abstract class Mal.Val : GC.Object {
public abstract bool truth_value();
}
abstract class Mal.Hashable : Mal.Val {
public string hashkey;
public static uint hash(Hashable h) { return str_hash(h.hashkey); }
public static bool equal(Hashable hl, Hashable hr) {
return hl.hashkey == hr.hashkey;
}
}
class Mal.Bool : Mal.Hashable {
public bool v;
public Bool(bool value) {
v = value;
hashkey = value ? "bt" : "bf";
}
public override bool truth_value() { return v; }
public override void gc_traverse(GC.Object.VisitorFunc visit) {}
}
// Mal.Listlike is a subclass of Mal.Val which includes both lists and
// vectors, and provides a common iterator API so that core functions
// and special forms can treat them the same.
//
// Most core functions that take a list argument also accept nil. To
// make that easy, Mal.Nil also derives from Mal.Listlike.
abstract class Mal.Listlike : Mal.ValWithMetadata {
public abstract Mal.Iterator iter();
}
abstract class Mal.Iterator : GLib.Object {
public abstract Mal.Val? deref();
public abstract Mal.Iterator step();
public bool empty() { return deref() == null; }
public bool nonempty() { return deref() != null; }
}
// ValWithMetadata is a subclass of Mal.Val which includes every value
// type you can put metadata on. Value types implementing this class
// must provide a copy() method, because with-meta has to make a copy
// of the value with new metadata.
abstract class Mal.ValWithMetadata : Mal.Val {
public Mal.Val? metadata;
construct {
metadata = null;
}
public abstract Mal.ValWithMetadata copy();
public abstract void gc_traverse_m(GC.Object.VisitorFunc visit);
public override void gc_traverse(GC.Object.VisitorFunc visit) {
visit(metadata);
gc_traverse_m(visit);
}
}
class Mal.Nil : Mal.Listlike {
public override bool truth_value() { return false; }
public override Mal.Iterator iter() { return new Mal.NilIterator(); }
public override Mal.ValWithMetadata copy() { return new Mal.Nil(); }
public override void gc_traverse_m(GC.Object.VisitorFunc visit) {}
}
class Mal.NilIterator : Mal.Iterator {
public override Mal.Val? deref() { return null; }
public override Mal.Iterator step() { return this; }
}
class Mal.List : Mal.Listlike {
public GLib.List<weak Val> vs;
public List(GLib.List<Val> values) {
foreach (var value in values) {
vs.append(value);
}
}
public List.empty() {
}
public override bool truth_value() { return true; }
public override Mal.Iterator iter() {
var toret = new Mal.ListIterator();
toret.node = vs;
return toret;
}
public override Mal.ValWithMetadata copy() {
return new Mal.List(vs);
}
public override void gc_traverse_m(GC.Object.VisitorFunc visit) {
foreach (var v in vs)
visit(v);
}
}
class Mal.ListIterator : Mal.Iterator {
public unowned GLib.List<Mal.Val>? node;
public override Mal.Val? deref() {
return node == null ? null : node.data;
}
public override Mal.Iterator step() {
if (node != null)
node = node.next;
return this;
}
}
class Mal.Vector : Mal.Listlike {
struct Ref { weak Mal.Val v; }
private Ref[] rs;
public Vector.from_list(GLib.List<Val> values) {
rs = new Ref[values.length()];
int i = 0;
foreach (var value in values) {
rs[i++] = { value };
}
}
public Vector.with_size(uint size) {
rs = new Ref[size];
}
private Vector.copy_of(Vector v) {
rs = v.rs;
}
public override bool truth_value() { return true; }
public override Mal.Iterator iter() {
var toret = new Mal.VectorIterator();
toret.vec = this;
toret.pos = 0;
return toret;
}
public override Mal.ValWithMetadata copy() {
return new Mal.Vector.copy_of(this);
}
public uint length { get { return rs.length; } }
public new Mal.Val @get(uint pos) {
assert(pos < rs.length);
return rs[pos].v;
}
public new void @set(uint pos, Mal.Val v) {
assert(pos < rs.length);
rs[pos].v = v;
}
public override void gc_traverse_m(GC.Object.VisitorFunc visit) {
foreach (var r in rs)
visit(r.v);
}
}
class Mal.VectorIterator : Mal.Iterator {
public Mal.Vector vec;
public int pos;
public override Mal.Val? deref() {
return pos >= vec.length ? null : vec[pos];
}
public override Mal.Iterator step() {
if (pos < vec.length) pos++;
return this;
}
}
class Mal.Num : Mal.Hashable {
public int64 v;
public Num(int64 value) {
v = value;
hashkey = "N" + v.to_string();
}
public override bool truth_value() { return true; }
public override void gc_traverse(GC.Object.VisitorFunc visit) {}
}
abstract class Mal.SymBase : Mal.Hashable {
public string v;
public override bool truth_value() { return true; }
public override void gc_traverse(GC.Object.VisitorFunc visit) {}
}
class Mal.Sym : Mal.SymBase {
public Sym(string value) {
v = value;
hashkey = "'" + v;
}
}
class Mal.Keyword : Mal.SymBase {
public Keyword(string value) {
v = value;
hashkey = ":" + v;
}
}
class Mal.String : Mal.Hashable {
public string v;
public String(string value) {
v = value;
hashkey = "\"" + v;
}
public override bool truth_value() { return true; }
public override void gc_traverse(GC.Object.VisitorFunc visit) {}
}
class Mal.Hashmap : Mal.ValWithMetadata {
public GLib.HashTable<weak Mal.Hashable, weak Mal.Val> vs;
construct {
vs = new GLib.HashTable<weak Mal.Hashable, weak Mal.Val>(
Mal.Hashable.hash, Mal.Hashable.equal);
}
public void insert(Mal.Val key, Mal.Val value) throws Mal.Error {
var hkey = key as Mal.Hashable;
if (hkey == null)
throw new Error.HASH_KEY_TYPE_ERROR("bad type as hash key");
vs[hkey] = value;
}
public void remove(Mal.Val key) throws Mal.Error {
var hkey = key as Mal.Hashable;
if (hkey == null)
throw new Error.HASH_KEY_TYPE_ERROR("bad type as hash key");
vs.remove(hkey);
}
public override bool truth_value() { return true; }
public override Mal.ValWithMetadata copy() {
var toret = new Mal.Hashmap();
toret.vs = vs;
return toret;
}
public override void gc_traverse_m(GC.Object.VisitorFunc visit) {
foreach (var key in vs.get_keys()) {
visit(key);
visit(vs[key]);
}
}
}
abstract class Mal.BuiltinFunction : Mal.ValWithMetadata {
public abstract string name();
public abstract Mal.Val call(Mal.List args) throws Mal.Error;
public override bool truth_value() { return true; }
public override void gc_traverse_m(GC.Object.VisitorFunc visit) {}
}
class Mal.Function : Mal.ValWithMetadata {
public bool is_macro;
#if !NO_ENV
public weak Mal.Listlike parameters;
public weak Mal.Val body;
public weak Mal.Env env;
public Function(Mal.Listlike parameters_, Mal.Val body_, Mal.Env env_) {
parameters = parameters_;
body = body_;
env = env_;
is_macro = false;
}
#endif
public override Mal.ValWithMetadata copy() {
#if !NO_ENV
var copied = new Mal.Function(parameters, body, env);
copied.is_macro = is_macro;
return copied;
#else
throw new Mal.Error.NOT_IMPLEMENTED_IN_THIS_STEP(
"can't copy a Mal.Function without Mal.Env existing");
#endif
}
public override bool truth_value() { return true; }
public override void gc_traverse_m(GC.Object.VisitorFunc visit) {
#if !NO_ENV
visit(parameters);
visit(body);
visit(env);
#endif
}
}
class Mal.Atom : Mal.Val {
public weak Mal.Val v;
public Atom(Mal.Val v_) { v = v_; }
public override bool truth_value() { return true; }
public override void gc_traverse(GC.Object.VisitorFunc visit) {
visit(v);
}
}