/** Copyright (C) Conformiq Software Oy, Ltd. | |
* All rights reserved. | |
* | |
* Created Wed Aug 27 16:49:21 2008. | |
* | |
* @file | |
* | |
* @author Tommi Vainikainen | |
* | |
* | |
*/ | |
package com.conformiq.adaptation.ttcn; | |
import java.io.BufferedWriter; | |
import java.io.FileNotFoundException; | |
import java.io.FileReader; | |
import java.io.FileWriter; | |
import java.io.IOException; | |
import java.util.Date; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Set; | |
import java.util.Vector; | |
import com.conformiq.qtronic2.Checkpoint; | |
import com.conformiq.qtronic2.MetaDataDictionary; | |
import com.conformiq.qtronic2.NotificationSink; | |
import com.conformiq.qtronic2.QMLArray; | |
import com.conformiq.qtronic2.QMLBoolean; | |
import com.conformiq.qtronic2.QMLNumber; | |
import com.conformiq.qtronic2.QMLOptional; | |
import com.conformiq.qtronic2.QMLRecord; | |
import com.conformiq.qtronic2.QMLRecordType; | |
import com.conformiq.qtronic2.QMLRecordTypeField; | |
import com.conformiq.qtronic2.QMLString; | |
import com.conformiq.qtronic2.QMLValue; | |
import com.conformiq.qtronic2.QMLValueVisitor; | |
import com.conformiq.qtronic2.ScriptBackend; | |
import com.conformiq.qtronic2.TimeStamp; | |
import com.conformiq.qtronic2.Checkpoint.CheckpointStatus; | |
import com.conformiq.qtronic2.Checkpoint.CheckpointType; | |
public class TTCNScripter extends ScriptBackend | |
{ | |
class TemplateDefinition | |
{ | |
public TemplateDefinition(final String type, final String templatename, | |
QMLRecord record) | |
{ | |
this.typeName = type; | |
this.templateName = templatename; | |
this.record = record; | |
} | |
private String typeName; | |
private String templateName; | |
public String getTypeName() | |
{ | |
return typeName; | |
} | |
public String getTemplateName() | |
{ | |
return templateName; | |
} | |
private QMLRecord record; | |
public QMLRecord getRecord() | |
{ | |
return record; | |
} | |
} | |
/** Convert adapter datums into TTCN3 code. */ | |
class TTCN3PortVisitor implements QMLValueVisitor | |
{ | |
public TTCN3PortVisitor(PrettyPrinter pp, boolean isInbound) | |
{ | |
this.out = pp; | |
this.isInbound = isInbound; | |
assert (out != null); | |
typeNameMap = new HashMap<String, String>(); | |
/* Booleans */ | |
typeNameMap.put("boolean", "boolean"); | |
/* Integers. */ | |
typeNameMap.put("int", "integer"); | |
typeNameMap.put("byte", "integer"); | |
typeNameMap.put("char", "integer"); | |
typeNameMap.put("short", "integer"); | |
typeNameMap.put("long", "integer"); | |
/* Floating point. */ | |
typeNameMap.put("float", "float"); | |
typeNameMap.put("double", "float"); | |
/* Strinags. */ | |
typeNameMap.put("String", "charstring"); | |
} | |
protected PrettyPrinter out; | |
protected final boolean isInbound; | |
protected Map<String, String> typeNameMap; | |
@Override | |
public void visit(QMLArray x) | |
{ | |
/* | |
* Port types are tuples with just Strings inside referring to | |
* types. | |
*/ | |
assert (x != null); | |
final int size = x.getNumberOfElements(); | |
for (int i = 0; i < size; i++) | |
{ | |
QMLString portname = (QMLString) x.getValue(i); | |
if (portname != null) | |
{ | |
final String origname = portname.getValue(); | |
final String name = TTCNScripter | |
.makeValidTTCN3Identifier(origname); | |
/* Skip AnyRecord.. */ | |
if (name.equals("AnyRecord")) | |
{ | |
continue; | |
} | |
/* | |
* It seems that record fields are separated using commas | |
* but ports are separated using semicolons in TTCN3..? | |
*/ | |
if (eptfBidirectionalPort) | |
out.print("inout"); | |
else | |
out.print(isInbound ? "in" : "out"); | |
out.print(" "); | |
out.print(name); | |
out.print(";"); | |
out.endl(); | |
} | |
} | |
} | |
@Override | |
public void visit(QMLBoolean b) | |
{ | |
} | |
@Override | |
public void visit(QMLNumber n) | |
{ | |
} | |
@Override | |
public void visit(QMLRecord r) | |
{ | |
} | |
@Override | |
public void visit(QMLString s) | |
{ | |
} | |
@Override | |
public void visit(QMLOptional p) | |
{ | |
} | |
} | |
// My port visitor | |
class MyTTCN3PortVisitor implements QMLValueVisitor | |
{ | |
public MyTTCN3PortVisitor(PrettyPrinter pp, boolean isInbound, | |
String port, String indent) | |
{ | |
this.out = pp; | |
this.isInbound = isInbound; | |
this.port = port; | |
this.indent = indent; | |
assert (out != null); | |
typeNameMap = new HashMap<String, String>(); | |
/* Booleans */ | |
typeNameMap.put("boolean", "boolean"); | |
/* Integers. */ | |
typeNameMap.put("int", "integer"); | |
typeNameMap.put("byte", "integer"); | |
typeNameMap.put("char", "integer"); | |
typeNameMap.put("short", "integer"); | |
typeNameMap.put("long", "integer"); | |
/* Floating point. */ | |
typeNameMap.put("float", "float"); | |
typeNameMap.put("double", "float"); | |
/* Strinags. */ | |
typeNameMap.put("String", "charstring"); | |
} | |
protected PrettyPrinter out; | |
protected final boolean isInbound; | |
protected Map<String, String> typeNameMap; | |
private String port; | |
private String indent; | |
@Override | |
public void visit(QMLArray x) | |
{ | |
/* | |
* Port types are tuples with just Strings inside referring to | |
* types. | |
*/ | |
assert (x != null); | |
final int size = x.getNumberOfElements(); | |
for (int i = 0; i < size; i++) | |
{ | |
QMLString portname = (QMLString) x.getValue(i); | |
if (portname != null) | |
{ | |
final String origname = portname.getValue(); | |
final String name = TTCNScripter | |
.makeValidTTCN3Identifier(origname); | |
/* Skip AnyRecord.. */ | |
if (name.equals("AnyRecord")) | |
{ | |
continue; | |
} | |
// Harness generation | |
out.print(indent + "function qtronic"); | |
out.print(isInbound ? "_receive_" : "_send_"); | |
out.print(name); | |
out.print(isInbound ? "_from_" : "_to_"); | |
out.print(this.port); | |
out.print("(template " + name + " "); | |
out.print((isInbound ? "tmplToMatch" : "msgToSend") | |
+ ") runs on " + runsOnName); | |
out.endl(); | |
out.print(indent + "{"); | |
out.endl(); | |
out.print(indent + indent | |
+ "// Do whatever manipulation is needed to '"); | |
out.print((isInbound ? "tmplToMatch" : "msgToSend")); | |
out.print("'"); | |
out.endl(); | |
if (isInbound) | |
{ | |
out | |
.print(indent | |
+ indent | |
+ "// before matching it against the expected value template."); | |
out.endl(); | |
out | |
.print(indent | |
+ indent | |
+ "// This manipulation typically means removing fields not present"); | |
out.endl(); | |
out.print(indent + indent | |
+ "// in the abstract model system interface."); | |
out.endl(); | |
if (eptfEnable) | |
{ | |
if (this.port.equals(eptfInboundPort) | |
|| this.port.equals(eptfOutboundPort)) | |
{ | |
out | |
.print(indent | |
+ indent | |
+ "EPTF_MBT_TESTER_PCO.receive(tmplToMatch) from vc_lgen;"); | |
out.endl(); | |
} | |
else | |
{ | |
out.print(indent + indent + this.port | |
+ ".receive(tmplToMatch);"); | |
out.endl(); | |
} | |
} | |
} | |
else | |
{ | |
out | |
.print(indent | |
+ indent | |
+ "// before it is delivered to the SUT through the real test interface."); | |
out.endl(); | |
out | |
.print(indent | |
+ indent | |
+ "// This can include addition of fields not present in the model or"); | |
out.endl(); | |
out | |
.print(indent | |
+ indent | |
+ "// manipulation of unique identifiers in the messages that Qtronic"); | |
out.endl(); | |
out | |
.print(indent | |
+ indent | |
+ "// cannot possible know at the time of test generation."); | |
out.endl(); | |
if (eptfEnable) | |
{ | |
if (this.port.equals(eptfInboundPort) | |
|| this.port.equals(eptfOutboundPort)) | |
{ | |
out | |
.print(indent | |
+ indent | |
+ "EPTF_MBT_TESTER_PCO.send(msgToSend) to vc_lgen;"); | |
out.endl(); | |
} | |
else | |
{ | |
out.print(indent + indent + this.port | |
+ ".send(msgToSend);"); | |
out.endl(); | |
} | |
} | |
} | |
out.print(indent + "}"); | |
out.endl(); | |
} | |
} | |
} | |
@Override | |
public void visit(QMLBoolean b) | |
{ | |
} | |
@Override | |
public void visit(QMLNumber n) | |
{ | |
} | |
@Override | |
public void visit(QMLRecord r) | |
{ | |
} | |
@Override | |
public void visit(QMLString s) | |
{ | |
} | |
@Override | |
public void visit(QMLOptional p) | |
{ | |
} | |
} | |
private PrettyPrinter out; | |
private NotificationSink notifications; | |
private MetaDataDictionary metadata; | |
private int testCaseIndex; | |
private int templateIndex; | |
private boolean isCompact; | |
private TimeStamp timeStamp; | |
private String logCommand; | |
private boolean generateTypes; | |
private boolean generateTestComponent; | |
private String filename; | |
private String timerName; | |
private String defaultName; | |
private String startHook; | |
private String commSlack; | |
private String extraImports; | |
private String runsOnName; | |
private String systemTypeName; | |
private String endHook; | |
private String portExtensions; | |
private String moduleName; | |
private String dataTypesFile; | |
private String testHarnessFile; | |
private boolean generateTestHarness; | |
private boolean firstStep; | |
private Map<QMLRecord, Integer> generatedTemplates; | |
private Vector<TemplateDefinition> postponedTemplates; | |
private Vector<String> testCaseNames; | |
private String extendsComponent; | |
private boolean eptfEnable; | |
private String eptfInboundPort; | |
private String eptfOutboundPort; | |
private boolean eptfBidirectionalPort; | |
static private String SCRIPTER_NAME = "TTCN-3 scripter 0.1"; | |
public TTCNScripter() | |
{ | |
this.testCaseIndex = 0; | |
this.templateIndex = 0; | |
this.isCompact = false; | |
this.timeStamp = new TimeStamp(); | |
this.timeStamp.seconds = 0; | |
this.timeStamp.nanoseconds = 0; | |
this.logCommand = "log"; | |
this.generateTypes = true; | |
this.generateTestComponent = true; | |
this.filename = ""; | |
this.timerName = ""; | |
this.defaultName = ""; | |
this.startHook = ""; | |
this.commSlack = ""; | |
this.extraImports = ""; | |
this.runsOnName = ""; | |
this.systemTypeName = ""; | |
this.endHook = ""; | |
this.portExtensions = ""; | |
this.moduleName = ""; | |
this.dataTypesFile = ""; | |
this.testHarnessFile = ""; | |
this.generateTestHarness = true; | |
this.firstStep = false; | |
this.generatedTemplates = new HashMap<QMLRecord, Integer>(); | |
this.postponedTemplates = new Vector<TemplateDefinition>(); | |
this.testCaseNames = new Vector<String>(); | |
this.extendsComponent = ""; | |
this.eptfEnable = false; | |
this.eptfInboundPort = ""; | |
this.eptfOutboundPort = ""; | |
this.eptfBidirectionalPort = false; | |
} | |
@Override | |
public void setNotificationSink(NotificationSink sink) | |
{ | |
notifications = sink; | |
} | |
@Override | |
public boolean setMetaData(MetaDataDictionary dict) | |
{ | |
metadata = dict; | |
return true; | |
} | |
@Override | |
public boolean setConfigurationOption(java.lang.String property, | |
java.lang.String value) | |
{ | |
if (property.equals("Main.Generated TTCN-3 file")) | |
{ | |
filename = value; | |
moduleName = getModuleName(filename); | |
} | |
else if (property.equals("Main.Generated types and test component")) | |
{ | |
dataTypesFile = value; | |
} | |
else if (property.equals("Main.Generated harness template file")) | |
{ | |
testHarnessFile = value; | |
} | |
else if (property.equals("Main.Generate types")) | |
{ | |
generateTypes = value.equals("true"); | |
} | |
else if (property.equals("Main.Generate ports and test component")) | |
{ | |
generateTestComponent = value.equals("true"); | |
} | |
else if (property.equals("Main.Test component extension")) | |
{ | |
extendsComponent = value; | |
} | |
else if (property.equals("Main.Generate test harness template")) | |
{ | |
generateTestHarness = value.equals("true"); | |
} | |
else if (property.equals("Logging.Name of the 'log' command")) | |
{ | |
logCommand = value; | |
} | |
else if (property.equals("Customization.Global timer name")) | |
{ | |
timerName = value; | |
} | |
else if (property.equals("Customization.Activated default")) | |
{ | |
defaultName = value; | |
} | |
else if (property.equals("Customization.Start test case hook call")) | |
{ | |
startHook = value; | |
} | |
else if (property.equals("Timing.Communications slack limit")) | |
{ | |
commSlack = value; | |
} | |
else if (property.equals("Customization.Extra import statements")) | |
{ | |
extraImports = value; | |
} | |
else if (property.equals("Customization.Runs on type name")) | |
{ | |
runsOnName = value; | |
} | |
else if (property.equals("Customization.System type name")) | |
{ | |
systemTypeName = value; | |
} | |
else if (property.equals("Customization.End test case hook call")) | |
{ | |
endHook = value; | |
} | |
else if (property.equals("Extensions.Use port type extension")) | |
{ | |
portExtensions = value; | |
} | |
else if (property.equals("Logging.Log checkpoints")) | |
{ | |
isCompact = !value.equals("true"); | |
} | |
else if (property.equals("EPTF_MBT_Applib.Enable")) | |
{ | |
eptfEnable = value.equals("true"); | |
} | |
else if (property.equals("EPTF_MBT_Applib.Inbound Port")) | |
{ | |
eptfInboundPort = value; | |
} | |
else if (property.equals("EPTF_MBT_Applib.Outbound Port")) | |
{ | |
eptfOutboundPort = value; | |
} | |
else if (property.equals("EPTF_MBT_Applib.Bidirectional Ports")) | |
{ | |
eptfBidirectionalPort = value.equals("true"); | |
} | |
return true; | |
} | |
private String getModuleName(String path) | |
{ | |
int slash = path.lastIndexOf("/"); | |
int backslash = path.lastIndexOf("\\"); | |
String module; | |
if (slash != -1 && backslash != -1) | |
{ | |
module = path | |
.substring((slash > backslash ? slash : backslash) + 1); | |
} | |
else if (slash != -1) | |
{ | |
module = path.substring(slash + 1); | |
} | |
else if (backslash != -1) | |
{ | |
module = path.substring(backslash + 1); | |
} | |
else | |
{ | |
module = path; | |
} | |
int size = module.length(); | |
String upper = module.toUpperCase(); | |
if (upper.lastIndexOf(".TTCN3") == (size - 6)) | |
{ | |
return module.substring(0, size - 6); | |
} | |
if (upper.lastIndexOf(".TTCN") == (size - 5)) | |
{ | |
return module.substring(0, size - 5); | |
} | |
if (upper.lastIndexOf(".3MP") == (size - 4)) | |
{ | |
return module.substring(0, size - 4); | |
} | |
return "QtronicTest"; | |
} | |
@Override | |
public boolean beginScript(String testsuiteName) | |
{ | |
if (notifications != null) | |
{ | |
notifications.notify("info", SCRIPTER_NAME | |
+ ": Export test cases for test " + "design configuration " | |
+ testsuiteName); | |
} | |
String msg = null; | |
if (filename.equals("")) | |
{ | |
msg = "TTCN-3 backend must be configured with a file name."; | |
} | |
else | |
{ | |
try | |
{ | |
out = new PrettyPrinter(new BufferedWriter(new FileWriter( | |
filename))); | |
} catch (IOException e) | |
{ | |
StringBuffer msgbuf = new StringBuffer(); | |
msgbuf.append("Failed to open file '"); | |
msgbuf.append(filename); | |
msgbuf.append("' for writing TTCN-3 script."); | |
msg = msgbuf.toString(); | |
} | |
} | |
if (msg != null) | |
{ | |
if (notifications != null) | |
{ | |
notifications.notify("error", SCRIPTER_NAME + ": " + msg); | |
} | |
else | |
{ | |
System.err.println(msg); | |
} | |
return false; | |
} | |
dumpHeader(filename); | |
out.print("module "); | |
out.print(moduleName); | |
out.endl(); | |
out.print("{"); | |
out.endl(); | |
out.print(" "); | |
out.block(); | |
out.print("import from "); | |
out.print(getModuleName(dataTypesFile)); | |
out.print(" all;"); | |
out.endl(); | |
// import generated test harness | |
if (eptfEnable && generateTestHarness && !testHarnessFile.equals("")) | |
{ | |
out.print("import from "); | |
out.print(getModuleName(testHarnessFile)); | |
out.print(" all;"); | |
out.endl(); | |
} | |
out.print("/* User provided imports begin */"); | |
out.endl(); | |
out.print(extraImports); | |
out.endl(); | |
out.print("/* User provided imports end */"); | |
out.endl(); | |
// print out the test harness template | |
try | |
{ | |
// should the harness template be written | |
if (generateTestHarness) | |
{ | |
// check if file already exists. If it does ask user | |
// to remove it first | |
try | |
{ | |
new FileReader(testHarnessFile); | |
if (notifications != null) | |
{ | |
notifications.notify("info", SCRIPTER_NAME + ": File " | |
+ testHarnessFile + " exists, NOT overwriting it."); | |
} | |
return true; | |
} catch (FileNotFoundException not_found) | |
{ | |
// create the template file | |
dumpTestHarness(); | |
if (notifications != null) | |
{ | |
notifications.notify("info", SCRIPTER_NAME | |
+ ": Generated TTCN-3 test harness template to " | |
+ "<hyperlink=\"" + testHarnessFile + "\">" | |
+ testHarnessFile + "</hyperlink>."); | |
} | |
} | |
} | |
} catch (Exception e) | |
{ | |
out.print("/* EXCEPTION CAUGHT */"); | |
out.endl(); | |
if (notifications != null) | |
{ | |
notifications | |
.notify( | |
"error", | |
SCRIPTER_NAME | |
+ ": Caught exception while " | |
+ "rendering TTCN test harness template. Please reload model " | |
+ "and try again (" + e.getMessage() + ")"); | |
} | |
return false; | |
} | |
if (generateTypes) | |
{ | |
// out.print("/* Qtronic generated data types begin */"); | |
// out.endl(); | |
/* First dump all the types used in the module. */ | |
try | |
{ | |
dumpTypes(); | |
dumpTemplates(); | |
// out.print("/* Qtronic generated data types end */"); | |
// out.endl(); | |
} catch (Exception e) | |
{ | |
out.print("/* EXCEPTION CAUGHT */"); | |
out.endl(); | |
if (notifications != null) | |
{ | |
notifications | |
.notify( | |
"error", | |
SCRIPTER_NAME | |
+ ": Caught exception while " | |
+ "rendering TTCN type definitions. Please reload model " | |
+ "and try again (" + e.getMessage() | |
+ ")"); | |
} | |
return false; | |
} | |
} | |
out.print("/* Qtronic generated alt step */"); | |
out.endl(); | |
/* | |
* The GENERATED default is always called QtronicDefaultAlt(), but the | |
* user can use alternative default by changing configuration option. In | |
* this case the user provides the default. | |
*/ | |
out.print("altstep QtronicDefaultAlt() runs on "); | |
out.print(runsOnName); | |
out.endl(); | |
out.print("{"); | |
out.endl(); | |
out.print(" "); | |
printAltStepBody(); | |
deleteCopies(); | |
templateIndex = 0; | |
testCaseIndex = 0; | |
firstStep = false; | |
return true; | |
} | |
private void printAltStepBody() | |
{ | |
printAltStepBody(""); | |
} | |
private void printAltStepBody(String indent) | |
{ | |
out.print(indent); | |
out.block(); | |
out.print("[] any port.receive"); | |
out.endl(); | |
out.print("{"); | |
out.endl(); | |
out.print(" "); | |
out.block(); | |
out.print(timerName); | |
out.print(".stop;"); | |
out.endl(); | |
out.print("setverdict(fail);"); | |
out.endl(); | |
if (!endHook.equals("")) | |
{ | |
out.print(endHook); | |
out.print(";"); | |
out.endl(); | |
} | |
out.print("stop;"); | |
out.endl(); | |
out.resume(); | |
out.print("}"); | |
out.endl(); | |
out.print("[] "); | |
out.print(timerName); | |
out.print(".timeout"); | |
out.endl(); | |
out.print("{"); | |
out.endl(); | |
out.print(" "); | |
out.block(); | |
out.print("setverdict(fail);"); | |
out.endl(); | |
if (!endHook.equals("")) | |
{ | |
out.print(endHook); | |
out.print(";"); | |
out.endl(); | |
} | |
out.print("stop;"); | |
out.endl(); | |
out.resume(); | |
out.print("}"); | |
out.endl(); | |
out.resume(); | |
out.print("}"); | |
out.endl(); | |
} | |
private void dumpType(final QMLRecordType type, Set<String> arrays) | |
{ | |
out.print("type record "); | |
out.print(makeValidTTCN3Identifier(type.getTypeName())); | |
out.endl(); | |
out.print("{"); | |
out.endl(); | |
out.print(" "); | |
out.block(); | |
for (int i = 0; i < type.getNumberOfFields(); i++) | |
{ | |
final QMLRecordTypeField field = type.getField(i); | |
TTCNTypeName v = new TTCNTypeName(arrays); | |
field.getType().accept(v); | |
assert (!v.getName().equals("")); | |
if (i != 0) | |
{ | |
out.print(","); | |
out.endl(); | |
} | |
out.print(v.getName()); | |
out.print(" "); | |
out.print(makeValidTTCN3Identifier(field.getFieldName())); | |
if (v.getOptional()) | |
{ | |
out.print(" optional"); | |
} | |
} | |
out.endl(); | |
out.resume(); | |
out.print("}"); | |
out.endl(); | |
for (int i = 0; i < type.getNumberOfInnerRecords(); i++) | |
{ | |
dumpType(type.getInnerType(i), arrays); | |
} | |
} | |
private void dumpTypes() throws Exception | |
{ | |
assert (metadata != null); | |
Set<String> arrays = new HashSet<String>(); | |
List<String> ports = new Vector<String>(); | |
PrettyPrinter oldOut = out; | |
String msg = null; | |
Exception rethrowMe = null; | |
if (dataTypesFile.equals("")) | |
{ | |
msg = "TTCN-3 backend must be configured with a data type file " | |
+ "name."; | |
} | |
else | |
{ | |
try | |
{ | |
out = new PrettyPrinter(new BufferedWriter(new FileWriter( | |
dataTypesFile))); | |
} catch (IOException e) | |
{ | |
StringBuffer msgbuf = new StringBuffer(); | |
msgbuf.append("Failed to open file '"); | |
msgbuf.append(dataTypesFile); | |
msgbuf.append("' for writing data types."); | |
msg = msgbuf.toString(); | |
rethrowMe = e; | |
} | |
} | |
if (msg != null) | |
{ | |
if (notifications != null) | |
{ | |
notifications.notify("error", msg); | |
} | |
else | |
{ | |
System.err.println(msg); | |
} | |
out = oldOut; | |
// Pass the exception forward for proper error handling further | |
// up the call stack. | |
throw (rethrowMe); | |
} | |
dumpHeader(dataTypesFile); | |
out.print("module "); | |
out.print(getModuleName(dataTypesFile)); | |
out.endl(); | |
out.print("{"); | |
out.endl(); | |
out.print(" "); | |
out.block(); | |
out.print("/* User provided imports begin */"); | |
out.endl(); | |
out.print(extraImports); | |
out.endl(); | |
out.print("/* User provided imports end */"); | |
out.endl(); | |
try | |
{ | |
if (generateTestComponent) | |
{ | |
final String portinfo = "portinfo:"; | |
String key = metadata.getNextKey(portinfo); | |
while (key != null) | |
{ | |
String data = key; | |
if (data.indexOf(portinfo) != 0) | |
{ | |
break; | |
} | |
final QMLValue definition = metadata.get(key); | |
assert (definition != null); | |
QMLArray tuple = (QMLArray) definition; | |
if (tuple != null) | |
{ | |
String origname; | |
boolean inbound = false; | |
int pos = data.indexOf(":inbound:"); | |
inbound = (pos != -1); | |
origname = data.substring(portinfo.length() | |
+ (inbound ? "inbound:".length() : "outbound:" | |
.length())); | |
if (eptfEnable | |
&& (origname.equals(eptfInboundPort) || origname | |
.equals(eptfOutboundPort))) | |
{ // Port definitions is not generated for the MBT port | |
System.err.print("//Skipping port" | |
+ makeValidTTCN3Identifier(origname) + "\n"); | |
} | |
else | |
{ | |
String name = makeValidTTCN3Identifier(origname); | |
out.print("type port "); | |
out.print(name); | |
out.print("Port message"); | |
ports.add(name); | |
out.endl(); | |
out.print("{"); | |
out.endl(); | |
out.print(" "); | |
out.block(); | |
TTCN3PortVisitor converter = new TTCN3PortVisitor( | |
out, !inbound); | |
tuple.accept(converter); | |
// if (converter.hasArrays()) { | |
// Iterator<String> it = | |
// converter.getArrays().keySet() | |
// .iterator(); | |
// while (it.hasNext()) { | |
// arrays.add(it.next()); | |
// } | |
// } | |
out.resume(); | |
out.print("}"); | |
if (!portExtensions.equals("")) | |
{ | |
out.print(" with {extension \""); | |
out.print(portExtensions); | |
out.print("\"}"); | |
} | |
out.endl(); | |
} | |
} | |
key = metadata.getNextKey(key); | |
} | |
} | |
if (generateTypes) | |
{ | |
Vector<QMLRecordType> types = metadata.getTypes(); | |
Iterator<QMLRecordType> rit = types.iterator(); | |
while (rit.hasNext()) | |
{ | |
QMLRecordType type = rit.next(); | |
if (eptfEnable && type.getTypeName().length() >= 5 | |
&& type.getTypeName().substring(0, 5).equals("EPTF_")) | |
{ // Do not generate type definitions for EPTF modules | |
} | |
else | |
{ | |
dumpType(type, arrays); | |
} | |
} | |
Iterator<String> it = arrays.iterator(); | |
while (it.hasNext()) | |
{ | |
String x = it.next(); | |
// TODO: reconsider changing this because now both | |
// TTCNTypeName class and this piece of code here has | |
// to know how array names are constructed. | |
out.print("type record of "); | |
out.print(x); | |
out.print(" "); | |
out.print(x); | |
out.print("Array;"); | |
out.endl(); | |
} | |
} | |
if (generateTestComponent) | |
{ | |
out.endl(); | |
out.print("type component "); | |
out.print(runsOnName); | |
if (!extendsComponent.equals("")) | |
{ | |
out.print(" extends "); | |
out.print(extendsComponent); | |
} | |
out.endl(); | |
out.print("{"); | |
out.endl(); | |
out.print(" "); | |
out.block(); | |
Iterator<String> it = ports.iterator(); | |
while (it.hasNext()) | |
{ | |
String x = it.next(); | |
out.print("port "); | |
out.print(x); | |
out.print("Port "); | |
out.print(x); | |
out.print(";"); | |
out.endl(); | |
} | |
out.print("timer "); | |
out.print(timerName); | |
out.print(" := 0.0;"); | |
out.endl(); | |
out.resume(); | |
out.print("}"); | |
out.endl(); | |
} | |
/* | |
* altstep QtronicDefaultAlt() runs on SystemType { [] any | |
* port.receive { mytimer.stop; setverdict(fail); stop; } [] | |
* mytimer.timeout { setverdict(fail); stop; } } | |
*/ | |
// Must close the module block. | |
out.resume(); | |
out.print("}"); | |
out.endl(); | |
out.flush(); | |
out.close(); | |
out = oldOut; | |
} catch (Exception e) | |
{ | |
out.flush(); | |
out.close(); | |
out = oldOut; | |
} | |
} | |
private void dumpTemplates() | |
{ | |
Iterator<TemplateDefinition> it = postponedTemplates.iterator(); | |
while (it.hasNext()) | |
{ | |
final TemplateDefinition def = it.next(); | |
out.print("template "); | |
out.print(makeValidTTCN3Identifier(def.getTypeName())); | |
out.print(" "); | |
out.print(def.getTemplateName()); | |
out.ws(); | |
out.print(":="); | |
out.endl(); | |
QMLRecord r = def.getRecord(); | |
TemplateDumper t = new TemplateDumper(out); | |
r.accept(t); | |
out.endl(); | |
} | |
} | |
/** | |
* prints out the test harness template, that contains: | |
* | |
* - import from QtronicTypes; | |
* | |
* - type component for the harness system | |
* | |
* - MTC component the tests should run on | |
* | |
* - harness alt step | |
* | |
* - start and end test hook calls | |
* | |
* - port and message mapping functions | |
*/ | |
private void dumpTestHarness() throws Exception | |
{ | |
assert (metadata != null); | |
PrettyPrinter oldOut = out; | |
String msg = null; | |
Exception rethrowMe = null; | |
if (testHarnessFile.equals("")) | |
{ | |
msg = "TTCN-3 backend must be configured with a test harness " | |
+ " file name."; | |
} | |
else | |
{ | |
try | |
{ | |
out = new PrettyPrinter(new BufferedWriter(new FileWriter( | |
testHarnessFile))); | |
} catch (IOException e) | |
{ | |
StringBuffer msgbuf = new StringBuffer(); | |
msgbuf.append("Failed to open file '"); | |
msgbuf.append(testHarnessFile); | |
msgbuf.append("' for writing test harness template."); | |
msg = msgbuf.toString(); | |
rethrowMe = e; | |
} | |
} | |
if (msg != null) | |
{ | |
if (notifications != null) | |
{ | |
notifications.notify("error", msg); | |
} | |
else | |
{ | |
System.err.println(msg); | |
} | |
out = oldOut; | |
// Pass the exception forward for proper error handling further | |
// up the call stack. | |
throw (rethrowMe); | |
} | |
String indent = " "; | |
dumpHeader(testHarnessFile); | |
out.print("module "); | |
out.print(getModuleName(testHarnessFile)); | |
out.endl(); | |
out.print("{"); | |
out.endl(); | |
out.block(); | |
// import all data types | |
out.print(indent); | |
out.print("import from "); | |
out.print(getModuleName(dataTypesFile)); | |
out.print(" all;"); | |
out.endl(); | |
out.print("/* User provided imports begin */"); | |
out.endl(); | |
out.print(extraImports); | |
out.endl(); | |
out.print("/* User provided imports end */"); | |
out.endl(); | |
out.block(); | |
// system mapping | |
if (!systemTypeName.equals("") && !eptfEnable) | |
{ | |
out.print(indent + "type component "); | |
out.print(systemTypeName); | |
out.endl(); | |
out.print(indent + "{"); | |
out.endl(); | |
out.print(indent + indent | |
+ "// Add port definitions for your system here"); | |
out.endl(); | |
out.print(indent + "}"); | |
out.endl(); | |
out.block(); | |
} | |
// MTC port definitions | |
if (!runsOnName.equals("")) | |
{ | |
// The component type should be already generated in the type | |
// definitions module. | |
if (!eptfEnable) | |
{ | |
out.print(indent); | |
out.print("type component "); | |
out.print(runsOnName); | |
out.endl(); | |
out.print(indent + "{"); | |
out.endl(); | |
out.print(indent + indent | |
+ "// Add port definitions for your MTC here"); | |
out.endl(); | |
out.print(indent + indent + "timer "); | |
out.print(timerName); | |
out.print(" := 0.0;"); | |
out.endl(); | |
out.print(indent + "}"); | |
out.endl(); | |
} | |
// alt step | |
String moduleName = getModuleName(dataTypesFile); | |
if (!moduleName.equals("")) | |
{ | |
out.print(indent); | |
out.print("altstep "); | |
out.print(defaultName); | |
out.print(" runs on "); | |
out.print(runsOnName); | |
out.endl(); | |
out.block(); | |
out.print(indent + "{"); | |
out.endl(); | |
out.print(indent); | |
out.block(); | |
printAltStepBody(indent); | |
out.resume(); | |
out.resume(); | |
} | |
// default start and stop functions | |
if (!startHook.equals("") && !eptfEnable) | |
{ | |
out.print(indent); | |
out.print("function "); | |
out.print(startHook); | |
out.print(" runs on "); | |
out.print(runsOnName); | |
out.endl(); | |
out.print(indent + "{"); | |
out.endl(); | |
out.print(indent + indent | |
+ "// Do port mapping between MTC and abstract" | |
+ " test system interface"); | |
out.endl(); | |
out.print(indent + indent | |
+ "// map(mtc:<someport>, system:<someport>);"); | |
out.endl(); | |
out.print(indent + "}"); | |
out.endl(); | |
out.block(); | |
} | |
if (!endHook.equals("") && !eptfEnable) | |
{ | |
out.print(indent); | |
out.print("function "); | |
out.print(endHook); | |
out.print(" runs on "); | |
out.print(runsOnName); | |
out.endl(); | |
out.print(indent + "{"); | |
out.endl(); | |
out.print(indent + indent + "// Do port unmapping e.g."); | |
out.endl(); | |
out.print(indent + indent | |
+ "// map(mtc:<someport>, system:<someport>);"); | |
out.endl(); | |
out.print(indent + "}"); | |
out.endl(); | |
out.block(); | |
} | |
// port mapping | |
try | |
{ | |
final String portinfo = "portinfo:"; | |
String key = metadata.getNextKey(portinfo); | |
while (key != null) | |
{ | |
String data = key; | |
if (data.indexOf(portinfo) != 0) | |
{ | |
break; | |
} | |
final QMLValue definition = metadata.get(key); | |
assert (definition != null); | |
boolean inbound = false; | |
int pos = data.indexOf(":inbound:"); | |
inbound = (pos != -1); | |
String origname = data | |
.substring(portinfo.length() | |
+ (inbound ? "inbound:".length() : "outbound:" | |
.length())); | |
String port = makeValidTTCN3Identifier(origname); | |
QMLArray tuple = (QMLArray) definition; | |
if (tuple != null) | |
{ | |
MyTTCN3PortVisitor converter = new MyTTCN3PortVisitor( | |
out, !inbound, port, indent); | |
tuple.accept(converter); | |
} | |
key = metadata.getNextKey(key); | |
} | |
} catch (Exception e) | |
{ | |
out.print("/* EXCEPTION CAUGHT in dumpTestHarness */"); | |
out.flush(); | |
out.close(); | |
out = oldOut; | |
throw e; | |
} | |
} | |
// Must close the module block. | |
out.resume(); | |
out.print("}"); | |
out.endl(); | |
out.flush(); | |
out.close(); | |
out = oldOut; | |
} | |
private void dumpHeader(String filename) | |
{ | |
assert (out != null); | |
out.print("/* -*- ttcn3 -*- */"); | |
out.endl(); | |
out.emptyline(); | |
out.print("/** "); | |
out.print("@file "); | |
out.print(filename); | |
out.endl(); | |
out.print(" *"); | |
out.block(); | |
out.endl(); | |
out.print(" @author Conformiq TTCN3 Script Backend 0.1"); | |
out.endl(); | |
out.print(" @date "); | |
out.print(new Date().toString()); | |
out.endl(); | |
out.print(""); | |
out.endl(); | |
out.print(" WARNING! This file has been automatically generated using"); | |
out.endl(); | |
out | |
.print(" Ericsson Qtronic TTCN3 Script Backend (based on the original Conformiq Backend)."); | |
out.print("DO NOT EDIT."); | |
out.endl(); | |
out.resume(); | |
out.print(" */"); | |
out.endl(); | |
out.emptyline(); | |
} | |
private void deleteCopies() | |
{ | |
generatedTemplates.clear(); | |
} | |
@Override | |
public boolean beginCase(String testcaseName) | |
{ | |
firstStep = true; | |
testCaseIndex++; | |
out.print("/* Generated test case #"); | |
out.print(testCaseIndex); | |
out.print(" */"); | |
out.endl(); | |
out.print("testcase "); | |
out.print(recordAndRenderTestCaseName(testcaseName)); | |
out.print("() runs on "); | |
out.print(runsOnName); | |
if (systemTypeName != null && !systemTypeName.equals("")) | |
{ | |
out.print(" system "); | |
out.print(systemTypeName); | |
} | |
out.endl(); | |
out.print("{"); | |
out.endl(); | |
out.print(" "); | |
out.block(); | |
out.print("var float oldtimer := 0.0;"); | |
out.endl(); | |
out.print("var float SLACK := "); | |
out.print(commSlack); | |
out.print(";"); | |
out.endl(); | |
if (!defaultName.equals("")) | |
{ | |
out.print("var default default_behaviour_ref;"); | |
out.endl(); | |
} | |
if (!startHook.equals("")) | |
{ | |
out.print(startHook); | |
out.print(";"); | |
out.endl(); | |
} | |
if (!defaultName.equals("")) | |
{ | |
out.print("default_behaviour_ref := activate("); | |
out.print(defaultName); | |
out.print(");"); | |
out.endl(); | |
} | |
return true; | |
} | |
// @Override | |
public void caseProbability(double probability) | |
{ | |
} | |
final private String escapeString(String s) | |
{ | |
// Checkpoint strings from the model must be escaped by "backslashing" | |
// double quotations and backslashes themselves. | |
StringBuffer escaped = new StringBuffer(); | |
final int size = s.length(); | |
if (size == 0) | |
return s; | |
for (int i = 0; i < size; i++) | |
{ | |
if (s.charAt(i) == '\\') | |
{ | |
escaped.append("\\\\"); | |
} | |
else if (s.charAt(i) == '"') | |
{ | |
escaped.append("\\\""); | |
} | |
else | |
{ | |
escaped.append(s.charAt(i)); | |
} | |
} | |
return escaped.toString(); | |
} | |
@Override | |
public boolean checkpointInfo(Checkpoint checkpoint, int status, | |
TimeStamp ts) | |
{ | |
if (isCompact || !firstStep || status == CheckpointStatus.UNCOVERED | |
|| status == CheckpointStatus.MAYBE_COVERED) | |
{ | |
return true; | |
} | |
if (checkpoint.getType() == CheckpointType.USUAL_CHECKPOINT) | |
{ | |
// TODO: we might want to have something configurable here or | |
// maybe something based on which CPs are selected as targets; | |
// now we just include methods, states and transtions into | |
// reports CPs to avoid "CP-bloat". | |
String cp = checkpoint.getName(); | |
String method = new String("method:"); | |
String transition = new String("transition:"); | |
String state = new String("state:"); | |
if ((cp.length() > method.length() && cp.substring(0, | |
method.length()).equals(method)) | |
|| (cp.length() > transition.length() && cp.substring(0, | |
transition.length()).equals(transition)) | |
|| (cp.length() > state.length() && cp.substring(0, | |
state.length()).equals(state))) | |
{ | |
out.print(logCommand); | |
out.print("(\"Structural feature: "); | |
out.print(escapeString(cp)); | |
out.print("\");"); | |
out.endl(); | |
} | |
} | |
else if (checkpoint.getType() == CheckpointType.REQUIREMENT) | |
{ | |
out.print(logCommand); | |
out.print("(\"Requirement: "); | |
out.print(escapeString(checkpoint.getName())); | |
out.print("\");"); | |
out.endl(); | |
} | |
return true; | |
} | |
@Override | |
public boolean endCase() | |
{ | |
out.print("setverdict(pass);"); | |
out.endl(); | |
/* | |
* Default is used only if the provided name is different from "", so if | |
* the default is not used let's not deactivate it either. | |
*/ | |
if (!defaultName.equals("")) | |
{ | |
out.print("deactivate(default_behaviour_ref);"); | |
out.endl(); | |
} | |
if (!endHook.equals("")) | |
{ | |
out.print(endHook); | |
out.print(";"); | |
out.endl(); | |
} | |
out.resume(); | |
out.print("}"); | |
out.endl(); | |
/* Generate templates out of the datums stored in the TestStep. */ | |
dumpTemplates(); | |
postponedTemplates.clear(); | |
return true; | |
} | |
@Override | |
public boolean endScript() | |
{ | |
out.print("control"); | |
out.endl(); | |
out.print("{"); | |
out.endl(); | |
out.print(" "); | |
out.block(); | |
for (int i = 1; i <= testCaseIndex; i++) | |
{ | |
out.print("execute("); | |
out.print(getTestCaseName(i)); | |
out.print("());"); | |
out.endl(); | |
} | |
out.resume(); | |
out.print("}"); | |
out.endl(); | |
out.resume(); | |
out.print("}"); | |
out.endl(); | |
try | |
{ | |
out.flush(); | |
out.close(); | |
} catch (Exception e) | |
{ | |
if (notifications != null) | |
{ | |
notifications.notify("error", SCRIPTER_NAME + ": " | |
+ e.toString()); | |
} | |
} | |
out = null; | |
StringBuffer ss = new StringBuffer(); | |
ss.append("Generated TTCN-3 script to <hyperlink=\""); | |
ss.append(filename); | |
ss.append("\">"); | |
ss.append(filename); | |
ss.append("</hyperlink>."); | |
if (notifications != null) | |
{ | |
notifications.notify("info", SCRIPTER_NAME + ": " + ss.toString()); | |
} | |
else | |
{ | |
System.out.println(ss.toString()); | |
} | |
testCaseNames.clear(); | |
return true; | |
} | |
@Override | |
public boolean testStep(QMLRecord r, String thread, String port, | |
boolean isFromTester, TimeStamp ts) | |
{ | |
/* | |
* We have an altstep defined: | |
* | |
* altstep QtronicDefaultAlt() runs on SystemType { [] any port.receive | |
* { mytimer.stop; setverdict(fail); stop; } [] mytimer.timeout { | |
* setverdict(fail); stop; } } | |
* | |
* which removes the need for "[] any port.receive" and timeout from alt | |
* statements. | |
*/ | |
// Remember the datum so that we can generate a template out of it. | |
// Generate a new template only if it has not been generated before. | |
String name; | |
Integer idx = generatedTemplates.get(r); | |
if (idx != null) | |
{ | |
StringBuffer ss = new StringBuffer(); | |
ss.append(r.getName()); | |
ss.append("Template"); | |
ss.append(idx); | |
name = ss.toString(); | |
} | |
else | |
{ | |
++templateIndex; | |
StringBuffer ss = new StringBuffer(); | |
ss.append(r.getName()); | |
ss.append("Template"); | |
ss.append(templateIndex); | |
name = ss.toString(); | |
postponedTemplates | |
.add(new TemplateDefinition(r.getName(), name, r)); | |
generatedTemplates.put(r, templateIndex); | |
} | |
if (isFromTester) | |
{ | |
/* | |
* Send datum to SUT. Generate: | |
* | |
* mytimer.start(<send time>); alt { [] mytimer.timeout { // OK } } | |
* <port>.send(template_<index>); | |
*/ | |
if (ts.seconds > timeStamp.seconds | |
|| ts.nanoseconds > timeStamp.nanoseconds) | |
{ | |
out.print(timerName); | |
out.print(".start("); | |
out.print(ts.seconds); | |
out.print("."); | |
out.print(ts.nanoseconds); | |
out.print(" - oldtimer);"); | |
out.endl(); | |
out.print("alt"); | |
out.endl(); | |
out.print("{"); | |
out.endl(); | |
out.print(" "); | |
out.block(); | |
out.print("[] "); | |
out.print(timerName); | |
out.print(".timeout"); | |
out.endl(); | |
out.print("{"); | |
out.endl(); | |
out.print("}"); | |
out.endl(); | |
out.resume(); | |
out.print("}"); | |
out.endl(); | |
; | |
out.print(timerName); | |
out.print(".stop;"); | |
out.endl(); | |
} | |
out.print("qtronic_send_"); | |
out.print(r.getName()); | |
out.print("_to_"); | |
out.print(port); | |
out.print("("); | |
out.print(name); | |
out.print(");"); | |
out.endl(); | |
} | |
else | |
{ | |
out.print(timerName); | |
out.print(".start(("); | |
out.print(ts.seconds); | |
out.print("."); | |
out.print(ts.nanoseconds); | |
out.print(" - oldtimer) + SLACK);"); | |
out.endl(); | |
out.print("qtronic_receive_"); | |
out.print(r.getName()); | |
out.print("_from_"); | |
out.print(port); | |
out.print("("); | |
out.print(name); | |
out.print(");"); | |
out.endl(); | |
out.print(timerName); | |
out.print(".stop;"); | |
out.endl(); | |
} | |
out.print("oldtimer := "); | |
out.print(ts.seconds); | |
out.print("."); | |
out.print(ts.nanoseconds); | |
out.print(";"); | |
out.endl(); | |
this.timeStamp.seconds = ts.seconds; | |
this.timeStamp.nanoseconds = ts.nanoseconds; | |
return true; | |
} | |
private String recordAndRenderTestCaseName(String testCaseName) | |
{ | |
// Remove whitespace | |
StringBuffer rendered = new StringBuffer(); | |
for (int i = 0; i < testCaseName.length(); i++) | |
{ | |
// Inverted the logic here to be safer by replacing everything | |
// but valid identifier chars with an underscore. According to the | |
// spec: "TTCN-3 identifiers are case sensitive and may | |
// only contain lowercase letters (a-z) uppercase letters | |
// (A-Z) and numeric digits (0-9). Use of the underscore ( | |
// _ ) symbol is also allowed. An identifier shall begin | |
// with a letter (i.e., not a number and not an | |
// underscore)." | |
char c = testCaseName.substring(i, i + 1).charAt(0); | |
// If the original test case name starts with a digit, we want | |
// to preserve that but need to prefix the test case name with | |
// an underscore. | |
if (c >= '0' && c <= '9' && i == 0) | |
rendered.append('_'); | |
if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') | |
|| (c >= '0' && c <= '9') || c == '_') | |
rendered.append(c); | |
else | |
rendered.append('_'); | |
} | |
// Put into test case name list | |
testCaseNames.add(rendered.toString()); | |
return rendered.toString(); | |
} | |
private String getTestCaseName(int i) | |
{ | |
// Get test case name at index i of the test case list | |
return testCaseNames.get(i - 1); | |
} | |
@Override | |
public boolean internalCommunicationsInfo(QMLRecord datum, String sender, | |
String receiver, String port, TimeStamp time) | |
{ | |
return true; | |
} | |
@Override | |
public boolean trace(String message, TimeStamp time) | |
{ | |
return true; | |
} | |
private static boolean isalpha(char c) | |
{ | |
return (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')); | |
} | |
private static boolean isalnum(char c) | |
{ | |
return (isalpha(c) || ('0' <= c && c <= '9')); | |
} | |
public static String makeValidTTCN3Identifier(String id) | |
{ | |
/* "Identifier ::= <alpha> (<alnum> | <underscore>)*" */ | |
StringBuffer valid_ = new StringBuffer(); | |
final int size = id.length(); | |
if (size == 0) | |
{ | |
System.err | |
.println("Warning: Empty string is not a valid TTCN3 identifier."); | |
return id; | |
} | |
if (isalpha(id.charAt(0))) | |
{ | |
valid_.append(id.substring(0, 1)); | |
} | |
else | |
{ | |
valid_.append("X" + id.substring(0, 1)); | |
} | |
for (int i = 1; i < size; i++) | |
{ | |
if (!isalnum(id.charAt(i)) && id.charAt(i) != '_') | |
{ | |
valid_.append("_"); | |
} | |
else | |
{ | |
valid_.append(id.charAt(i)); | |
} | |
} | |
/* Postfix TTCN3 reserved words with '_' */ | |
String valid = valid_.toString(); | |
if (valid.equals("action") || valid.equals("fail") | |
|| valid.equals("named") || valid.equals("self") | |
|| valid.equals("activate") || valid.equals("false") | |
|| valid.equals("none") || valid.equals("send") | |
|| valid.equals("address") || valid.equals("float") | |
|| valid.equals("nonrecursive") || valid.equals("sender") | |
|| valid.equals("all") || valid.equals("for") | |
|| valid.equals("not") || valid.equals("set") | |
|| valid.equals("alt") || valid.equals("from") | |
|| valid.equals("not4b") || valid.equals("signature") | |
|| valid.equals("and") || valid.equals("function") | |
|| valid.equals("nowait") || valid.equals("start") | |
|| valid.equals("and4b") || valid.equals("null") | |
|| valid.equals("stop") || valid.equals("any") | |
|| valid.equals("get") || valid.equals("sut") | |
|| valid.equals("getcall") || valid.equals("objid") | |
|| valid.equals("system") || valid.equals("bitstring") | |
|| valid.equals("getreply") || valid.equals("octetstring") | |
|| valid.equals("boolean") || valid.equals("goto") | |
|| valid.equals("of") || valid.equals("template") | |
|| valid.equals("group") || valid.equals("omit") | |
|| valid.equals("testcase") || valid.equals("call") | |
|| valid.equals("on") || valid.equals("timeout") | |
|| valid.equals("catch") || valid.equals("hexstring") | |
|| valid.equals("optional") || valid.equals("timer") | |
|| valid.equals("char") || valid.equals("or") || valid.equals("to") | |
|| valid.equals("charstring") || valid.equals("if") | |
|| valid.equals("or4b") || valid.equals("trigger") | |
|| valid.equals("check") || valid.equals("ifpresent") | |
|| valid.equals("out") || valid.equals("true") | |
|| valid.equals("clear") || valid.equals("import") | |
|| valid.equals("override") || valid.equals("type") | |
|| valid.equals("complement") || valid.equals("in") | |
|| valid.equals("component") || valid.equals("inconc") | |
|| valid.equals("param") || valid.equals("union") | |
|| valid.equals("connect") || valid.equals("infinity") | |
|| valid.equals("pass") || valid.equals("universal") | |
|| valid.equals("const") || valid.equals("inout") | |
|| valid.equals("pattern") || valid.equals("unmap") | |
|| valid.equals("control") || valid.equals("integer") | |
|| valid.equals("port") || valid.equals("create") | |
|| valid.equals("interleave") || valid.equals("procedure") | |
|| valid.equals("value") || valid.equals("valueof") | |
|| valid.equals("deactivate") || valid.equals("label") | |
|| valid.equals("raise") || valid.equals("var") | |
|| valid.equals("disconnect") || valid.equals("language") | |
|| valid.equals("read") || valid.equals("verdict") | |
|| valid.equals("display") || valid.equals("length") | |
|| valid.equals("receive") || valid.equals("verdicttype") | |
|| valid.equals("do") || valid.equals("log") | |
|| valid.equals("record") || valid.equals("done") | |
|| valid.equals("rem") || valid.equals("while") | |
|| valid.equals("map") || valid.equals("repeat") | |
|| valid.equals("with") || valid.equals("else") | |
|| valid.equals("match") || valid.equals("reply") | |
|| valid.equals("encode") || valid.equals("message") | |
|| valid.equals("return") || valid.equals("xor") | |
|| valid.equals("enumerated") || valid.equals("mixed") | |
|| valid.equals("running") || valid.equals("xor4b") | |
|| valid.equals("error") || valid.equals("mod") | |
|| valid.equals("runs") || valid.equals("exception") | |
|| valid.equals("modifies") || valid.equals("execute") | |
|| valid.equals("module") || valid.equals("expand") | |
|| valid.equals("mtc") || valid.equals("extension") | |
|| valid.equals("external") || | |
/* special identifiers reserved for the predefined functions */ | |
valid.equals("int2char") || valid.equals("char2int") | |
|| valid.equals("int2unichar") || valid.equals("unichar2int") | |
|| valid.equals("bit2int") || valid.equals("hex2int") | |
|| valid.equals("int2bit") || valid.equals("int2hex") | |
|| valid.equals("int2oct") || valid.equals("int2str") | |
|| valid.equals("oct2int") || valid.equals("str2int") | |
|| valid.equals("lengthof") || valid.equals("sizeof") | |
|| valid.equals("ischosen") || valid.equals("ispresent")) | |
{ | |
return valid + "_"; | |
} | |
return valid; | |
} | |
} |