All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.tla2bAst.Translator Maven / Gradle / Ivy

The newest version!
package de.tla2bAst;

import de.be4.classicalb.core.parser.BParser;
import de.be4.classicalb.core.parser.Definitions;
import de.be4.classicalb.core.parser.analysis.prolog.RecursiveMachineLoader;
import de.be4.classicalb.core.parser.exceptions.BCompoundException;
import de.be4.classicalb.core.parser.exceptions.PreParseException;
import de.be4.classicalb.core.parser.node.Node;
import de.be4.classicalb.core.parser.node.Start;
import de.be4.classicalb.core.parser.util.PrettyPrinter;
import de.be4.classicalb.core.parser.util.SuffixIdentifierRenaming;
import de.hhu.stups.sablecc.patch.PositionedNode;
import de.prob.prolog.output.PrologTermOutput;
import de.tla2b.analysis.*;
import de.tla2b.config.ConfigfileEvaluator;
import de.tla2b.config.ModuleOverrider;
import de.tla2b.exceptions.TLA2BFrontEndException;
import de.tla2b.exceptions.TLA2BException;
import de.tla2b.global.TranslationGlobals;
import de.tla2b.output.TlaTypePrinter;
import de.tla2b.translation.BMacroHandler;
import de.tla2b.translation.RecursiveFunctionHandler;
import de.tla2b.types.TLAType;
import de.tla2b.util.FileUtils;
import tla2sany.drivers.FrontEndException;
import tla2sany.drivers.SANY;
import tla2sany.modanalyzer.SpecObj;
import tla2sany.semantic.ModuleNode;
import tlc2.tool.impl.ModelConfig;
import util.ToolIO;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Map;
import java.util.List;
import java.util.stream.Collectors;

public class Translator implements TranslationGlobals {
	private static final String GENERATED_BY_TLA2B_HEADER = "/*@ generated by TLA2B ";

	private String parentPath;
	private File moduleFile;
	private File configFile;
	private List moduleFiles = new ArrayList<>();

	private BAstCreator bAstCreator;

	// private String moduleName;
	private ModuleNode moduleNode;
	private ModelConfig modelConfig;

	private SpecAnalyser specAnalyser;
	private TypeChecker typechecker;

	public Translator(String moduleFileName) throws TLA2BFrontEndException {
		this.moduleFile = new File(moduleFileName);
		if (!moduleFile.exists()) {
			throw new RuntimeException("Can not find module file: '" + moduleFileName + "'");
		}
		try {
			this.moduleFile = moduleFile.getCanonicalFile();
		} catch (IOException e) {
			throw new RuntimeException("Can not access module file: '" + moduleFileName + "'");
		}
		this.parentPath = moduleFile.getParent() == null ? "." : moduleFile.getParent();

		this.configFile = new File(FileUtils.removeExtension(moduleFile.getAbsolutePath()) + ".cfg");
		if (!configFile.exists()) {
			this.configFile = null;
		}

		parse();
	}

	/**
	 * External interface
	 */
	public static String translateModuleString(String moduleName, String moduleString, String configString)
		throws TLA2BException {
		Translator translator = new Translator(moduleName, moduleString, configString);
		Start bAST = translator.getBAST();
		PrettyPrinter pp = new PrettyPrinter();
		pp.setRenaming(new SuffixIdentifierRenaming());
		bAST.apply(pp);
		return pp.getPrettyPrint();
	}

	public Translator(String moduleName, String moduleString, String configString) throws TLA2BException {
		createTLATempFile(moduleString, moduleName);
		createCfgFile(configString, moduleName);
		parse();
		translate();
	}

	// Used for Testing in tla2bAST project
	public Translator(String moduleString, String configString) throws TLA2BFrontEndException {
		String moduleName = "Testing";
		createTLATempFile(moduleString, moduleName);
		createCfgFile(configString, moduleName);
		parse();
	}

	private void createTLATempFile(String moduleString, String moduleName) {
		File dir = new File("temp/");
		dir.mkdirs();
		dir.deleteOnExit();

		moduleFile = new File("temp/" + moduleName + ".tla");
		try (BufferedWriter out = Files.newBufferedWriter(moduleFile.toPath(), StandardCharsets.UTF_8)) {
			out.write(moduleString);
		} catch (IOException e) {
			System.err.println("Error while writing file '" + moduleFile.getAbsolutePath() + "':\n" + e.getMessage());
		}
	}

	private void createCfgFile(String configString, String moduleName) {
		modelConfig = null;
		if (configString != null) {
			configFile = new File("temp/" + moduleName + ".cfg");
			try (BufferedWriter out = Files.newBufferedWriter(configFile.toPath(), StandardCharsets.UTF_8)) {
				out.write(configString);
			} catch (IOException e) {
				System.err.println("Error while writing file '" + configFile.getAbsolutePath() + "':\n" + e.getMessage());
			}
		}
	}

	private void parse() throws TLA2BFrontEndException {
		moduleNode = parseModule();

		modelConfig = null;
		if (configFile != null) {
			modelConfig = new ModelConfig(configFile.getAbsolutePath(), new SimpleResolver());
			modelConfig.parse();
		}
	}

	public ModuleNode parseModule() throws TLA2BFrontEndException {
		String fileName = moduleFile.getName();
		ToolIO.setUserDir(moduleFile.getParent());

		SpecObj spec = new SpecObj(fileName, null);
		try {
			SANY.frontEndMain(spec, fileName, ToolIO.out);
		} catch (FrontEndException e) {
			// should never happen
			throw new RuntimeException("Could not parse module: '" + fileName + "'", e);
		}

		if (spec.getParseErrors().isFailure()) {
			throw new TLA2BFrontEndException(allMessagesToString(ToolIO.getAllMessages()) + spec.getParseErrors(), spec);
		}

		if (spec.getSemanticErrors().isFailure()) {
			throw new TLA2BFrontEndException(allMessagesToString(ToolIO.getAllMessages()) + spec.getSemanticErrors(), spec);
		}

		// RootModule
		ModuleNode n = spec.getExternalModuleTable().getRootModule();
		if (spec.getInitErrors().isFailure()) {
			throw new TLA2BFrontEndException(spec.getInitErrors().toString(), spec);
		}

		if (n == null) { // Parse Error
			throw new TLA2BFrontEndException(allMessagesToString(ToolIO.getAllMessages()), spec);
		}

		return n;
	}

	public static String allMessagesToString(String[] allMessages) {
		return String.join("\n", allMessages) + "\n";
	}

	public Start translate() throws TLA2BException {
		InstanceTransformation.run(moduleNode);
		SymbolSorter.sort(moduleNode);

		ConfigfileEvaluator conEval = null;
		if (modelConfig != null) {
			conEval = new ConfigfileEvaluator(modelConfig, moduleNode);
			conEval.start();

			ModuleOverrider.run(moduleNode, conEval);
			specAnalyser = SpecAnalyser.createSpecAnalyser(moduleNode, conEval);
		} else {
			specAnalyser = SpecAnalyser.createSpecAnalyser(moduleNode);
		}
		specAnalyser.start();
		typechecker = new TypeChecker(moduleNode, conEval, specAnalyser);
		typechecker.start();
		SymbolRenamer.run(moduleNode, specAnalyser);
		bAstCreator = new BAstCreator(moduleNode, conEval, specAnalyser,
				new UsedExternalFunctions(moduleNode, specAnalyser),
				new PredicateVsExpression(moduleNode),
				new BMacroHandler(specAnalyser, conEval),
				new RecursiveFunctionHandler(specAnalyser));

		this.moduleFiles = bAstCreator.getFilesOrderedById().stream()
				.map(file -> new File(parentPath, file + ".tla")).collect(Collectors.toList());
		return getBAST();
	}

	public void createProbFile() {
		File probFile = new File(FileUtils.removeExtension(moduleFile.getAbsolutePath()) + ".prob");

		BParser bParser = new BParser();
		try (BufferedWriter outWriter = Files.newBufferedWriter(probFile.toPath(), StandardCharsets.UTF_8)) {
			bParser.getDefinitions().addDefinitions(getBDefinitions());
			final RecursiveMachineLoader rml = parseAllMachines(getBAST(), getModuleFile(), bParser);
			rml.printAsProlog(new PrologTermOutput(outWriter, false));
			System.out.println(probFile.getAbsolutePath() + " created.");
		} catch (BCompoundException | IOException | PreParseException e) {
			System.err.println(e.getMessage());
			System.exit(-1);
		}
	}

	public void createMachineFile() {
		File machineFile = new File(FileUtils.removeExtension(moduleFile.getAbsolutePath()) + "_tla.txt");
		if (machineFile.exists()) {
			try (BufferedReader in = new BufferedReader(new FileReader(machineFile))) {
				String firstLine = in.readLine();
				if (firstLine != null && !firstLine.startsWith(GENERATED_BY_TLA2B_HEADER)) {
					System.err.println("Error: File " + machineFile.getName() + " already exists"
						+ " and was not generated by TLA2B.\n" + "Delete or move this file.");
					System.exit(-1);
				}
			} catch (IOException e) {
				System.err.println(e.getMessage());
				System.exit(-1);
			}
		}

		PrettyPrinter pp = new PrettyPrinter();
		pp.setRenaming(new SuffixIdentifierRenaming());
		getBAST().apply(pp);
		try (BufferedWriter out = Files.newBufferedWriter(machineFile.toPath(), StandardCharsets.UTF_8)) {
			out.write(GENERATED_BY_TLA2B_HEADER + VERSION_NUMBER + " */\n" + pp.getPrettyPrint());
			System.out.println("B-Machine " + machineFile.getAbsolutePath() + " created.");
		} catch (IOException e) {
			System.err.println("Error while creating file '" + machineFile.getAbsolutePath() + "':\n" + e.getMessage());
			System.exit(-1);
		}
	}

	public RecursiveMachineLoader parseAllMachines(final Start ast, final File f, final BParser bparser) throws BCompoundException {
		final RecursiveMachineLoader rml = new RecursiveMachineLoader(parentPath, bparser.getContentProvider());
		rml.loadAllMachines(f, ast, bparser.getDefinitions());

		// Create the assignment of nodes to TLA modules:
		// manipulate loaded files in RML: this is necessary for printing ALL included module file names in rml.printAsProlog
		// per default only the main module (startFile) is included
		rml.getMachineFilesLoaded().clear(); // clear to ensure correct order of file numbers assigned below
		rml.getMachineFilesLoaded().addAll(this.moduleFiles);
		for (PositionedNode node : bAstCreator.getSourcePositions()) {
			// Overwrite node ID mapping with the assignment that is created when positioned nodes are created
			rml.getNodeIdMapping().assignIdentifiers(bAstCreator.getNodeFileNumbers().lookupFileNumber((Node) node), (Node) node);
		}
		// this is required for correct positions in ProB2(-UI) when rml.printAsProlog is called
		rml.setPositionPrinter(new TlaTypePrinter(rml.getNodeIdMapping(), bAstCreator.getTypes()));
		return rml;
	}

	public Start translateExpressionIncludingModel(String tlaExpression) throws TLA2BException {
		ExpressionTranslator expressionTranslator = new ExpressionTranslator(tlaExpression, this);
		expressionTranslator.parse();
		return expressionTranslator.translateIncludingModel();
	}

	@Deprecated
	public Start translateExpression(String tlaExpression) throws TLA2BException {
		return this.translateExpressionIncludingModel(tlaExpression);
	}

	public static Start translateExpressionWithoutModel(String tlaExpression) {
		ExpressionTranslator expressionTranslator = new ExpressionTranslator(tlaExpression);
		expressionTranslator.parse();
		return expressionTranslator.translateWithoutModel();
	}

	@Deprecated
	public static Start translateTlaExpression(String tlaExpression) {
		return translateExpressionWithoutModel(tlaExpression);
	}

	public Definitions getBDefinitions() {
		return bAstCreator.getBDefinitions();
	}

	public ModuleNode getModuleNode() {
		return moduleNode;
	}

	protected TypeChecker getTypeChecker() {
		return this.typechecker;
	}

	protected SpecAnalyser getSpecAnalyser() {
		return this.specAnalyser;
	}

	public Start getBAST() {
		return bAstCreator.getStartNode();
	}

	public File getModuleFile() {
		return moduleFile;
	}

	public List getModuleFiles() {
		return Collections.unmodifiableList(moduleFiles);
	}

	public Map getTypes() {
		return bAstCreator.getTypes();
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy