package org.sugarj.driver.transformations.primitive; import java.io.IOException; import java.util.Collection; import java.util.HashSet; import java.util.TreeSet; import org.spoofax.interpreter.core.IContext; import org.spoofax.interpreter.core.InterpreterException; import org.spoofax.interpreter.library.AbstractPrimitive; import org.spoofax.interpreter.stratego.Strategy; import org.spoofax.interpreter.terms.IStrategoTerm; import org.spoofax.jsglr.shared.BadTokenException; import org.sugarj.common.ATermCommands; import org.sugarj.common.Environment; import org.sugarj.common.FileCommands; import org.sugarj.common.Log; import org.sugarj.common.path.AbsolutePath; import org.sugarj.common.path.Path; import org.sugarj.common.path.RelativePath; import org.sugarj.driver.Driver; import org.sugarj.driver.ImportCommands; import org.sugarj.driver.ModuleSystemCommands; import org.sugarj.driver.Result; import org.sugarj.util.Renaming; /** * Primitive for looking up and loading a model according to the current environment. * If successful, this primitive returns the loaded model as a term. * * @author seba */ class CompileTransformed extends AbstractPrimitive { private Driver driver; private Environment environment; public CompileTransformed(Driver driver, Environment environment) { super("SUGARJ_compile", 0, 2); this.driver = driver; this.environment = environment; } @Override public boolean call(IContext context, Strategy[] svars, IStrategoTerm[] tvars) throws InterpreterException { try { IStrategoTerm generatedModel = context.current(); if (!ATermCommands.isString(tvars[0]) || !ATermCommands.isString(tvars[1])) return false; String modelPath = ATermCommands.getString(tvars[0]); RelativePath modelRelativePath = new RelativePath(modelPath); IStrategoTerm transformationsTerm = tvars[1]; RelativePath transformationPath = new RelativePath(ATermCommands.getString(transformationsTerm)); RelativePath source = ImportCommands.getTransformedModelSourceFilePath(modelRelativePath, transformationPath, environment); try { Renaming ren = new Renaming(modelPath, source.getRelativePath()); environment.getRenamings().add(0, ren); // generatedModel = driver.currentRename(generatedModel); driver.getCurrentResult().generateFile(source, ATermCommands.atermToString(generatedModel)); } catch (IOException e) { driver.setErrorMessage(e.getLocalizedMessage()); } Result res; try { res = driver.subcompile(driver.getTreeForErrorMarking(), source); if (res != null) { context.setCurrent(ATermCommands.atermFromFile(source.getAbsolutePath())); Result modelResult = ModuleSystemCommands.locateResult(FileCommands.dropExtension(modelPath), environment); if (modelResult != null) res.addDependency(modelResult); Result transformationResult = ModuleSystemCommands.locateResult(FileCommands.dropExtension(transformationPath.getRelativePath()), environment); if (transformationResult != null) res.addDependency(transformationResult); } } catch (Exception e) { e.printStackTrace(); driver.setErrorMessage(e.getMessage()); return false; } finally { environment.getRenamings().remove(0); } if (res == null) return false; try { if (res.hasFailed()) { for (BadTokenException e : res.getParseErrors()) driver.setErrorMessage("line " + e.getLineNumber() + ": " + e.getLocalizedMessage()); for (String err : res.getCollectedErrors()) driver.setErrorMessage(err); return false; } checkCommunicationIntegrity(modelPath, transformationPath, source, res); } catch (IOException e) { e.printStackTrace(); driver.setErrorMessage(e.getMessage()); } catch (ClassNotFoundException e) { e.printStackTrace(); driver.setErrorMessage(e.getMessage()); } catch (Exception e) { e.printStackTrace(); driver.setErrorMessage(e.getMessage()); } } catch (Exception e) { e.printStackTrace(); driver.setErrorMessage(e.getMessage()); } return true; } private void checkCommunicationIntegrity(String modelPath, RelativePath transformationPath, RelativePath source, Result res) throws IOException, ClassNotFoundException { String error = null; Log.log.beginTask("Check communication integrity", Log.CORE); try { Collection<Path> modelDeps = new HashSet<Path>(); Result modelResult = ModuleSystemCommands.locateResult(FileCommands.dropExtension(modelPath), environment); if (modelResult != null) { modelDeps.addAll(modelResult.getCircularFileDependencies(environment)); modelDeps.addAll(modelResult.getDirectlyGeneratedFiles()); } Collection<Path> transDeps = new HashSet<Path>(); Result transResult = ModuleSystemCommands.locateResult(FileCommands.dropExtension(transformationPath.getRelativePath()), environment); if (transResult != null) { transDeps.addAll(transResult.getCircularFileDependencies(environment)); transDeps.addAll(transResult.getDirectlyGeneratedFiles()); } if (res.getPersistentPath() == null) res.writeDependencyFile(FileCommands.newTempFile("dep")); Collection<Path> transformedModelDeps = res.getCircularFileDependencies(environment); TreeSet<String> failed = new TreeSet<String>(); for (Path p : transformedModelDeps) { boolean ok = false || source.equals(p) || res.getDirectlyGeneratedFiles().contains(p) || modelDeps.contains(p) || transDeps.contains(p); Result pRes = null; if (!ok) { // transformations may generate other artifacts, given that their dependencies in turn are marked in the current result Path dep = new AbsolutePath(FileCommands.dropExtension(p.getAbsolutePath()) + ".dep"); if (FileCommands.exists(dep)) { pRes = Result.readDependencyFile(dep); if (pRes != null && pRes.isGenerated()) { boolean isContained = transformedModelDeps.containsAll(pRes.getCircularFileDependencies(environment)); ok = isContained; } } } if (!ok) failed.add(FileCommands.dropExtension(p.getAbsolutePath())); } if (!failed.isEmpty()) { StringBuilder b = new StringBuilder("Violation of communication integrity in " + source.getRelativePath() + ": Generated model refers to the following artifacts, which neither the model nor the transformation refers to.\n"); for (String p : failed) b.append(" ").append(p).append('\n'); error = b.toString(); driver.setErrorMessage(error); } } finally { if (error == null) Log.log.endTask(true); else Log.log.endTask(error); } } }