Package: CodeGenBase

CodeGenBase

nameinstructionbranchcomplexitylinemethod
CodeGenBase()
M: 0 C: 21
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
cleanup(IRStatus)
M: 6 C: 13
68%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 3 C: 4
57%
M: 0 C: 1
100%
cleanup(List)
M: 0 C: 15
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
clear()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
emitCode(File, String, String)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
emitCode(File, String, String, String)
M: 13 C: 45
78%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 3 C: 9
75%
M: 0 C: 1
100%
finalIrEvent(List)
M: 0 C: 12
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
formatCode(StringWriter)
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
genIrExp(IRStatus, MergeVisitor)
M: 24 C: 31
56%
M: 3 C: 3
50%
M: 3 C: 1
25%
M: 3 C: 9
75%
M: 0 C: 1
100%
genIrModule(MergeVisitor, IRStatus)
M: 39 C: 42
52%
M: 3 C: 3
50%
M: 3 C: 1
25%
M: 3 C: 10
77%
M: 0 C: 1
100%
genIrStatus(List, INode)
M: 0 C: 12
100%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 0 C: 4
100%
M: 0 C: 1
100%
generate(List)
M: 0 C: 43
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 11
100%
M: 0 C: 1
100%
getClasses(List)
M: 25 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
getIRGenerator()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getInfo()
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getModules(List)
M: 0 C: 25
100%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 0 C: 6
100%
M: 0 C: 1
100%
getNodes(List)
M: 0 C: 10
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
getSettings()
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getTransAssistant()
M: 0 C: 3
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
getUserModules(List)
M: 0 C: 27
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
getUserTestCases(List)
M: 9 C: 24
73%
M: 1 C: 3
75%
M: 1 C: 2
67%
M: 1 C: 5
83%
M: 0 C: 1
100%
handleOldNames(List)
M: 0 C: 19
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
initVelocity()
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
initialIrEvent(List)
M: 0 C: 12
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
isTestCase(IRStatus)
M: 0 C: 9
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
preProcessAst(List)
M: 0 C: 38
100%
M: 0 C: 4
100%
M: 0 C: 3
100%
M: 0 C: 9
100%
M: 0 C: 1
100%
preProcessVdmUserClass(INode)
M: 14 C: 20
59%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 3 C: 5
63%
M: 0 C: 1
100%
registerIrObs(IREventObserver)
M: 0 C: 9
100%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 0 C: 3
100%
M: 0 C: 1
100%
removeUnreachableStms(List)
M: 0 C: 19
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 5
100%
M: 0 C: 1
100%
setIRGenerator(IRGenerator)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
setSettings(IRSettings)
M: 0 C: 6
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
setTransAssistant(TransAssistantIR)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
shouldGenerateVdmNode(INode)
M: 0 C: 12
100%
M: 0 C: 2
100%
M: 0 C: 2
100%
M: 0 C: 4
100%
M: 0 C: 1
100%
simplifyLibrary(INode)
M: 1 C: 65
98%
M: 1 C: 9
90%
M: 1 C: 5
83%
M: 1 C: 18
95%
M: 0 C: 1
100%
static {...}
M: 0 C: 5
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
unregisterIrObs(IREventObserver)
M: 10 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%

Coverage

1: package org.overture.codegen.ir;
2:
3: import java.io.BufferedWriter;
4: import java.io.File;
5: import java.io.FileOutputStream;
6: import java.io.IOException;
7: import java.io.OutputStreamWriter;
8: import java.io.PrintWriter;
9: import java.io.StringWriter;
10: import java.util.HashSet;
11: import java.util.LinkedList;
12: import java.util.List;
13: import java.util.Set;
14:
15: import org.apache.log4j.Logger;
16: import org.apache.velocity.app.Velocity;
17: import org.overture.ast.analysis.AnalysisException;
18: import org.overture.ast.analysis.DepthFirstAnalysisAdaptor;
19: import org.overture.ast.definitions.PDefinition;
20: import org.overture.ast.definitions.SClassDefinition;
21: import org.overture.ast.definitions.SFunctionDefinition;
22: import org.overture.ast.definitions.SOperationDefinition;
23: import org.overture.ast.expressions.ANewExp;
24: import org.overture.ast.expressions.ANotYetSpecifiedExp;
25: import org.overture.ast.lex.Dialect;
26: import org.overture.ast.modules.AModuleModules;
27: import org.overture.ast.node.INode;
28: import org.overture.ast.statements.ANotYetSpecifiedStm;
29: import org.overture.ast.util.modules.ModuleList;
30: import org.overture.codegen.analysis.vdm.UnreachableStmRemover;
31: import org.overture.codegen.assistant.DeclAssistantIR;
32: import org.overture.codegen.ir.statements.ABlockStmIR;
33: import org.overture.codegen.merging.MergeVisitor;
34: import org.overture.codegen.trans.BlockCleanupTrans;
35: import org.overture.codegen.trans.OldNameRenamer;
36: import org.overture.codegen.trans.assistants.TransAssistantIR;
37: import org.overture.codegen.utils.Generated;
38: import org.overture.codegen.utils.GeneratedData;
39: import org.overture.codegen.utils.GeneratedModule;
40: import org.overture.config.Settings;
41:
42: /**
43: * This class is a base class implementation of a code generator that is developed on top of the Code Generation
44: * Platform (CGP). Code generators that want to translate VDM models into some target language can inherit from this
45: * class.
46: *
47: * @author pvj
48: */
49: abstract public class CodeGenBase implements IREventCoordinator
50: {
51:         /**
52:          * The {@link #generator} field is used for constructing and transforming the Intermediate Representation (IR)
53:          * generated from the VDM AST.
54:          */
55:         protected IRGenerator generator;
56:
57:         /**
58:          * The {@link #transAssistant} provides functionality that is convenient when implementing transformations.
59:          */
60:         protected TransAssistantIR transAssistant;
61:
62:         /**
63:          * The {@link #irObserver} can receive and manipulate the initial and final versions of the IR via the
64:          * {@link #initialIrEvent(List)} and {@link #finalIrEvent(List)} methods.
65:          */
66:         protected IREventObserver irObserver;
67:
68:         /**
69:          * Used to log information during the code generation process.
70:          */
71:         protected static Logger log = Logger.getLogger(CodeGenBase.class.getName());
72:
73:         /**
74:          * Constructs this code generator by initializing the template engine and constructing the {@link #generator}.
75:          */
76:         protected CodeGenBase()
77:         {
78:                 super();
79:                 initVelocity();
80:                 this.irObserver = null;
81:                 this.generator = new IRGenerator();
82:                 this.transAssistant = new TransAssistantIR(generator.getIRInfo());
83:         }
84:
85:         /**
86:          * This method clears the state of the {@link #generator}, which forms the first step of the code generation
87:          * process. That is, this method is invoked upon entering {@link #generate(List)}.
88:          */
89:         protected void clear()
90:         {
91:                 generator.clear();
92:         }
93:
94:         /**
95:          * The entry point of this class. This method translates a VDM AST into target language code. Use of the template
96:          * method design pattern ensures that the state of this code generator is properly initialized and that the VDM AST
97:          * is pre-processed in accordance with the {@link #preProcessAst(List)} method.
98:          *
99:          * @param ast
100:          * The VDM AST, which can be either VDM modules or classes.
101:          * @return The data generated from the VDM AST.
102:          * @throws AnalysisException
103:          * If a problem occurs during the construction of the IR.
104:          */
105:         public GeneratedData generate(List<INode> ast) throws AnalysisException
106:         {
107:                 clear();
108:
109:•                if (Settings.dialect == Dialect.VDM_SL)
110:                 {
111:                         ModuleList moduleList = new ModuleList(getModules(ast));
112:                         moduleList.combineDefaults();
113:                         ast = getNodes(moduleList);
114:                 }
115:
116:                 preProcessAst(ast);
117:
118:                 List<IRStatus<PIR>> statuses = new LinkedList<>();
119:
120:•                for (INode node : ast)
121:                 {
122:                         genIrStatus(statuses, node);
123:                 }
124:
125:                 return genVdmToTargetLang(statuses);
126:         }
127:
128:         /**
129:          * This method translates a VDM node into an IR status.
130:          *
131:          * @param statuses
132:          * A list of previously generated IR statuses. The generated IR status will be added to this list.
133:          * @param node
134:          * The VDM node from which we generate an IR status
135:          * @throws AnalysisException
136:          * If something goes wrong during the construction of the IR status.
137:          */
138:         protected void genIrStatus(List<IRStatus<PIR>> statuses, INode node)
139:                         throws AnalysisException
140:         {
141:                 IRStatus<PIR> status = generator.generateFrom(node);
142:
143:•                if (status != null)
144:                 {
145:                         statuses.add(status);
146:                 }
147:         }
148:
149:         /**
150:          * Translates a list of IR statuses into target language code. This method must be implemented by all code
151:          * generators that inherit from this class. This method is invoked by {@link #generate(List)}.
152:          *
153:          * @param statuses
154:          * The IR statuses holding the nodes to be code generated.
155:          * @return The generated code as well as information about the code generation process.
156:          * @throws AnalysisException
157:          * If something goes wrong during the code generation process.
158:          */
159:         abstract protected GeneratedData genVdmToTargetLang(
160:                         List<IRStatus<PIR>> statuses) throws AnalysisException;
161:
162:         /**
163:          * This method pre-processes the VDM AST by<br>
164:          * (1) computing a definition table that can be used during the analysis of the IR to determine if a VDM identifier
165:          * state designator is local or not.<br>
166:          * (2) Removing unreachable statements from the VDM AST <br>
167:          * (3) Normalizing old names by replacing tilde signs '~' with underscores '_' <br>
168:          * (4) Simplifying the standard libraries by cutting nodes that are not likely to be meaningful during the analysis
169:          * of the VDM AST. Library classes are processed using {@link #simplifyLibrary(INode)}, whereas non-library modules
170:          * or classes are processed using {@link #preProcessVdmUserClass(INode)}.
171:          *
172:          * @param ast
173:          * The VDM AST subject to pre-processing.
174:          * @throws AnalysisException
175:          * In case something goes wrong during the VDM AST analysis.
176:          */
177:         protected void preProcessAst(List<INode> ast) throws AnalysisException
178:         {
179:                 generator.computeDefTable(getUserModules(ast));
180:                 removeUnreachableStms(ast);
181:                 handleOldNames(ast);
182:
183:•                for (INode node : ast)
184:                 {
185:•                        if (getInfo().getAssistantManager().getDeclAssistant().isLibrary(node))
186:                         {
187:                                 simplifyLibrary(node);
188:                         } else
189:                         {
190:                                 preProcessVdmUserClass(node);
191:                         }
192:                 }
193:         }
194:
195:         /**
196:          * Initializes the Apache Velocity template engine.
197:          */
198:         protected void initVelocity()
199:         {
200:                 Velocity.setProperty("runtime.log.logsystem.class", "org.apache.velocity.runtime.log.NullLogSystem");
201:                 Velocity.init();
202:         }
203:
204:         /**
205:          * Formats the generated code. By default, this method simply returns the input unmodified.
206:          *
207:          * @param code
208:          * The unformatted code.
209:          * @return The formatted code.
210:          */
211:         protected String formatCode(StringWriter code)
212:         {
213:                 return code.toString();
214:         }
215:
216:         /**
217:          * Convenience method for extracting the VDM module definitions from a list of VDM nodes.
218:          *
219:          * @param ast
220:          * A list of VDM nodes.
221:          * @return The module definitions extracted from <code>ast</code>.
222:          */
223:         public static List<AModuleModules> getModules(List<INode> ast)
224:         {
225:                 List<AModuleModules> modules = new LinkedList<>();
226:
227:•                for (INode n : ast)
228:                 {
229:•                        if (n instanceof AModuleModules)
230:                         {
231:                                 modules.add((AModuleModules) n);
232:                         }
233:                 }
234:
235:                 return modules;
236:         }
237:
238:         /**
239:          * Convenience method for extracting the VDM class definitions from a list of VDM nodes.
240:          *
241:          * @param ast
242:          * A list of VDM nodes.
243:          * @return The class definitions extracted from <code>ast</code>.
244:          */
245:         public static List<SClassDefinition> getClasses(List<INode> ast)
246:         {
247:                 List<SClassDefinition> classes = new LinkedList<>();
248:
249:•                for (INode n : ast)
250:                 {
251:•                        if (n instanceof SClassDefinition)
252:                         {
253:                                 classes.add((SClassDefinition) n);
254:                         }
255:                 }
256:
257:                 return classes;
258:         }
259:
260:         /**
261:          * Convenience method for converting a VDM AST into a list of nodes.
262:          *
263:          * @param ast
264:          * The VDM AST.
265:          * @return The VDM AST as a list of nodes.
266:          */
267:         public static List<INode> getNodes(List<? extends INode> ast)
268:         {
269:                 List<INode> nodes = new LinkedList<>();
270:
271:                 nodes.addAll(ast);
272:
273:                 return nodes;
274:         }
275:
276:         /**
277:          * Applies the {@link #cleanup(IRStatus)} method to all the IR statuses.
278:          *
279:          * @param statuses
280:          * The IR statuses
281:          */
282:         public void cleanup(List<IRStatus<PIR>> statuses)
283:         {
284:•                for (IRStatus<PIR> s : statuses)
285:                 {
286:                         cleanup(s);
287:                 }
288:         }
289:
290:         /**
291:          * Cleans up an IR status by removing redundant {@link ABlockStmIR} nodes using the {@link BlockCleanupTrans}
292:          * transformation.
293:          *
294:          * @param status
295:          * The IR status
296:          */
297:         public void cleanup(IRStatus<PIR> status)
298:         {
299:•                if (status != null && status.getIrNode() != null)
300:                 {
301:                         try
302:                         {
303:                                 status.getIrNode().apply(new BlockCleanupTrans());
304:                         } catch (org.overture.codegen.ir.analysis.AnalysisException e)
305:                         {
306:                                 e.printStackTrace();
307:                                 log.error("Problem encountered when trying to clean up blocks");
308:                         }
309:                 }
310:         }
311:
312:         /**
313:          * Given an IR status this method determines if it represents a test case or not.
314:          *
315:          * @param status
316:          * The IR status.
317:          * @return True if the <code>status</code> represents a test case - false otherwise.
318:          */
319:         protected boolean isTestCase(IRStatus<? extends PIR> status)
320:         {
321:                 return getInfo().getDeclAssistant().isTestCase(status.getIrNode().getSourceNode().getVdmNode());
322:         }
323:
324:         /**
325:          * This method extracts the user modules or classes from a VDM AST.
326:          *
327:          * @param ast
328:          * The VDM AST.
329:          * @return A list of user modules or classes.
330:          */
331:         protected List<INode> getUserModules(List<? extends INode> ast)
332:         {
333:                 List<INode> userModules = new LinkedList<INode>();
334:
335:•                for (INode node : ast)
336:                 {
337:•                        if (!getInfo().getDeclAssistant().isLibrary(node))
338:                         {
339:                                 userModules.add(node);
340:                         }
341:                 }
342:
343:                 return userModules;
344:         }
345:
346:         /**
347:          * This method removes unreachable statements from the VDM AST.
348:          *
349:          * @param ast
350:          * The VDM AST subject to processing.
351:          * @throws AnalysisException
352:          * If something goes wrong when trying to remove unreachable statements from the <code>ast</code>.
353:          */
354:         protected void removeUnreachableStms(List<? extends INode> ast)
355:                         throws AnalysisException
356:         {
357:                 UnreachableStmRemover remover = new UnreachableStmRemover();
358:
359:•                for (INode node : ast)
360:                 {
361:                         node.apply(remover);
362:                 }
363:         }
364:
365:         /**
366:          * Simplifies a VDM standard library class or module by removing sub-nodes that are likely not to be of interest
367:          * during the generation of the IR.
368:          *
369:          * @param module
370:          * A VDM class or module
371:          */
372:         protected void simplifyLibrary(INode module)
373:         {
374:                 List<PDefinition> defs = null;
375:
376:•                if (module instanceof SClassDefinition)
377:                 {
378:                         defs = ((SClassDefinition) module).getDefinitions();
379:•                } else if (module instanceof AModuleModules)
380:                 {
381:                         defs = ((AModuleModules) module).getDefs();
382:                 } else
383:                 {
384:                         // Nothing to do
385:                         return;
386:                 }
387:
388:•                for (PDefinition def : defs)
389:                 {
390:•                        if (def instanceof SOperationDefinition)
391:                         {
392:                                 SOperationDefinition op = (SOperationDefinition) def;
393:
394:                                 op.setBody(new ANotYetSpecifiedStm());
395:                                 op.setPrecondition(null);
396:                                 op.setPostcondition(null);
397:•                        } else if (def instanceof SFunctionDefinition)
398:                         {
399:                                 SFunctionDefinition func = (SFunctionDefinition) def;
400:
401:                                 func.setBody(new ANotYetSpecifiedExp());
402:                                 func.setPrecondition(null);
403:                                 func.setPostcondition(null);
404:                         }
405:                 }
406:         }
407:
408:         /**
409:          * Processes old names by replacing the tilde sign '~' with an underscore.
410:          *
411:          * @param vdmAst
412:          * The VDM AST subject to processing.
413:          * @throws AnalysisException
414:          * If something goes wrong during the renaming process.
415:          */
416:         protected void handleOldNames(List<? extends INode> vdmAst)
417:                         throws AnalysisException
418:         {
419:                 OldNameRenamer oldNameRenamer = new OldNameRenamer();
420:
421:•                for (INode module : vdmAst)
422:                 {
423:                         module.apply(oldNameRenamer);
424:                 }
425:         }
426:
427:         /**
428:          * Given a list of IR statuses this method retrieves the names of the user-defined test cases.
429:          *
430:          * @param statuses
431:          * The list of IR statuses from which the test case names are retrieved
432:          * @return The names of the user-defined test cases.
433:          */
434:         protected List<String> getUserTestCases(List<IRStatus<PIR>> statuses)
435:         {
436:                 List<String> userTestCases = new LinkedList<>();
437:
438:•                for (IRStatus<PIR> s : statuses)
439:                 {
440:•                        if (getInfo().getDeclAssistant().isTestCase(s.getVdmNode()))
441:                         {
442:                                 userTestCases.add(getInfo().getDeclAssistant().getNodeName(s.getVdmNode()));
443:                         }
444:                 }
445:
446:                 return userTestCases;
447:         }
448:
449:         /**
450:          * Pre-processing of a user class. This method is invoked by {@link #preProcessAst(List)}.
451:          *
452:          * @param vdmModule
453:          * The user module or class.
454:          */
455:         protected void preProcessVdmUserClass(INode vdmModule)
456:         {
457:                 final Set<String> instantiatedClasses = new HashSet<>();
458:                 
459:                 try {
460:                         vdmModule.apply(new DepthFirstAnalysisAdaptor() {
461:                                 
462:                                 @Override
463:                                 public void caseANewExp(ANewExp node) throws AnalysisException {
464:                                 
465:                                         super.caseANewExp(node);
466:                                         instantiatedClasses.add(node.getClassName().getName());
467:                                 }
468:                         });
469:                 } catch (AnalysisException e) {
470:
471:                         log.error("Got unexpected error when trying to find classes that are instantiated: " + e.getMessage());
472:                         e.printStackTrace();
473:                 }
474:                 
475:                 this.generator.getIRInfo().getInstantiatedClasses().addAll(instantiatedClasses);
476:         }
477:
478:         /**
479:          * Determines whether a VDM module or class should be code generated or not.
480:          *
481:          * @param vdmNode
482:          * The node to be checked.
483:          * @return True if <code>node</code> should be code generated - false otherwise.
484:          */
485:         protected boolean shouldGenerateVdmNode(INode vdmNode)
486:         {
487:                 DeclAssistantIR declAssistant = getInfo().getDeclAssistant();
488:
489:•                if (declAssistant.isLibrary(vdmNode))
490:                 {
491:                         return false;
492:                 } else
493:                 {
494:                         return true;
495:                 }
496:         }
497:
498:         /**
499:          * This method translates an IR module or class into target language code.
500:          *
501:          * @param mergeVisitor
502:          * The visitor that translates the IR module or class into target language code.
503:          * @param status
504:          * The IR status that holds the IR node that we want to code generate.
505:          * @return The generated code and data about what has been generated.
506:          * @throws org.overture.codegen.ir.analysis.AnalysisException
507:          * If something goes wrong during the code generation process.
508:          */
509:         protected GeneratedModule genIrModule(MergeVisitor mergeVisitor,
510:                         IRStatus<? extends PIR> status)
511:                         throws org.overture.codegen.ir.analysis.AnalysisException
512:         {
513:•                if (status.canBeGenerated())
514:                 {
515:                         mergeVisitor.init();
516:                         StringWriter writer = new StringWriter();
517:                         status.getIrNode().apply(mergeVisitor, writer);
518:
519:                         boolean isTestCase = isTestCase(status);
520:
521:                         GeneratedModule generatedModule;
522:•                        if (mergeVisitor.hasMergeErrors())
523:                         {
524:                                 generatedModule = new GeneratedModule(status.getIrNodeName(), status.getIrNode(), mergeVisitor.getMergeErrors(), isTestCase);
525:•                        } else if (mergeVisitor.hasUnsupportedTargLangNodes())
526:                         {
527:                                 generatedModule = new GeneratedModule(status.getIrNodeName(), new HashSet<VdmNodeInfo>(), mergeVisitor.getUnsupportedInTargLang(), isTestCase);
528:                         } else
529:                         {
530:                                 generatedModule = new GeneratedModule(status.getIrNodeName(), status.getIrNode(), formatCode(writer), isTestCase);
531:                                 generatedModule.setTransformationWarnings(status.getTransformationWarnings());
532:                         }
533:
534:                         return generatedModule;
535:                 } else
536:                 {
537:                         return new GeneratedModule(status.getIrNodeName(), status.getUnsupportedInIr(), new HashSet<IrNodeInfo>(), isTestCase(status));
538:                 }
539:         }
540:
541:         /**
542:          * Translates an IR expression into target language code.
543:          *
544:          * @param expStatus
545:          * The IR status that holds the expressions that we want to code generate.
546:          * @param mergeVisitor
547:          * The visitor that translates the IR expression into target language code.
548:          * @return The generated code and data about what has been generated.
549:          * @throws org.overture.codegen.ir.analysis.AnalysisException
550:          * If something goes wrong during the code generation process.
551:          */
552:         protected Generated genIrExp(IRStatus<SExpIR> expStatus,
553:                         MergeVisitor mergeVisitor)
554:                         throws org.overture.codegen.ir.analysis.AnalysisException
555:         {
556:                 StringWriter writer = new StringWriter();
557:                 SExpIR expCg = expStatus.getIrNode();
558:
559:•                if (expStatus.canBeGenerated())
560:                 {
561:                         mergeVisitor.init();
562:
563:                         expCg.apply(mergeVisitor, writer);
564:
565:•                        if (mergeVisitor.hasMergeErrors())
566:                         {
567:                                 return new Generated(mergeVisitor.getMergeErrors());
568:•                        } else if (mergeVisitor.hasUnsupportedTargLangNodes())
569:                         {
570:                                 return new Generated(new HashSet<VdmNodeInfo>(), mergeVisitor.getUnsupportedInTargLang());
571:                         } else
572:                         {
573:                                 String code = writer.toString();
574:
575:                                 return new Generated(code);
576:                         }
577:                 } else
578:                 {
579:
580:                         return new Generated(expStatus.getUnsupportedInIr(), new HashSet<IrNodeInfo>());
581:                 }
582:         }
583:
584:         /**
585:          * Emits generated code to a file. The file will be encoded using UTF-8.
586:          *
587:          * @param outputFolder
588:          * The output folder that will store the generated code.
589:          * @param fileName
590:          * The name of the file that will store the generated code.
591:          * @param code
592:          * The generated code.
593:          */
594:         public static void emitCode(File outputFolder, String fileName, String code)
595:         {
596:                 emitCode(outputFolder, fileName, code, "UTF-8");
597:         }
598:
599:         /**
600:          * Emits generated code to a file.
601:          *
602:          * @param outputFolder
603:          * outputFolder The output folder that will store the generated code.
604:          * @param fileName
605:          * The name of the file that will store the generated code.
606:          * @param code
607:          * The generated code.
608:          * @param encoding
609:          * The encoding to use for the generated code.
610:          */
611:         public static void emitCode(File outputFolder, String fileName, String code,
612:                         String encoding)
613:         {
614:                 try
615:                 {
616:                         File javaFile = new File(outputFolder, File.separator + fileName);
617:                         javaFile.getParentFile().mkdirs();
618:                         javaFile.createNewFile();
619:                         PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(javaFile, false), encoding));
620:                         BufferedWriter out = new BufferedWriter(writer);
621:                         out.write(code);
622:                         out.close();
623:
624:                 } catch (IOException e)
625:                 {
626:                         log.error("Error when saving class file: " + fileName);
627:                         e.printStackTrace();
628:                 }
629:         }
630:
631:         /**
632:          * Registration of the {@link #irObserver}.
633:          */
634:         @Override
635:         public void registerIrObs(IREventObserver obs)
636:         {
637:•                if (obs != null && irObserver == null)
638:                 {
639:                         irObserver = obs;
640:                 }
641:         }
642:
643:         /**
644:          * Unregistration of the {@link #irObserver}.
645:          */
646:         @Override
647:         public void unregisterIrObs(IREventObserver obs)
648:         {
649:•                if (obs != null && irObserver == obs)
650:                 {
651:                         irObserver = null;
652:                 }
653:         }
654:
655:         /**
656:          * Notifies the {@link #irObserver} when the initial version of the IR has been constructed. This method allows the
657:          * {@link #irObserver} to modify the initial version of the IR.
658:          *
659:          * @param ast
660:          * The initial version of the IR.
661:          * @return A possibly modified version of the initial IR.
662:          */
663:         public List<IRStatus<PIR>> initialIrEvent(List<IRStatus<PIR>> ast)
664:         {
665:•                if (irObserver != null)
666:                 {
667:                         return irObserver.initialIRConstructed(ast, getInfo());
668:                 }
669:
670:                 return ast;
671:         }
672:
673:         /**
674:          * Notifies the {@link #irObserver} when the final version of the IR has been constructed. This method allows the
675:          * {@link #irObserver} to modify the IR.
676:          *
677:          * @param ast
678:          * The final version of the IR.
679:          * @return A possibly modified version of the IR
680:          */
681:         public List<IRStatus<PIR>> finalIrEvent(List<IRStatus<PIR>> ast)
682:         {
683:•                if (irObserver != null)
684:                 {
685:                         return irObserver.finalIRConstructed(ast, getInfo());
686:                 }
687:
688:                 return ast;
689:         }
690:
691:         public void setIRGenerator(IRGenerator generator)
692:         {
693:                 this.generator = generator;
694:         }
695:
696:         public IRGenerator getIRGenerator()
697:         {
698:                 return generator;
699:         }
700:
701:         public void setSettings(IRSettings settings)
702:         {
703:                 generator.getIRInfo().setSettings(settings);
704:         }
705:
706:         public IRSettings getSettings()
707:         {
708:                 return generator.getIRInfo().getSettings();
709:         }
710:
711:         public IRInfo getInfo()
712:         {
713:                 return generator.getIRInfo();
714:         }
715:
716:         public void setTransAssistant(TransAssistantIR transAssistant)
717:         {
718:                 this.transAssistant = transAssistant;
719:         }
720:
721:         public TransAssistantIR getTransAssistant()
722:         {
723:                 return transAssistant;
724:         }
725: }