summaryrefslogtreecommitdiff
path: root/Build/source/utils/asymptote/table.h
blob: e8717cfa8edd72ca05ee5be7e62afb75d8a34e69 (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
134
135
136
137
138
139
140
141
/*****
 * table.h
 * Andy Hammerlindl 2002/06/18
 *
 * Table used to bind symbols to vars and types in a namespace.
 *****/

#ifndef TABLE_H
#define TABLE_H

#include <cassert>
#include <utility>

#include "symbol.h"
#include "common.h"

namespace sym {

template <class B>
class table;

template <class B>
std::ostream& operator<< (std::ostream& out, const table<B>& t);

template <class B>
class table {
protected:
  typedef mem::multimap<symbol*CONST,B> scope_t;
  typedef typename scope_t::iterator scope_iterator;
  typedef mem::list<scope_t> scopes_t;
  typedef mem::list<B> name_t;
  typedef typename name_t::iterator name_iterator;
  typedef mem::map<symbol*CONST,name_t> names_t;
  typedef typename names_t::iterator names_iterator;

  scopes_t scopes;
  names_t names;

  void remove(symbol *key);
public :
  table();

  void enter(symbol *key, B value);
  B look(symbol *key);

  // Checks if a symbol was added in the last scope.  Useful for
  // stopping multiple definitions.
  B lookInTopScope(symbol *key);

  // Allows scoping and overloading of symbols of the same name
  void beginScope();
  void endScope();

  // Copies all bindings in the top scope to the scope underneath it, and
  // removes the the top scope.
  void collapseScope();

  // Adds to l, all names prefixed by start.
  void completions(mem::list<symbol *>& l, string start);

  friend std::ostream& operator<< <B> (std::ostream& out, const table& t);
};

template <class B>
inline table<B>::table()
{
  beginScope();
}

template <class B>
inline void table<B>::enter(symbol *key, B value)
{
  scopes.front().insert(std::make_pair(key,value));
  names[key].push_front(value);
}

template <class B>
inline B table<B>::look(symbol *key)
{
  if (!names[key].empty())
    return names[key].front();
  return 0;
}

template <class B>
inline B table<B>::lookInTopScope(symbol *key)
{
  scope_iterator p = scopes.front().find(key);
  if (p!=scopes.front().end())
    return p->second;
  return 0;
}

template <class B>
inline void table<B>::beginScope()
{
  scopes.push_front(scope_t());
}

template <class B>
inline void table<B>::remove(symbol *key)
{
  if (!names[key].empty())
    names[key].pop_front();
}

template <class B>
inline void table<B>::endScope()
{
  scope_t &scope = scopes.front();
  for (scope_iterator p = scope.begin(); p != scope.end(); ++p)
    remove(p->first);
  scopes.pop_front();
}

template <class B>
inline void table<B>::collapseScope()
{
  scope_t scope = scopes.front();
  scopes.pop_front();

  scopes.front().insert(scope.begin(), scope.end());
}

// Returns true if start is a prefix for name; eg, mac is a prefix of machine.
inline bool prefix(string start, string name) {
  return equal(start.begin(), start.end(), name.begin());
}

template <class B>
inline void table<B>::completions(mem::list<symbol *>& l, string start)
{
  for (names_iterator p = names.begin(); p != names.end(); ++p)
    if (prefix(start, *(p->first)) && !p->second.empty())
      l.push_back(p->first);
}


} // namespace sym

#endif