Method: asSortedList(Set)

1: /*
2: * #%~
3: * VDM Code Generator
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.codegen.utils;
23:
24: import java.io.BufferedReader;
25: import java.io.File;
26: import java.io.FileInputStream;
27: import java.io.FileOutputStream;
28: import java.io.FileReader;
29: import java.io.FileWriter;
30: import java.io.IOException;
31: import java.io.InputStream;
32: import java.io.OutputStream;
33: import java.util.Collections;
34: import java.util.LinkedList;
35: import java.util.List;
36: import java.util.Set;
37:
38: import org.overture.ast.analysis.AnalysisException;
39: import org.overture.ast.analysis.DepthFirstAnalysisAdaptor;
40: import org.overture.ast.definitions.SClassDefinition;
41: import org.overture.ast.expressions.PExp;
42: import org.overture.ast.factory.AstFactory;
43: import org.overture.ast.intf.lex.ILexLocation;
44: import org.overture.ast.intf.lex.ILexNameToken;
45: import org.overture.ast.lex.Dialect;
46: import org.overture.ast.lex.LexLocation;
47: import org.overture.ast.lex.LexNameToken;
48: import org.overture.ast.node.INode;
49: import org.overture.ast.typechecker.NameScope;
50: import org.overture.ast.types.AVoidType;
51: import org.overture.ast.util.definitions.ClassList;
52: import org.overture.codegen.analysis.vdm.Renaming;
53: import org.overture.codegen.analysis.violations.InvalidNamesResult;
54: import org.overture.codegen.analysis.violations.Violation;
55: import org.overture.codegen.assistant.AssistantManager;
56: import org.overture.codegen.assistant.LocationAssistantIR;
57: import org.overture.codegen.ir.ITempVarGen;
58: import org.overture.codegen.ir.IrNodeInfo;
59: import org.overture.codegen.ir.VdmNodeInfo;
60: import org.overture.codegen.printer.MsgPrinter;
61: import org.overture.parser.lex.LexException;
62: import org.overture.parser.lex.LexTokenReader;
63: import org.overture.parser.messages.Console;
64: import org.overture.parser.messages.VDMError;
65: import org.overture.parser.messages.VDMErrorsException;
66: import org.overture.parser.messages.VDMWarning;
67: import org.overture.parser.syntax.ClassReader;
68: import org.overture.parser.syntax.ExpressionReader;
69: import org.overture.parser.syntax.ParserException;
70: import org.overture.parser.util.ParserUtil;
71: import org.overture.parser.util.ParserUtil.ParserResult;
72: import org.overture.typechecker.ClassTypeChecker;
73: import org.overture.typechecker.Environment;
74: import org.overture.typechecker.PublicClassEnvironment;
75: import org.overture.typechecker.TypeCheckInfo;
76: import org.overture.typechecker.TypeChecker;
77: import org.overture.typechecker.assistant.TypeCheckerAssistantFactory;
78: import org.overture.typechecker.util.TypeCheckerUtil;
79: import org.overture.typechecker.util.TypeCheckerUtil.TypeCheckResult;
80: import org.overture.typechecker.visitor.TypeCheckVisitor;
81:
82: public class GeneralCodeGenUtils
83: {
84:         private static final String LINE_SEPARATOR = System.getProperty("line.separator");
85:
86:         public static boolean isVdmSourceFile(File f)
87:         {
88:                 return isVdmPpSourceFile(f) || isVdmSlSourceFile(f)
89:                                 || isVdmRtSourceFile(f);
90:         }
91:
92:         public static boolean isVdmRtSourceFile(File f)
93:         {
94:                 return hasExtension(f, new String[] { ".vdmrt", ".vrt" });
95:         }
96:
97:         public static boolean isVdmSlSourceFile(File f)
98:         {
99:                 return hasExtension(f, new String[] { ".vsl", ".vdmsl" });
100:         }
101:
102:         public static boolean isVdmPpSourceFile(File f)
103:         {
104:                 return hasExtension(f, new String[] { ".vdmpp", ".vpp" });
105:         }
106:
107:         private static boolean hasExtension(File f, String[] extensions)
108:         {
109:                 for (String ext : extensions)
110:                 {
111:                         if (f.getName().endsWith(ext))
112:                         {
113:                                 return true;
114:                         }
115:                 }
116:
117:                 return false;
118:         }
119:
120:         public static String errorStr(TypeCheckResult<?> tcResult)
121:         {
122:                 if (tcResult == null)
123:                 {
124:                         return "No type check result found!";
125:                 }
126:
127:                 StringBuilder sb = new StringBuilder();
128:
129:                 if (!tcResult.parserResult.warnings.isEmpty())
130:                 {
131:                         sb.append("Parser warnings:").append('\n');
132:                         for (VDMWarning w : tcResult.parserResult.warnings)
133:                         {
134:                                 sb.append(w).append('\n');
135:                         }
136:                         sb.append('\n');
137:                 }
138:
139:                 if (!tcResult.parserResult.errors.isEmpty())
140:                 {
141:                         sb.append("Parser errors:").append('\n');
142:                         for (VDMError e : tcResult.parserResult.errors)
143:                         {
144:                                 sb.append(e).append('\n');
145:                         }
146:                         sb.append('\n');
147:                 }
148:
149:                 if (!tcResult.warnings.isEmpty())
150:                 {
151:                         sb.append("Type check warnings:").append('\n');
152:                         for (VDMWarning w : tcResult.warnings)
153:                         {
154:                                 sb.append(w).append('\n');
155:                         }
156:                         sb.append('\n');
157:                 }
158:
159:                 if (!tcResult.errors.isEmpty())
160:                 {
161:                         sb.append("Type check errors:").append('\n');
162:                         for (VDMError w : tcResult.errors)
163:                         {
164:                                 sb.append(w).append('\n');
165:                         }
166:                         sb.append('\n');
167:                 }
168:
169:                 return sb.toString();
170:         }
171:
172:         public static TypeCheckResult<PExp> validateExp(String exp)
173:                         throws AnalysisException
174:         {
175:                 if (exp == null || exp.isEmpty())
176:                 {
177:                         throw new AnalysisException("No expression to generate from");
178:                 }
179:
180:                 ParserResult<PExp> parseResult = null;
181:                 try
182:                 {
183:                         parseResult = ParserUtil.parseExpression(exp);
184:                 } catch (Exception e)
185:                 {
186:                         throw new AnalysisException("Unable to parse expression: " + exp
187:                                         + ". Message: " + e.getMessage());
188:                 }
189:
190:                 if (parseResult.errors.size() > 0)
191:                 {
192:                         throw new AnalysisException("Unable to parse expression: " + exp);
193:                 }
194:
195:                 TypeCheckResult<PExp> typeCheckResult = null;
196:                 try
197:                 {
198:                         typeCheckResult = TypeCheckerUtil.typeCheckExpression(exp);
199:                 } catch (Exception e)
200:                 {
201:                         throw new AnalysisException("Unable to type check expression: "
202:                                         + exp + ". Message: " + e.getMessage());
203:                 }
204:
205:                 return typeCheckResult;
206:         }
207:
208:         public static boolean hasErrors(TypeCheckResult<?> tcResult)
209:         {
210:                 return !tcResult.parserResult.errors.isEmpty()
211:                                 || !tcResult.errors.isEmpty();
212:         }
213:
214:         public static SClassDefinition consMainClass(
215:                         List<SClassDefinition> mergedParseLists, String expression,
216:                         Dialect dialect, String mainClassName, ITempVarGen nameGen)
217:                         throws VDMErrorsException, AnalysisException
218:         {
219:                 ClassList classes = new ClassList();
220:                 classes.addAll(mergedParseLists);
221:                 PExp entryExp = typeCheckEntryPoint(classes, expression, dialect);
222:
223:                 String resultTypeStr = entryExp.getType() instanceof AVoidType ? "()"
224:                                 : "?";
225:
226:                 // Collect all the class names
227:                 List<String> namesToAvoid = new LinkedList<>();
228:
229:                 for (SClassDefinition c : classes)
230:                 {
231:                         namesToAvoid.add(c.getName().getName());
232:                 }
233:
234:                 // If the user already uses the name proposed for the main class
235:                 // we have to find a new name for the main class
236:                 if (namesToAvoid.contains(mainClassName))
237:                 {
238:                         String prefix = mainClassName + "_";
239:                         mainClassName = nameGen.nextVarName(prefix);
240:
241:                         while (namesToAvoid.contains(mainClassName))
242:                         {
243:                                 mainClassName = nameGen.nextVarName(prefix);
244:                         }
245:                 }
246:
247:                 String entryClassTemplate = "class " + mainClassName + "\n"
248:                                 + "operations\n" + "public static Run : () ==> " + resultTypeStr
249:                                 + "\n" + "Run () == " + expression + ";\n" + "end "
250:                                 + mainClassName;
251:
252:                 SClassDefinition clazz = parseClass(entryClassTemplate, mainClassName, dialect);
253:
254:                 return tcClass(classes, clazz);
255:         }
256:
257:         public static PExp typeCheckEntryPoint(ClassList classes, String expression,
258:                         Dialect dialect) throws VDMErrorsException, AnalysisException
259:         {
260:                 SClassDefinition defaultModule = null;
261:
262:                 LexNameToken name = new LexNameToken("CLASS", "DEFAULT", new LexLocation());
263:                 defaultModule = AstFactory.newAClassClassDefinition(name, null, null);
264:                 defaultModule.setUsed(true);
265:                 PExp exp = parseExpression(expression, defaultModule.getName().getName(), dialect);
266:
267:                 return tcExp(classes, exp);
268:         }
269:
270:         public static PExp tcExp(ClassList classes, PExp exp)
271:                         throws AnalysisException, VDMErrorsException
272:         {
273:                 TypeCheckerAssistantFactory af = new TypeCheckerAssistantFactory();
274:                 ClassTypeChecker.clearErrors();
275:                 ClassTypeChecker classTc = new ClassTypeChecker(classes, af);
276:
277:                 for (SClassDefinition c : classes)
278:                 {
279:                         clearTypeData(c);
280:                 }
281:
282:                 classTc.typeCheck();
283:
284:                 TypeCheckVisitor tc = new TypeCheckVisitor();
285:                 TypeChecker.clearErrors();
286:                 Environment env = new PublicClassEnvironment(af, classes, null);
287:
288:                 exp.apply(tc, new TypeCheckInfo(af, env, NameScope.NAMESANDSTATE));
289:
290:                 if (TypeChecker.getErrorCount() > 0)
291:                 {
292:                         throw new VDMErrorsException(TypeChecker.getErrors());
293:                 } else
294:                 {
295:                         return exp;
296:                 }
297:         }
298:
299:         public static SClassDefinition tcClass(ClassList classes,
300:                         SClassDefinition clazz) throws AnalysisException, VDMErrorsException
301:
302:         {
303:                 for (SClassDefinition c : classes)
304:                 {
305:                         clearTypeData(c);
306:                 }
307:
308:                 TypeCheckerAssistantFactory af = new TypeCheckerAssistantFactory();
309:                 ClassTypeChecker.clearErrors();
310:                 ClassTypeChecker classTc = new ClassTypeChecker(classes, af);
311:
312:                 classes.add(clazz);
313:                 classTc.typeCheck();
314:
315:                 if (TypeChecker.getErrorCount() > 0)
316:                 {
317:                         throw new VDMErrorsException(TypeChecker.getErrors());
318:                 } else
319:                 {
320:                         return clazz;
321:                 }
322:         }
323:
324:         private static void clearTypeData(SClassDefinition c)
325:                         throws AnalysisException
326:         {
327:                 // Reset lex name data so the classes can be type checked again
328:                 c.apply(new DepthFirstAnalysisAdaptor()
329:                 {
330:                         @Override
331:                         public void inILexNameToken(ILexNameToken node)
332:                                         throws AnalysisException
333:                         {
334:                                 if (node instanceof LexNameToken && node.parent() != null)
335:                                 {
336:                                         ((LexNameToken) node).typeQualifier = null;
337:                                         node.parent().replaceChild(node, node.copy());
338:                                 }
339:                         }
340:                 });
341:         }
342:
343:         public static PExp parseExpression(String expression,
344:                         String defaultModuleName, Dialect dialect)
345:                         throws ParserException, LexException
346:         {
347:                 LexTokenReader ltr = new LexTokenReader(expression, dialect, Console.charset);
348:                 ExpressionReader reader = new ExpressionReader(ltr);
349:                 reader.setCurrentModule(defaultModuleName);
350:
351:                 return reader.readExpression();
352:         }
353:
354:         public static SClassDefinition parseClass(String classStr,
355:                         String defaultModuleName, Dialect dialect)
356:         {
357:                 LexTokenReader ltr = new LexTokenReader(classStr, dialect, Console.charset);
358:                 ClassReader reader = new ClassReader(ltr);
359:                 reader.setCurrentModule(defaultModuleName);
360:
361:                 // There should be only one class
362:                 for (SClassDefinition clazz : reader.readClasses())
363:                 {
364:                         if (clazz.getName().getName().equals(defaultModuleName))
365:                         {
366:                                 return clazz;
367:                         }
368:                 }
369:
370:                 return null;
371:         }
372:
373:         public static void replaceInFile(File file, String regex,
374:                         String replacement)
375:         {
376:                 replaceInFile(file.getAbsolutePath(), regex, replacement);
377:         }
378:
379:         public static void replaceInFile(String filePath, String regex,
380:                         String replacement)
381:         {
382:                 try
383:                 {
384:                         File file = new File(filePath);
385:                         BufferedReader reader = new BufferedReader(new FileReader(file));
386:                         String line = "", oldtext = "";
387:                         while ((line = reader.readLine()) != null)
388:                         {
389:                                 oldtext += line + "\n";
390:                         }
391:                         reader.close();
392:                         String newtext = oldtext.replaceAll(regex, replacement);
393:
394:                         FileWriter writer = new FileWriter(filePath);
395:                         writer.write(newtext);
396:                         writer.close();
397:                 } catch (IOException ioe)
398:                 {
399:                         MsgPrinter.getPrinter().errorln("Error replacing characters in file: "
400:                                         + filePath);
401:                         ioe.printStackTrace();
402:                 }
403:         }
404:
405:         public static void copyDirectory(File sourceLocation, File targetLocation)
406:                         throws IOException
407:         {
408:                 if (!targetLocation.exists())
409:                 {
410:                         targetLocation.getParentFile().mkdirs();
411:                 }
412:
413:                 if (sourceLocation.isDirectory())
414:                 {
415:                         String[] children = sourceLocation.list();
416:                         for (int i = 0; i < children.length; i++)
417:                         {
418:                                 copyDirectory(new File(sourceLocation, children[i]), new File(targetLocation, children[i]));
419:                         }
420:                 } else
421:                 {
422:                         targetLocation.createNewFile();
423:
424:                         InputStream in = new FileInputStream(sourceLocation);
425:                         OutputStream out = new FileOutputStream(targetLocation);
426:
427:                         // Copy the bits from instream to outstream
428:                         byte[] buf = new byte[1024];
429:                         int len;
430:                         while ((len = in.read(buf)) > 0)
431:                         {
432:                                 out.write(buf, 0, len);
433:                         }
434:                         in.close();
435:                         out.close();
436:                 }
437:         }
438:
439:         public static List<String> getClassesToSkip(String userInput)
440:         {
441:                 if (userInput == null)
442:                 {
443:                         return new LinkedList<String>();
444:                 }
445:
446:                 String[] split = userInput.split(";");
447:
448:                 List<String> classesToSkip = new LinkedList<String>();
449:
450:                 for (String element : split)
451:                 {
452:                         element = element.trim();
453:
454:                         if (element != null && !element.isEmpty())
455:                         {
456:                                 if (!classesToSkip.contains(element))
457:                                 {
458:                                         classesToSkip.add(element);
459:                                 }
460:                         }
461:                 }
462:
463:                 return classesToSkip;
464:         }
465:
466:         public static String constructNameViolationsString(
467:                         InvalidNamesResult invalidNames)
468:         {
469:                 StringBuffer buffer = new StringBuffer();
470:
471:                 List<Violation> reservedWordViolations = asSortedList(invalidNames.getReservedWordViolations());
472:                 List<Violation> typenameViolations = asSortedList(invalidNames.getTypenameViolations());
473:                 List<Violation> tempVarViolations = asSortedList(invalidNames.getTempVarViolations());
474:                 List<Violation> objectMethodViolations = asSortedList(invalidNames.getObjectMethodViolations());
475:
476:                 String correctionMessage = String.format("Prefix '%s' has been added to the name"
477:                                 + LINE_SEPARATOR, invalidNames.getCorrectionPrefix());
478:
479:                 for (Violation violation : reservedWordViolations)
480:                 {
481:                         buffer.append("Reserved name violation: " + violation + ". "
482:                                         + correctionMessage);
483:                 }
484:
485:                 for (Violation violation : typenameViolations)
486:                 {
487:                         buffer.append("Type name violation: " + violation + ". "
488:                                         + correctionMessage);
489:                 }
490:
491:                 for (Violation violation : tempVarViolations)
492:                 {
493:                         buffer.append("Temporary variable violation: " + violation + ". "
494:                                         + correctionMessage);
495:                 }
496:
497:                 for (Violation violation : objectMethodViolations)
498:                 {
499:                         buffer.append("java.lang.Object method violation: " + violation
500:                                         + ". " + correctionMessage);
501:                 }
502:
503:                 return buffer.toString();
504:         }
505:
506:         public static String constructVarRenamingString(List<Renaming> renamings)
507:         {
508:                 StringBuilder sb = new StringBuilder();
509:
510:                 for (Renaming r : renamings)
511:                 {
512:                         sb.append(r).append('\n');
513:                 }
514:
515:                 return sb.toString();
516:         }
517:
518:         public static List<Violation> asSortedList(Set<Violation> violations)
519:         {
520:                 LinkedList<Violation> list = new LinkedList<Violation>(violations);
521:                 Collections.sort(list);
522:
523:                 return list;
524:         }
525:
526:         public static void printMergeErrors(List<Exception> mergeErrors)
527:         {
528:                 for (Exception error : mergeErrors)
529:                 {
530:                         MsgPrinter.getPrinter().println(error.toString());
531:                 }
532:         }
533:
534:         public static void printUnsupportedIrNodes(
535:                         Set<VdmNodeInfo> unsupportedNodes)
536:         {
537:                 AssistantManager assistantManager = new AssistantManager();
538:                 LocationAssistantIR locationAssistant = assistantManager.getLocationAssistant();
539:
540:                 List<VdmNodeInfo> nodesSorted = locationAssistant.getVdmNodeInfoLocationSorted(unsupportedNodes);
541:
542:                 for (VdmNodeInfo vdmNodeInfo : nodesSorted)
543:                 {
544:                         MsgPrinter.getPrinter().print(vdmNodeInfo.getNode().toString()
545:                                         + " (" + vdmNodeInfo.getNode().getClass().getSimpleName()
546:                                         + ")");
547:
548:                         ILexLocation location = locationAssistant.findLocation(vdmNodeInfo.getNode());
549:
550:                         MsgPrinter.getPrinter().print(location != null
551:                                         ? " at [line, pos] = [" + location.getStartLine() + ", "
552:                                                         + location.getStartPos() + "] in "
553:                                                         + location.getFile().getName()
554:                                         : "");
555:
556:                         String reason = vdmNodeInfo.getReason();
557:
558:                         if (reason != null)
559:                         {
560:                                 MsgPrinter.getPrinter().print(". Reason: " + reason);
561:                         }
562:
563:                         MsgPrinter.getPrinter().println("");
564:                 }
565:         }
566:
567:         public static void printUnsupportedNodes(Set<IrNodeInfo> unsupportedNodes)
568:         {
569:                 AssistantManager assistantManager = new AssistantManager();
570:                 LocationAssistantIR locationAssistant = assistantManager.getLocationAssistant();
571:
572:                 List<IrNodeInfo> nodesSorted = locationAssistant.getIrNodeInfoLocationSorted(unsupportedNodes);
573:
574:                 for (IrNodeInfo nodeInfo : nodesSorted)
575:                 {
576:                         INode vdmNode = locationAssistant.getVdmNode(nodeInfo);
577:                         MsgPrinter.getPrinter().print(vdmNode != null ? vdmNode.toString()
578:                                         : nodeInfo.getNode().getClass().getSimpleName());
579:
580:                         ILexLocation location = locationAssistant.findLocation(nodeInfo);
581:
582:                         MsgPrinter.getPrinter().print(location != null
583:                                         ? " at [line, pos] = [" + location.getStartLine() + ", "
584:                                                         + location.getStartPos() + "] in " + location.getFile()
585:                                         : "");
586:
587:                         String reason = nodeInfo.getReason();
588:
589:                         if (reason != null)
590:                         {
591:                                 MsgPrinter.getPrinter().print(". Reason: " + reason);
592:                         }
593:
594:                         MsgPrinter.getPrinter().println("");
595:                 }
596:         }
597: }