summaryrefslogtreecommitdiffstats
path: root/src/Term.vala
blob: 5c1c9686f65ada241bc333d336af9292eaeb569a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
namespace Eva {
  public interface Term : Object {
    public abstract string to_string();
    
    public bool equals(Term o) {
      return (match(o) != null);
    }
    
    public Gee.Map<string, Term>? match(Term o) {
      Gee.Map<string, Term> vars = new Gee.HashMap<string, Term>();
      Gee.Map<string, string> aliases = new Gee.HashMap<string, string>();
      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<string, Term> vars, Gee.Map<string, string> aliases);
    
    public abstract void encode(Erl.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);
    }
  }
}