namespace Eva { public interface Term : Object { public abstract string to_string(); public bool equals(Term o) { return (match(o) != null); } public Gee.Map? match(Term o) { Gee.Map vars = new Gee.HashMap(); Gee.Map aliases = new Gee.HashMap(); if(!do_match(o, vars, aliases)) { return null; } else { foreach(string a in aliases.keys) { string v = Var.alias(a, aliases); if(v in vars.keys) vars[a] = vars[v]; } return vars; } } protected abstract bool do_match(Term o, Gee.Map vars, Gee.Map aliases); internal abstract void encode(Buffer buffer); public static Term decode(void *buffer) { int index = 0; int version; Erl.decode_version(buffer, ref index, out version); return do_decode(buffer, ref index); } private static Term do_decode(void *buffer, ref int index) { int type, size; assert(Erl.get_type(buffer, ref index, out type, out size) == 0); switch(type) { case Erl.TermType.SMALL_INTEGER: char value; assert(Erl.decode_char(buffer, ref index, out value) == 0); return new Int((uchar)value); case Erl.TermType.INTEGER: long value; assert(Erl.decode_long(buffer, ref index, out value) == 0); return new Int(value); case Erl.TermType.FLOAT: double value; assert(Erl.decode_double(buffer, ref index, out value) == 0); return new Double(value); case Erl.TermType.ATOM: char[] value = new char[size+1]; assert(Erl.decode_atom(buffer, ref index, value) == 0); return new Atom(binary_to_string(value, size)); case Erl.TermType.SMALL_TUPLE: case Erl.TermType.LARGE_TUPLE: assert(Erl.decode_tuple_header(buffer, ref index, out size) == 0); Term[] terms = new Term[size]; for(int i = 0; i < size; ++i) { terms[i] = do_decode(buffer, ref index); } return new Tuple(terms); case Erl.TermType.NIL: case Erl.TermType.LIST: assert(Erl.decode_list_header(buffer, ref index, out size) == 0); if(size == 0) { return List.empty; } else { return decode_list(buffer, ref index, size); } case Erl.TermType.STRING: char[] value = new char[size+1]; assert(Erl.decode_string(buffer, ref index, value) == 0); return new String(binary_to_string(value, size)); case Erl.TermType.BINARY: char[] value = new char[size]; long l; assert(Erl.decode_binary(buffer, ref index, value, out l) == 0); return new Binary(value); case Erl.TermType.PID: Erl.Pid value; assert(Erl.decode_pid(buffer, ref index, out value) == 0); return new Pid(value); case Erl.TermType.PORT: Erl.Port value; assert(Erl.decode_port(buffer, ref index, out value) == 0); return new Port(value); case Erl.TermType.REFERENCE: case Erl.TermType.NEW_REFERENCE: Erl.Ref value; assert(Erl.decode_ref(buffer, ref index, out value) == 0); return new Ref(value); default: assert_not_reached(); } } private static List decode_list(void *buffer, ref int index, int n) { Term head = do_decode(buffer, ref index); Term tail; if(n > 1) { tail = decode_list(buffer, ref index, n-1); } else { tail = do_decode(buffer, ref index); } return new Cons(head, tail); } } }