Project

General

Profile

root / trunk / compiler / ooasCompiler / src / org / momut / ooas / visitors / OoaCheckObjectRefsConstant.java @ 7

1
/**
2
  *
3
  *                      OOAS Compiler
4
  *
5
  *       Copyright 2015, AIT Austrian Institute of Technology.
6
  * This code is based on the C# Version of the OOAS Compiler, which is
7
  * copyright 2015 by the Institute of Software Technology, Graz University
8
  * of Technology with portions copyright by the AIT Austrian Institute of
9
  * Technology. All rights reserved.
10
  *
11
  * SEE THE "LICENSE" FILE FOR THE TERMS UNDER WHICH THIS FILE IS PROVIDED.
12
  *
13
  * If you modify the file please update the list of contributors below to in-
14
  * clude your name. Please also stick to the coding convention of using TABs
15
  * to do the basic (block-level) indentation and spaces for anything after
16
  * that. (Enable the display of special chars and it should be pretty obvious
17
  * what this means.) Also, remove all trailing whitespace.
18
  *
19
  * Contributors:
20
  *               Willibald Krenn (AIT)
21
  *               Stephan Zimmerer (AIT)
22
  *               Markus Demetz (AIT)
23
  *               Christoph Czurda (AIT)
24
  *
25
  */
26

    
27

    
28
package org.momut.ooas.visitors;
29

    
30
import java.util.ArrayList;
31
import java.util.HashSet;
32
import java.util.IdentityHashMap;
33

    
34
import org.momut.ooas.ast.expressions.CallExpression;
35
import org.momut.ooas.ast.expressions.Expression;
36
import org.momut.ooas.ast.expressions.IdentifierExpression;
37
import org.momut.ooas.ast.identifiers.FunctionIdentifier;
38
import org.momut.ooas.ast.identifiers.Identifier;
39
import org.momut.ooas.ast.identifiers.IdentifierKind;
40
import org.momut.ooas.ast.identifiers.MainModule;
41
import org.momut.ooas.ast.identifiers.MethodIdentifier;
42
import org.momut.ooas.ast.identifiers.NamedActionIdentifier;
43
import org.momut.ooas.ast.statements.Assignment;
44
import org.momut.ooas.ast.types.ListType;
45
import org.momut.ooas.ast.types.MapType;
46
import org.momut.ooas.ast.types.OoActionSystemType;
47
import org.momut.ooas.ast.types.TupleType;
48
import org.momut.ooas.ast.types.UlyssesType;
49
import org.momut.ooas.parser.ParserError;
50
import org.momut.ooas.parser.ParserMessage;
51
import org.momut.ooas.parser.ParserState;
52

    
53
/**
54
 *
55
 * @author KrennW
56
 *
57
 */
58
public final class OoaCheckObjectRefsConstant extends OoaCompleteAstTraversalVisitor {
59

    
60
        private static class CallGraphNode {
61
                public final FunctionIdentifier m_functionIdentifier;
62
                public final HashSet<CallGraphNode> m_calledFunctions;
63
                public final HashSet<CallGraphNode> m_callees;
64
                public boolean m_mayChangeObjectReferences;
65

    
66

    
67
                @Override
68
                public int hashCode() {
69
                        return m_functionIdentifier == null
70
                                ?  0
71
                                :  m_functionIdentifier.tokenText().hashCode();
72
                }
73

    
74
                @Override
75
                public boolean equals(Object obj) {
76
                        if (obj instanceof CallGraphNode) {
77
                                final CallGraphNode other = (CallGraphNode) obj;
78
                                return m_functionIdentifier != null
79
                                        ? m_functionIdentifier.tokenText().equals(other.m_functionIdentifier.tokenText())
80
                                        : m_functionIdentifier == other.m_functionIdentifier;
81
                        }
82
                        return false;
83
                }
84

    
85
                @Override
86
                public String toString() {
87
                        return m_functionIdentifier == null ? "<root>" : m_functionIdentifier.tokenText();
88
                }
89

    
90
                public CallGraphNode(FunctionIdentifier id) {
91
                        m_functionIdentifier = id;
92
                        m_calledFunctions = new HashSet<>();
93
                        m_callees = new HashSet<>();
94
                        m_mayChangeObjectReferences = false;
95
                }
96
        }
97

    
98

    
99
        /** null (root-do/od block), or an action or method that is currently being parsed. */
100
        private final ArrayList<FunctionIdentifier> m_currentFunction;
101
        /** Maps FunctionIdentifiers to the CallGraphNode data structure. */
102
        private final IdentityHashMap<String, CallGraphNode> m_callGraph;
103

    
104

    
105
        /** Adds a new CallGraphNode to the callgraph if necessary. Returns the node. */
106
        private CallGraphNode addCallGraphNode(FunctionIdentifier anIdentifier) {
107
                if (anIdentifier != null) {
108
                        final String token = anIdentifier.tokenText().intern();
109
                        if (!m_callGraph.containsKey(token)) {
110
                                m_callGraph.put(token, new CallGraphNode(anIdentifier));
111
                        }
112
                        return m_callGraph.get(token);
113
                }
114

    
115
                if (!m_callGraph.containsKey(null)) {
116
                        m_callGraph.put(null, new CallGraphNode(null));
117
                }
118
                return m_callGraph.get(null);
119
        }
120

    
121
        /** adds a link to the callgraph */
122
        private void addCalledFunction(CallGraphNode aNode) {
123
                final FunctionIdentifier fi = m_currentFunction.get(m_currentFunction.size() -1);
124
                if (fi != null && !m_callGraph.containsKey(fi.tokenText().intern()))
125
                        addCallGraphNode(fi);
126
                final CallGraphNode currNode = fi == null ? m_callGraph.get(null) : m_callGraph.get(fi.tokenText().intern());
127
                aNode.m_callees.add(currNode);
128
                currNode.m_calledFunctions.add(aNode);
129
        }
130

    
131
        private void setMayChangeObjectRefs() {
132
                final FunctionIdentifier fi = m_currentFunction.get(m_currentFunction.size() -1);
133
                CallGraphNode node = m_callGraph.get(fi);
134
                if (node == null)
135
                        node = addCallGraphNode(fi);
136
                node.m_mayChangeObjectReferences = true;
137
        }
138

    
139
        private void check(TupleType type) {
140
                for (final UlyssesType t: type.innerTypes())
141
                        switch (t.kind()) {
142
                        case ListType:
143
                                check( (ListType) t);
144
                                break;
145
                        case MapType:
146
                                check( (MapType) t);
147
                                break;
148
                        case TupleType:
149
                                check( (TupleType) t);
150
                                break;
151
                        case OoActionSystemType:
152
                                setMayChangeObjectRefs();
153
                                return;
154
                        default:
155
                                break;
156
                        }
157
        }
158

    
159
        private void check(MapType type) {
160
                throw new RuntimeException("OoaCheckObjectRefsConstant pass does not support MapTypes.");
161
        }
162

    
163
        private void check(ListType type) {
164
                switch (type.innerType().kind()) {
165
                case ListType:
166
                        check( (ListType) type.innerType());
167
                        break;
168
                case MapType:
169
                        check( (MapType) type.innerType());
170
                        break;
171
                case TupleType:
172
                        check( (TupleType) type.innerType());
173
                        break;
174
                case OoActionSystemType:
175
                        setMayChangeObjectRefs();
176
                        return;
177
                default:
178
                        break;
179
                }
180
        }
181

    
182
        private IdentifierExpression m_lastIdentifier = null;
183

    
184
        @Override
185
        public void visit(IdentifierExpression identifierExpression) {
186
                m_lastIdentifier = identifierExpression;
187
        }
188

    
189
        @Override
190
        public void visit(Assignment assignment) {
191
                for (final Expression e: assignment.values())
192
                        VisitSub(e, assignment);
193
                for (final Expression e: assignment.places()) {
194
                        m_lastIdentifier = null;
195
                        VisitSub(e, assignment);
196
                        if (m_lastIdentifier.identifier().kind() == IdentifierKind.AttributeIdentifier)
197
                                switch(e.type().kind()) {
198
                                        case ListType:
199
                                                check( (ListType) e.type());
200
                                                break;
201
                                        case MapType:
202
                                                check( (MapType) e.type());
203
                                                break;
204
                                        case TupleType:
205
                                                check( (TupleType) e.type() );
206
                                                break;
207
                                        case OoActionSystemType:
208
                                                setMayChangeObjectRefs();
209
                                                break;
210
                                        default:
211
                                                break;
212
                                }
213
                }
214
        }
215

    
216
        @Override
217
        public void visit(CallExpression callExpression) {
218
                for (final FunctionIdentifier f: callExpression.callTargets())
219
                        addCalledFunction(addCallGraphNode(f));
220
                super.visit(callExpression);
221
        }
222

    
223

    
224
        @Override
225
        public void visit(MethodIdentifier methodIdentifier) {
226
                m_currentFunction.add(methodIdentifier);
227
                try {
228
                        addCallGraphNode(methodIdentifier);
229
                        super.visit(methodIdentifier);
230
                } finally {
231
                        m_currentFunction.remove(m_currentFunction.size() -1);
232
                }
233
        }
234

    
235
        @Override
236
        public void visit(NamedActionIdentifier actionIdentifier){
237
                m_currentFunction.add(actionIdentifier);
238
                try {
239
                        addCallGraphNode(actionIdentifier);
240
                        super.visit(actionIdentifier);
241
                } finally {
242
                        m_currentFunction.remove(m_currentFunction.size() -1);
243
                }
244
        }
245

    
246
        @Override
247
        public void visit(OoActionSystemType ooActionSystemType) {
248
                for (final Identifier s: ooActionSystemType.symbols().symbolList())
249
                        VisitSub(s, ooActionSystemType);
250

    
251
                m_currentFunction.add(null);
252
                try {
253
                        VisitSub(ooActionSystemType.doOdBlock(), ooActionSystemType);
254
                } finally {
255
                        m_currentFunction.remove(m_currentFunction.size() -1);
256
                }
257
        }
258

    
259
        @Override
260
        public void visit(MainModule mainModule) {
261
                super.visit(mainModule);
262
                // forward information..
263
                for (final CallGraphNode n: m_callGraph.values())
264
                        promoteChangeInfo(n);
265
                final CallGraphNode root = m_callGraph.get(null);
266
                if (root.m_mayChangeObjectReferences) {
267
                        // check that only the initialize function changes object refs..
268
                        final StringBuilder b = new StringBuilder();
269
                        b.append("The following functions (all action systems merged) potentially change object references:");
270
                        b.append(System.lineSeparator());
271
                        printCandidates(root, 1,b);
272
                        m_ParserState.AddMessage(new ParserMessage("",0,0, b.toString()));
273
                        for (final CallGraphNode n: root.m_calledFunctions)
274
                                if (n.m_mayChangeObjectReferences && !n.toString().equals("initialize")) {
275
                                        m_ParserState.AddErrorMessage(new ParserError("", 0, 0,
276
                                                "Only \"initialize\" is allowed to change object references when using the symbolic solver."));
277
//                                        System.out.println(b.toString());
278
                                        break;
279
                                }
280
                }
281
        }
282

    
283
        private void printCandidates(CallGraphNode root, int level, StringBuilder msg) {
284
                for (final CallGraphNode n: root.m_calledFunctions) {
285
                        if (n.m_mayChangeObjectReferences) {
286
                                for (int i = 0; i < level; i++)
287
                                        msg.append("\t");
288
                                msg.append(n.m_functionIdentifier.toString());
289
                                msg.append(System.lineSeparator());
290
                                printCandidates(n, level + 1, msg);
291
                        }
292
                }
293
        }
294

    
295
        private void promoteChangeInfo(CallGraphNode n) {
296
                if (n.m_mayChangeObjectReferences) {
297
                        for (final CallGraphNode c: n.m_callees) {
298
                                if (!c.m_mayChangeObjectReferences) {
299
                                        c.m_mayChangeObjectReferences = true;
300
                                        if (!c.m_calledFunctions.contains(n))
301
                                                System.out.println("Bug.");
302
                                        promoteChangeInfo(c);
303
                                }
304
                        }
305
                }
306
        }
307

    
308
        public OoaCheckObjectRefsConstant(ParserState aState) {
309
                super(aState);
310
                m_callGraph = new IdentityHashMap<>();
311
                m_currentFunction = new ArrayList<>();
312
                m_currentFunction.add(null);
313
                addCallGraphNode(null);  // add root elem.
314
        }
315
}