de.tla2bAst.ExpressionTranslator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of tla2bAST Show documentation
Show all versions of tla2bAST Show documentation
Translator from TLA+ to ProB's AST representation.
The newest version!
package de.tla2bAst;
import de.be4.classicalb.core.parser.node.Start;
import de.tla2b.analysis.SpecAnalyser;
import de.tla2b.analysis.SymbolRenamer;
import de.tla2b.analysis.TypeChecker;
import de.tla2b.exceptions.ExpressionTranslationException;
import de.tla2b.exceptions.TLA2BException;
import de.tla2b.exceptions.TLA2BFrontEndException;
import de.tla2b.exceptions.TypeErrorException;
import tla2sany.drivers.FrontEndException;
import tla2sany.drivers.InitException;
import tla2sany.drivers.SANY;
import tla2sany.modanalyzer.ParseUnit;
import tla2sany.modanalyzer.SpecObj;
import tla2sany.parser.ParseException;
import tla2sany.semantic.ModuleNode;
import tla2sany.st.SyntaxTreeConstants;
import tla2sany.st.TreeNode;
import util.ToolIO;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
public class ExpressionTranslator implements SyntaxTreeConstants {
private final String tlaExpression;
private final ArrayList variables = new ArrayList<>();
private final ArrayList noVariables = new ArrayList<>();
private Start expressionStart;
private ModuleNode moduleNode;
private String expr;
private Translator translator;
public Start getBExpressionParseUnit() {
return expressionStart;
}
public ExpressionTranslator(String tlaExpression) {
this.tlaExpression = tlaExpression;
}
public ExpressionTranslator(String tlaExpression, Translator translator) {
this.tlaExpression = tlaExpression;
this.translator = translator;
}
public void parse() {
String dir = System.getProperty("java.io.tmpdir");
ToolIO.setUserDir(dir);
File tempFile;
String moduleName;
String module;
try {
tempFile = File.createTempFile("Testing", ".tla");
moduleName = tempFile.getName().substring(0,tempFile.getName().indexOf("."));
module = "----MODULE " + moduleName + " ----\n" + "Expression == "
+ tlaExpression + "\n====";
FileWriter fw = new FileWriter(tempFile);
fw.write(module);
fw.close();
} catch (IOException e) {
throw new ExpressionTranslationException(
"Can not create temporary file in directory '" + dir + "'");
}
SpecObj spec = parseModuleWithoutSemanticAnalyse(moduleName, module);
evalVariables(spec, moduleName);
StringBuilder sb = new StringBuilder();
sb.append("----MODULE ").append(moduleName).append(" ----\n");
sb.append("EXTENDS Naturals, Integers, Reals, Sequences, FiniteSets \n");
if (!variables.isEmpty()) {
sb.append("VARIABLES ");
for (int i = 0; i < variables.size(); i++) {
if (i != 0) {
sb.append(", ");
}
sb.append(variables.get(i));
}
sb.append("\n");
}
sb.append("Expression");
sb.append(" == ");
sb.append(tlaExpression);
sb.append("\n====================");
try {
FileWriter fw = new FileWriter(tempFile);
fw.write(sb.toString());
fw.close();
tempFile.deleteOnExit();
} catch (IOException e) {
throw new ExpressionTranslationException(e.getMessage());
}
ToolIO.reset();
this.expr = sb.toString();
this.moduleNode = null;
try {
moduleNode = parseModule(moduleName, sb.toString());
} catch (TLA2BFrontEndException e) {
throw new ExpressionTranslationException(e.getLocalizedMessage());
}
}
public Start translateIncludingModel() throws TLA2BException {
SpecAnalyser specAnalyser = SpecAnalyser.createSpecAnalyserForTlaExpression(moduleNode);
TypeChecker tc = translator.getTypeChecker();
try {
// here we add typing for known identifiers from the module
tc.visitOpDefNode(specAnalyser.getExpressionOpdefNode());
} catch (TypeErrorException e) {
// ignore type errors; new free variables will always throw an exception here
// (they have no type, which is correct as they are not part of the module);
// real type errors are checked below
}
TypeChecker tc2 = new TypeChecker(moduleNode, specAnalyser);
try {
// here we add the typing for new variables
// the types of module variables are also checked
tc2.start();
} catch (TypeErrorException e) {
String message = "****TypeError****\n" + e.getLocalizedMessage() + "\n" + expr + "\n";
throw new ExpressionTranslationException(message);
}
SymbolRenamer.run(moduleNode, specAnalyser);
BAstCreator bASTCreator = new BAstCreator(moduleNode, specAnalyser);
this.expressionStart = bASTCreator.expressionStart;
return this.expressionStart;
}
public Start translateWithoutModel() {
SpecAnalyser specAnalyser = SpecAnalyser.createSpecAnalyserForTlaExpression(moduleNode);
TypeChecker tc = new TypeChecker(moduleNode, specAnalyser);
try {
tc.start();
} catch (TLA2BException e) {
String message = "****TypeError****\n" + e.getLocalizedMessage()
+ "\n" + expr + "\n";
throw new ExpressionTranslationException(message);
}
SymbolRenamer.run(moduleNode, specAnalyser);
BAstCreator bASTCreator = new BAstCreator(moduleNode, specAnalyser);
this.expressionStart = bASTCreator.expressionStart;
return this.expressionStart;
}
@Deprecated
public Start translate() {
return this.translateWithoutModel();
}
public static ModuleNode parseModule(String moduleName, String module)
throws TLA2BFrontEndException {
SpecObj spec = new SpecObj(moduleName, null);
try {
SANY.frontEndMain(spec, moduleName, ToolIO.out);
} catch (FrontEndException e) {
// Error in Frontend, should never happen
throw new TLA2BFrontEndException("Frontend error! This should never happen.", spec);
}
if (spec.parseErrors.isFailure()) {
String message = module + "\n\n" + spec.parseErrors + allMessagesToString(ToolIO.getAllMessages());
throw new TLA2BFrontEndException(message, spec);
}
if (spec.semanticErrors.isFailure()) {
String message = module + "\n\n" + spec.semanticErrors + allMessagesToString(ToolIO.getAllMessages());
throw new TLA2BFrontEndException(message, spec);
}
// RootModule
ModuleNode n = spec.getExternalModuleTable().rootModule;
if (spec.getInitErrors().isFailure()) {
System.err.println(spec.getInitErrors());
throw new TLA2BFrontEndException(allMessagesToString(ToolIO.getAllMessages()), spec);
}
if (n == null) { // Parse Error
// System.out.println("Rootmodule null");
throw new TLA2BFrontEndException(
allMessagesToString(ToolIO.getAllMessages()), spec);
}
return n;
}
private SpecObj parseModuleWithoutSemanticAnalyse(String moduleFileName,
String module) {
SpecObj spec = new SpecObj(moduleFileName, null);
try {
SANY.frontEndInitialize(spec, ToolIO.out);
SANY.frontEndParse(spec, ToolIO.out);
} catch (InitException | ParseException e1) {
System.out.println(e1);
}
if (spec.parseErrors.isFailure()) {
String message = module + "\n\n";
message += allMessagesToString(ToolIO.getAllMessages());
throw new ExpressionTranslationException(message);
}
return spec;
}
private void evalVariables(SpecObj spec, String moduleName) {
ParseUnit p = spec.parseUnitContext.get(moduleName);
TreeNode n_module = p.getParseTree();
TreeNode n_body = n_module.heirs()[2];
TreeNode n_operatorDefintion = n_body.heirs()[0];
TreeNode expr = n_operatorDefintion.heirs()[2];
searchVarInSyntaxTree(expr);
// this code seems to assume that there is no variable clash between outer and nested variables
// I guess the parser will then generate "Multiply-defined symbol ..." errors
for (String noVariable : noVariables) {
variables.remove(noVariable);
}
}
private final static Set KEYWORDS = new HashSet<>();
static {
KEYWORDS.add("BOOLEAN");
KEYWORDS.add("TRUE");
KEYWORDS.add("FALSE");
KEYWORDS.add("Nat");
KEYWORDS.add("Int");
KEYWORDS.add("Real");
KEYWORDS.add("Cardinality");
KEYWORDS.add("IsFiniteSet");
KEYWORDS.add("Append");
KEYWORDS.add("Head");
KEYWORDS.add("Tail");
KEYWORDS.add("Len");
KEYWORDS.add("Seq");
KEYWORDS.add("SubSeq");
KEYWORDS.add("SelectSeq");
KEYWORDS.add("MinOfSet");
KEYWORDS.add("MaxOfSet");
KEYWORDS.add("SetProduct");
KEYWORDS.add("SetSummation");
KEYWORDS.add("PermutedSequences");
KEYWORDS.add("@");
}
/**
*
*/
private void searchVarInSyntaxTree(TreeNode treeNode) {
// System.out.println(treeNode.getKind() + " " + treeNode.getImage());
switch (treeNode.getKind()) {
case N_GeneralId: {
String con = treeNode.heirs()[1].getImage();
if (!variables.contains(con) && !KEYWORDS.contains(con)) {
variables.add(con);
}
break;
}
case N_IdentLHS: { // left side of a definition
TreeNode[] children = treeNode.heirs();
noVariables.add(children[0].getImage());
break;
}
case N_IdentDecl: { // parameter of a LET definition
// e.g. x in LET foo(x) == e
noVariables.add(treeNode.heirs()[0].getImage());
break;
}
case N_FunctionDefinition: {
// the first child is the function name
noVariables.add(treeNode.heirs()[0].getImage());
break;
}
case
N_UnboundQuant: { // TODO: check: is this an unbounded quantifier with infinite domain or a quantifier that does not hide the quantified variables?
TreeNode[] children = treeNode.heirs();
for (int i = 1; i < children.length - 2; i = i + 2) {
// System.out.println("N_UnboundQuant: "+children[i].getImage());
}
searchVarInSyntaxTree(treeNode.heirs()[children.length - 1]);
break;
}
case N_UnboundOrBoundChoose: { // not sure the format is the same as N_QuantBound
TreeNode[] children = treeNode.heirs();
for (int i = 1; i < children.length - 2; i = i + 2) {
String boundedVar = children[i].getImage();
// typically children[i+1] is N_MaybeBound
if (!noVariables.contains(boundedVar)) {
noVariables.add(boundedVar);
//System.out.println("CHOOSE quantified variable: " + boundedVar);
}
}
searchVarInSyntaxTree(treeNode.heirs()[children.length - 1]);
break;
}
case N_QuantBound: {
TreeNode[] children = treeNode.heirs();
for (int i = 0; i < children.length - 2; i = i + 2) {
String boundedVar = children[i].getImage();
if (!noVariables.contains(boundedVar)) {
noVariables.add(boundedVar);
// System.out.println("N_QuantBound: locally quantified variable" + boundedVar);
}
}
searchVarInSyntaxTree(treeNode.heirs()[children.length - 1]);
break;
}
case N_SubsetOf: { // { x \in S : e }
TreeNode[] children = treeNode.heirs();
String boundedVar = children[1].getImage(); // x
if (!noVariables.contains(boundedVar)) {
noVariables.add(boundedVar);
}
searchVarInSyntaxTree(treeNode.heirs()[3]); // S
searchVarInSyntaxTree(treeNode.heirs()[5]); // e
break;
}
}
for (int i = 0; i < treeNode.heirs().length; i++) {
searchVarInSyntaxTree(treeNode.heirs()[i]);
}
}
public static String allMessagesToString(String[] allMessages) {
return Translator.allMessagesToString(allMessages);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy