summaryrefslogtreecommitdiffstats
path: root/src/Term.vala
blob: 6b0873052beb2a1cbc4545cf87951b18852d9a9f (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
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)
            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(array_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:
        List term = new List();
        
        assert(Erl.decode_list_header(buffer, ref index, out size) == 0);
        if(size != 0) {
          for(int i = 0; i < size; ++i) {
            term.list.add(do_decode(buffer, ref index));
          }
        
          term.tail = do_decode(buffer, ref index);
        }
        
        return term;
        
      case Erl.TermType.STRING:
        char[] value = new char[size+1];
        assert(Erl.decode_string(buffer, ref index, value) == 0);
        return new String(array_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();
      }
    }
  }
  
}