Method: typeCheckLet(INode, LinkedList, INode, TypeCheckInfo)

1: /*
2: * #%~
3: * The VDM Type Checker
4: * %%
5: * Copyright (C) 2008 - 2014 Overture
6: * %%
7: * This program is free software: you can redistribute it and/or modify
8: * it under the terms of the GNU General Public License as
9: * published by the Free Software Foundation, either version 3 of the
10: * License, or (at your option) any later version.
11: *
12: * This program is distributed in the hope that it will be useful,
13: * but WITHOUT ANY WARRANTY; without even the implied warranty of
14: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15: * GNU General Public License for more details.
16: *
17: * You should have received a copy of the GNU General Public
18: * License along with this program. If not, see
19: * <http://www.gnu.org/licenses/gpl-3.0.html>.
20: * #~%
21: */
22: package org.overture.typechecker.visitor;
23:
24: import java.util.LinkedList;
25: import java.util.List;
26: import java.util.Map;
27: import java.util.Vector;
28:
29: import org.overture.ast.analysis.AnalysisException;
30: import org.overture.ast.analysis.QuestionAnswerAdaptor;
31: import org.overture.ast.analysis.intf.IQuestionAnswer;
32: import org.overture.ast.annotations.PAnnotation;
33: import org.overture.ast.definitions.AExplicitFunctionDefinition;
34: import org.overture.ast.definitions.AMultiBindListDefinition;
35: import org.overture.ast.definitions.PDefinition;
36: import org.overture.ast.definitions.SClassDefinition;
37: import org.overture.ast.expressions.PExp;
38: import org.overture.ast.factory.AstFactory;
39: import org.overture.ast.intf.lex.ILexLocation;
40: import org.overture.ast.modules.AModuleModules;
41: import org.overture.ast.node.INode;
42: import org.overture.ast.patterns.PMultipleBind;
43: import org.overture.ast.statements.PStm;
44: import org.overture.ast.typechecker.NameScope;
45: import org.overture.ast.types.ABooleanBasicType;
46: import org.overture.ast.types.PType;
47: import org.overture.ast.util.PTypeSet;
48: import org.overture.typechecker.Environment;
49: import org.overture.typechecker.FlatCheckedEnvironment;
50: import org.overture.typechecker.TypeCheckInfo;
51: import org.overture.typechecker.TypeCheckerErrors;
52: import org.overture.typechecker.annotations.TCAnnotation;
53: import org.overture.typechecker.utilities.type.QualifiedDefinition;
54:
55: public class AbstractTypeCheckVisitor extends
56:                 QuestionAnswerAdaptor<TypeCheckInfo, PType>
57: {
58:
59:         public AbstractTypeCheckVisitor(
60:                         IQuestionAnswer<TypeCheckInfo, PType> visitor)
61:         {
62:                 super(visitor);
63:         }
64:
65:         public AbstractTypeCheckVisitor()
66:         {
67:                 super();
68:         }
69:
70:         @Override
71:         public PType createNewReturnValue(INode node, TypeCheckInfo question)
72:         {
73:                 return null;
74:         }
75:
76:         @Override
77:         public PType createNewReturnValue(Object node, TypeCheckInfo question)
78:         {
79:                 return null;
80:         }
81:
82:         @Override
83:         public PType defaultINode(INode node, TypeCheckInfo question)
84:                         throws AnalysisException
85:         {
86:                 return THIS.defaultINode(node, question);
87:         }
88:
89:         protected PType typeCheckIf(ILexLocation ifLocation, PExp testExp,
90:                         INode thenNode, List<? extends INode> elseIfNodeList,
91:                         INode elseNode, TypeCheckInfo question) throws AnalysisException
92:         {
93:                 boolean isExpression = testExp.parent() instanceof PExp;
94:
95:                 question.qualifiers = null;
96:
97:                 PType test = testExp.apply(THIS, question.newConstraint(null));
98:
99:                 if (!question.assistantFactory.createPTypeAssistant().isType(test, ABooleanBasicType.class))
100:                 {
101:                         TypeCheckerErrors.report((isExpression ? 3108 : 3224), "If expression is not boolean", testExp.getLocation(), testExp);
102:                 }
103:
104:                 List<QualifiedDefinition> qualified = testExp.apply(question.assistantFactory.getQualificationVisitor(), question);
105:
106:                 for (QualifiedDefinition qdef : qualified)
107:                 {
108:                         qdef.qualifyType();
109:                 }
110:
111:                 PTypeSet rtypes = new PTypeSet(question.assistantFactory);
112:                 question.qualifiers = null;
113:                 rtypes.add(thenNode.apply(THIS, question));
114:
115:                 for (QualifiedDefinition qdef : qualified)
116:                 {
117:                         qdef.resetType();
118:                 }
119:
120:                 if (elseIfNodeList != null)
121:                 {
122:                         for (INode stmt : elseIfNodeList)
123:                         {
124:                                 question.qualifiers = null;
125:                                 rtypes.add(stmt.apply(THIS, question));
126:                         }
127:                 }
128:
129:                 if (elseNode != null)
130:                 {
131:                         question.qualifiers = null;
132:                         rtypes.add(elseNode.apply(THIS, question));
133:                 } else
134:                 {
135:                         // If the else case is empty then it is a statement and its type is void
136:                         rtypes.add(AstFactory.newAVoidType(ifLocation));
137:                         question.assistantFactory.createPTypeAssistant().checkReturnType(question.returnType, rtypes.getType(ifLocation), question.mandatory, ifLocation);
138:                 }
139:
140:                 return rtypes.getType(ifLocation);
141:
142:         }
143:
144:         /**
145:          * Type checks a AElseIf node
146:          *
147:          * @param elseIfNode
148:          * @param elseIfLocation
149:          * @param test
150:          * @param thenNode
151:          * @param question
152:          * @return
153:          * @throws AnalysisException
154:          */
155:         PType typeCheckAElseIf(INode elseIfNode, ILexLocation elseIfLocation,
156:                         INode test, INode thenNode, TypeCheckInfo question)
157:                         throws AnalysisException
158:         {
159:                 if (!question.assistantFactory.createPTypeAssistant().isType(test.apply(THIS, question.newConstraint(null)), ABooleanBasicType.class))
160:                 {
161:                         boolean isExpression = elseIfNode.parent() instanceof PExp;
162:                         TypeCheckerErrors.report((isExpression ? 3086 : 3218), "Expression is not boolean", elseIfLocation, elseIfNode);
163:                 }
164:
165:                 List<QualifiedDefinition> qualified = test.apply(question.assistantFactory.getQualificationVisitor(), question);
166:
167:                 for (QualifiedDefinition qdef : qualified)
168:                 {
169:                         qdef.qualifyType();
170:                 }
171:
172:                 PType type = thenNode.apply(THIS, question);
173:
174:                 for (QualifiedDefinition qdef : qualified)
175:                 {
176:                         qdef.resetType();
177:                 }
178:
179:                 return type;
180:         }
181:
182:         PType typeCheckANotYetSpecifiedExp(INode node, ILexLocation location)
183:         {
184:                 return AstFactory.newAUnknownType(location);// Because we terminate anyway
185:         }
186:
187:         /**
188:          * Type checks a let node
189:          *
190:          * @param node
191:          * @param localDefs
192:          * @param body
193:          * @param question
194:          * @return
195:          * @throws AnalysisException
196:          */
197:         protected PType typeCheckLet(INode node, LinkedList<PDefinition> localDefs,
198:                         INode body, TypeCheckInfo question) throws AnalysisException
199:         {
200:                 // Each local definition is in scope for later local definitions...
201:                 Environment local = question.env;
202:
203:•                for (PDefinition d : localDefs)
204:                 {
205:•                        if (d instanceof AExplicitFunctionDefinition)
206:                         {
207:                                 // Functions' names are in scope in their bodies, whereas
208:                                 // simple variable declarations aren't
209:
210:                                 local = new FlatCheckedEnvironment(question.assistantFactory, d, local, question.scope); // cumulative
211:                                 question.assistantFactory.createPDefinitionAssistant().implicitDefinitions(d, local);
212:
213:                                 question.assistantFactory.createPDefinitionAssistant().typeResolve(d, THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, question.qualifiers));
214:
215:•                                if (question.env.isVDMPP())
216:                                 {
217:                                         SClassDefinition cdef = question.env.findClassDefinition();
218:                                         // question.assistantFactory.createPDefinitionAssistant().setClassDefinition(d, cdef);
219:                                         d.setClassDefinition(cdef);
220:                                         d.setAccess(question.assistantFactory.createPAccessSpecifierAssistant().getStatic(d, true));
221:                                 }
222:
223:                                 d.apply(THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, question.qualifiers));
224:                         } else
225:                         {
226:                                 question.assistantFactory.createPDefinitionAssistant().implicitDefinitions(d, local);
227:                                 question.assistantFactory.createPDefinitionAssistant().typeResolve(d, THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, question.qualifiers));
228:                                 d.apply(THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope).newModule(question.fromModule));
229:                                 local = new FlatCheckedEnvironment(question.assistantFactory, d, local, question.scope); // cumulative
230:                         }
231:                 }
232:
233:                 PType r = body.apply(THIS, new TypeCheckInfo(question.assistantFactory, local, question.scope, null, question.constraint, null, question.fromModule, question.mandatory));
234:                 local.unusedCheck(question.env);
235:                 return r;
236:         }
237:
238:         /**
239:          * Type check method for let be such that
240:          * @param node
241:          * @param nodeLocation
242:          * @param bind
243:          * @param suchThat
244:          * @param body
245:          * @param question
246:          * @return a pair of the type and definition
247:          * @throws AnalysisException
248:          */
249:         protected Map.Entry<PType, AMultiBindListDefinition> typecheckLetBeSt(
250:                         INode node, ILexLocation nodeLocation, PMultipleBind bind,
251:                         PExp suchThat, INode body, TypeCheckInfo question)
252:                         throws AnalysisException
253:         {
254:                 final PDefinition def = AstFactory.newAMultiBindListDefinition(nodeLocation, question.assistantFactory.createPMultipleBindAssistant().getMultipleBindList((PMultipleBind) bind));
255:
256:                 def.apply(THIS, question.newConstraint(null));
257:                 
258:                 List<PDefinition> qualified = new Vector<PDefinition>();
259:                 
260:                 for (PDefinition d: question.assistantFactory.createPDefinitionAssistant().getDefinitions(def))
261:                 {
262:                         PDefinition copy = d.clone();
263:                         copy.setNameScope(NameScope.LOCAL);
264:                         qualified.add(copy);
265:                 }
266:                 
267:                 Environment local = new FlatCheckedEnvironment(question.assistantFactory, qualified, question.env, question.scope);
268:
269:                 TypeCheckInfo newInfo = new TypeCheckInfo(question.assistantFactory, local, question.scope, question.qualifiers, question.constraint, null, question.fromModule, question.mandatory);
270:
271:                 if (suchThat != null
272:                                 && !question.assistantFactory.createPTypeAssistant().isType(suchThat.apply(THIS, newInfo.newConstraint(null)), ABooleanBasicType.class))
273:                 {
274:                         boolean isExpression = node instanceof PExp;
275:                         TypeCheckerErrors.report((isExpression ? 3117 : 3225), "Such that clause is not boolean", nodeLocation, node);
276:                 }
277:
278:                 newInfo.qualifiers = null;
279:                 final PType r = body.apply(THIS, newInfo);
280:                 local.unusedCheck();
281:
282:                 return new Map.Entry<PType, AMultiBindListDefinition>()
283:                 {
284:
285:                         @Override
286:                         public AMultiBindListDefinition setValue(
287:                                         AMultiBindListDefinition value)
288:                         {
289:                                 return null;
290:                         }
291:
292:                         @Override
293:                         public AMultiBindListDefinition getValue()
294:                         {
295:                                 return (AMultiBindListDefinition) def;
296:                         }
297:
298:                         @Override
299:                         public PType getKey()
300:                         {
301:                                 return r;
302:                         }
303:                 };
304:         }
305:         
306:         /**
307:          * Annotation before processing.
308:          */
309:         
310:         protected void beforeAnnotations(List<PAnnotation> annotations, INode node, TypeCheckInfo question) throws AnalysisException
311:         {
312:                 for (PAnnotation annotation: annotations)
313:                 {
314:                         beforeAnnotation(annotation, node, question);
315:                 }
316:         }
317:         
318:         protected void beforeAnnotation(PAnnotation annotation, INode node, TypeCheckInfo question)
319:         {
320:                 if (annotation.getImpl() instanceof TCAnnotation)
321:                 {
322:                         TCAnnotation impl = (TCAnnotation)annotation.getImpl();
323:                         
324:                         // This is not as ugly as multiple overloaded beforeAnotation and beforeAnnotations!
325:                         if (node instanceof PDefinition)
326:                         {
327:                                 impl.tcBefore((PDefinition)node, question);
328:                         }
329:                         else if (node instanceof PExp)
330:                         {
331:                                 impl.tcBefore((PExp)node, question);
332:                         }
333:                         else if (node instanceof PStm)
334:                         {
335:                                 impl.tcBefore((PStm)node, question);
336:                         }
337:                         else if (node instanceof AModuleModules)
338:                         {
339:                                 impl.tcBefore((AModuleModules)node, question);
340:                         }
341:                         else if (node instanceof SClassDefinition)
342:                         {
343:                                 impl.tcBefore((SClassDefinition)node, question);
344:                         }
345:                         else
346:                         {
347:                                 System.err.println("Cannot apply annoation to " + node.getClass().getSimpleName());
348:                         }
349:                 }
350:         }
351:         
352:         /**
353:          * After annotation processing.
354:          */
355:         
356:         protected void afterAnnotations(List<PAnnotation> annotations, INode node, TypeCheckInfo question) throws AnalysisException
357:         {
358:                 for (PAnnotation annotation: annotations)
359:                 {
360:                         afterAnnotation(annotation, node, question);
361:                 }
362:         }
363:
364:         protected void afterAnnotation(PAnnotation annotation, INode node, TypeCheckInfo question)
365:         {
366:                 if (annotation.getImpl() instanceof TCAnnotation)
367:                 {
368:                         TCAnnotation impl = (TCAnnotation)annotation.getImpl();
369:                         
370:                         // This is not as ugly as multiple overloaded beforeAnotation and beforeAnnotations!
371:                         if (node instanceof PDefinition)
372:                         {
373:                                 impl.tcAfter((PDefinition)node, question);
374:                         }
375:                         else if (node instanceof PExp)
376:                         {
377:                                 impl.tcAfter((PExp)node, question);
378:                         }
379:                         else if (node instanceof PStm)
380:                         {
381:                                 impl.tcAfter((PStm)node, question);
382:                         }
383:                         else if (node instanceof AModuleModules)
384:                         {
385:                                 impl.tcAfter((AModuleModules)node, question);
386:                         }
387:                         else if (node instanceof SClassDefinition)
388:                         {
389:                                 impl.tcAfter((SClassDefinition)node, question);
390:                         }
391:                         else
392:                         {
393:                                 System.err.println("Cannot apply annoation to " + node.getClass().getSimpleName());
394:                         }
395:                 }
396:         }
397: }