summaryrefslogtreecommitdiff
path: root/st/SymbolTable.java
blob: bd76a13466c70388df320b4549f681e7e637f1aa (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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
package st;

import java.util.*;
import misc.*;
import heat.TypecheckException;

/**
 * Class which provides methods for interacting with and managing
 * the symbol table. Maintains context-awareness to keep the state
 * of each symbol consistent.
 */
public class SymbolTable {
    private HashMap<TokenKey,AbstractInstance> symt;    // the mapping of ids to Instances
    private HashMap<TypeEnum,AbstractInstance> active;  // the current scope of the visitor (class, method)

    public SymbolTable() {
        MinimalLogger.info("Creating a new SymbolTable...");
        this.symt = new HashMap<>();
        this.active = new HashMap<>();
    }

    @Override public String toString() {
        StringBuilder mapAsString = new StringBuilder("{");
        for (TokenKey key : this.symt.keySet()) {
            mapAsString.append(key.toString() + ":" + this.symt.get(key).getType() + ", ");
        }
        mapAsString.delete(mapAsString.length()-2, mapAsString.length()).append("}");
        return mapAsString.toString();
    }


    /**
     * Methods intended to be used during the first pass
     *
     * Will always throw a typecheck error when symbols are not distinct.
     */
    public void put(TokenKey id, AbstractInstance symbol) {
        MinimalLogger.info(String.format("Inserting %s -> %s",
                                         id,
                                         symbol.getType()));
        if (this.symt.get(id) != null)
            throw new TypecheckException(String.format("SymbolTable tried to place %s twice!",
                                                       id.toString()));
        this.symt.put(id, symbol);
    }


    /**
     * Methods intended to be used during the second pass
     */
    public void setExtend(String arg) {
        ClassInstance cls = (ClassInstance) this.active.get(TypeEnum.classname);
        ClassInstance ext = this.getClass(arg);

        MinimalLogger.info(String.format("%s found to extend %s",
                                         cls.getName(),
                                         ext.getName()));
        cls.setExtend(ext);
        TokenKey k;
        for (TypeInstance t : ext.getLocals()) {
            k = new TokenKey(t.getName(), TypeEnum.integer,
                             cls, null);
            if (this.symt.get(k) == null) {
                MinimalLogger.info(String.format("Added %s (%s) as a local var of %s (%s)",
                                                 t.getName(), t.getType(),
                                                 cls.getName(), cls.getType()));
                cls.addLocal(t);
                this.symt.put(k, t);
            } else { MinimalLogger.info(String.format("%s found to be overridden in %s.",
                                                      t.getName(), cls.getName())); }
        }
        for (MethodInstance m : ext.getMethods()) {
            k = new TokenKey(m.getName(), TypeEnum.method,
                             cls, null);
            if (this.symt.get(k) == null) {
                MinimalLogger.info(String.format("Added %s (%s) as a method of %s (%s)",
                                                 m.getName(), m.getType(),
                                                 cls.getName(), cls.getType()));
                this.symt.put(k, m);
                cls.addMethod(m);
            } else {
                MethodInstance exist = (MethodInstance) this.symt.get(k);
                ArrayList<TypeInstance> expected = exist.getArguments();
                ArrayList<TypeInstance> actual = m.getArguments();
                if (expected.size() != actual.size() ||
                    !exist.getReturn().equals(m.getReturn()))
                    throw new TypecheckException(String.format("SymbolTable found that %s is overwritten in %s!",
                                                               m.getName(),
                                                               cls.getName()));
                for (int i = 0; i < actual.size(); ++i) {
                    if (!expected.get(i).getClassInstance().equals(actual.get(i).getClassInstance())) {
                        throw new TypecheckException(String.format("SymbolTable found that %s is overwritten in %s!",
                                                                   m.getName(),
                                                                   cls.getName()));
                    }
                }

                MinimalLogger.info(String.format("%s found to be overridden in %s.",
                                                 m.getName(), cls.getName()));
            }
        }
    }

    public void addLocal(String lvar) {
        TypeInstance var = this.getType(lvar);
        AbstractInstance par;
        if (this.active.get(TypeEnum.method) != null) { // we are in a method
            MethodInstance par1 = (MethodInstance) this.active.get(TypeEnum.method);
            par1.addLocal(var);
            par = par1;
        } else {
            ClassInstance par1 = (ClassInstance) this.active.get(TypeEnum.classname);
            par1.addLocal(var);
            par = par1;
        }
        MinimalLogger.info(String.format("Added %s (%s) as a local var of %s (%s)",
                                         var.getName(), var.getType(),
                                         par.getName(), par.getType()));
    }

    public void addMethod(String mtd) {
        ClassInstance cls = (ClassInstance) this.active.get(TypeEnum.classname);
        MethodInstance lmtd = this.getMethod(mtd);

        cls.addMethod(lmtd);

        MinimalLogger.info(String.format("Added %s as a method of %s",
                                         lmtd.getName(), cls.getName()));
    }

    public void addParameter(String arg) {
        MethodInstance mtd = (MethodInstance) this.active.get(TypeEnum.method);
        TypeInstance para = this.getType(arg);

        mtd.addArgument(para); // also adds to local vars

        MinimalLogger.info(String.format("Added %s as a parameter of %s",
                                         para.getName(), mtd.getName()));
        MinimalLogger.info(String.format("Added %s as a localvar of %s",
                                         para.getName(), mtd.getName()));

    }

    public void addClassInstance(TypeInstance t, String c) {
        ClassInstance cls = (c != null) ?
            this.getClass(c) :
            null;

        if (cls != null)
            MinimalLogger.info(String.format("%s is an instance of class %s",
                                             t.getName(), c));
        t.addClassInstance(cls);
    }

    /**
     * Methods to safely retrieve differentiable types
     * in `typecheck', `vaporize' libraries
     */
    public void setActive(TypeEnum type, AbstractInstance id) {
        MinimalLogger.info(String.format("%s is now the active %s.",
                                         id.getName(),
                                         type));
        this.active.put(type, id);
    }

    public void removeActive(TypeEnum type) {
        AbstractInstance id = this.getActive(type);
        MinimalLogger.info(String.format("%s is no longer the active %s.",
                                         id.getName(),
                                         type));
        this.active.remove(type);
    }

    public TypeInstance getType(String name) {
        TokenKey id = new TokenKey(name,
                                   TypeEnum.integer,
                                   (ClassInstance) this.getActive(TypeEnum.classname),
                                   (MethodInstance) this.getActive(TypeEnum.method));
        AbstractInstance symbol;
        TypeInstance ret = ((symbol = this.symt.get(id)) !=
                            null && symbol instanceof TypeInstance) ?
            (TypeInstance) symbol : null;
        if (ret == null)
            MinimalLogger.severe(String.format("getType returning null for missing alias %s!",
                                               id));
        return ret;
    }

    public TypeInstance getTypeAttr(String name) {
        TokenKey id = new TokenKey(name,
                                   TypeEnum.integer,
                                   (ClassInstance) this.getActive(TypeEnum.classname),
                                   null);
        AbstractInstance symbol;
        TypeInstance ret = ((symbol = this.symt.get(id)) !=
                            null && symbol instanceof TypeInstance) ?
            (TypeInstance) symbol : null;
        if (ret == null)
            MinimalLogger.severe(String.format("getType returning null for missing alias %s!",
                                               id));
        return ret;
    }


    public MethodInstance getMethod(String name) {
        TokenKey id = new TokenKey(name,
                                   TypeEnum.method,
                                   (ClassInstance) this.getActive(TypeEnum.classname),
                                   null);
        AbstractInstance symbol;
        MethodInstance ret = ((symbol = this.symt.get(id)) !=
                              null && symbol instanceof MethodInstance) ?
            (MethodInstance) symbol : null;
        if (ret == null)
            MinimalLogger.severe(String.format("getMethod returning null for missing alias %s!",
                                               id));
        return ret;
    }

    public MethodInstance getMethod(String name, ClassInstance c) {
        TokenKey id = new TokenKey(name,
                                   TypeEnum.method,
                                   c,
                                   null);
        AbstractInstance symbol;
        MethodInstance ret = ((symbol = this.symt.get(id)) !=
                              null && symbol instanceof MethodInstance) ?
            (MethodInstance) symbol : null;
        if (ret == null)
            MinimalLogger.severe(String.format("getMethod returning null for missing alias %s!",
                                               id));
        return ret;
    }

    public ClassInstance getClass(String name) {
        TokenKey id = new TokenKey(name,
                                   TypeEnum.classname,
                                   null,
                                   null);
        AbstractInstance symbol;
        ClassInstance ret =  ((symbol = this.symt.get(id)) !=
                              null && symbol instanceof ClassInstance) ?
            (ClassInstance) symbol : null;
        if (ret == null)
            MinimalLogger.severe(String.format("getClass returning null for missing alias %s!",
                                               id));
        return ret;
    }

    public AbstractInstance getActive(TypeEnum type) {
        return this.active.get(type);
    }

}