From 3b2752183f58f2fe10151e138be7a805acc7cb4a Mon Sep 17 00:00:00 2001 From: fjouault Date: Mon, 5 Jan 2015 17:39:33 +0100 Subject: moved inject and extract methods into new class AbstractLanguage AbstractLanguage may be reused by other implementations of Language so that they do not need to reimplement inject and extract.--- .../eclipse/gmt/tcs/metadata/AbstractLanguage.java | 405 +++++++++++++++++++++ .../gmt/tcs/metadata/adhoc/WorkspaceLanguage.java | 321 ++++------------ 2 files changed, 476 insertions(+), 250 deletions(-) create mode 100644 plugins/org.eclipse.gmt.tcs.metadata/src/org/eclipse/gmt/tcs/metadata/AbstractLanguage.java diff --git a/plugins/org.eclipse.gmt.tcs.metadata/src/org/eclipse/gmt/tcs/metadata/AbstractLanguage.java b/plugins/org.eclipse.gmt.tcs.metadata/src/org/eclipse/gmt/tcs/metadata/AbstractLanguage.java new file mode 100644 index 0000000..e89178f --- /dev/null +++ b/plugins/org.eclipse.gmt.tcs.metadata/src/org/eclipse/gmt/tcs/metadata/AbstractLanguage.java @@ -0,0 +1,405 @@ +/** + * Copyright (c) 2015 ESEO. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * ESEO - initial API and implementation + * + * $Id$ + */ +package org.eclipse.gmt.tcs.metadata; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.emf.ecore.EObject; +import org.eclipse.gmt.tcs.extractor.ModelAdapter; +import org.eclipse.gmt.tcs.extractor.TCSExtractor; +import org.eclipse.gmt.tcs.injector.ASMModelAdapter; +import org.eclipse.gmt.tcs.injector.ElementTrace; +import org.eclipse.gmt.tcs.metadata.adhoc.TCSInjection; +import org.eclipse.gmt.tcs.metadata.adhoc.VirtualExtractorModelAdapter; +import org.eclipse.gmt.tcs.metadata.adhoc.VirtualModelAdapter; +import org.eclipse.m2m.atl.core.IModel; +import org.eclipse.m2m.atl.core.IReferenceModel; +import org.eclipse.m2m.atl.core.emf.EMFInjector; +import org.eclipse.m2m.atl.core.emf.EMFModelFactory; +import org.eclipse.m2m.atl.core.launch.ILauncher; +import org.eclipse.m2m.atl.drivers.emf4atl.ASMEMFModel; +import org.eclipse.m2m.atl.drivers.emf4atl.ASMEMFModelElement; +import org.eclipse.m2m.atl.drivers.emf4atl.EMFModelLoader; +import org.eclipse.m2m.atl.dsls.DSLResourceProvider; +import org.eclipse.m2m.atl.dsls.tcs.injector.CompletionInformation; +import org.eclipse.m2m.atl.dsls.textsource.TextSource; +import org.eclipse.m2m.atl.engine.emfvm.StackFrame; +import org.eclipse.m2m.atl.engine.emfvm.VMException; +import org.eclipse.m2m.atl.engine.emfvm.launch.EMFVMLauncher; +import org.eclipse.m2m.atl.engine.emfvm.lib.AbstractStackFrame; +import org.eclipse.m2m.atl.engine.emfvm.lib.ExecEnv; +import org.eclipse.m2m.atl.engine.emfvm.lib.LibExtension; +import org.eclipse.m2m.atl.engine.emfvm.lib.Operation; +import org.eclipse.m2m.atl.engine.emfvm.lib.Tuple; +import org.eclipse.m2m.atl.engine.vm.AtlModelHandler; +import org.eclipse.m2m.atl.engine.vm.nativelib.ASMModel; + +/** + * This Language implements generic inject and extract methods by relying abstract methods to access + * required resources. + * A concrete subclass must implement these abstract methods in addition to all missing methods from + * Language, but can rely on the generic inject and extract methos. + * + * @author Frédéric Jouault + */ +public abstract class AbstractLanguage implements Language { + public Object inject(ModelFactory factory, Object model, TextSource source, final Map params) { + try { + params.put("name", this.getName()); + // TODO: support multiple parserGenerators + //params.put("parserGenerator", getParserGenerator()); // not specifying any parserGenerator will default to antlr3 + + Object metamodel = getMetamodel(factory); + + // Grab a reference to problemModel now, because if we get it after the injection, + // it may have been replaced by a model adapter. + Object problemModel = params.get("problems"); + + if(model == null) { + model = factory.newModel("model.xmi", metamodel); + } + final Object model_ = model; + + final Map hyperlinks = (Map)params.get("hyperlinks"); + final Map locations = (Map)params.get("locationByElement"); + Map trace_ = (Map)params.get("trace"); + if((hyperlinks != null) && (trace_ == null)) { + trace_ = new HashMap(); + params.put("trace", trace_); + } + final Map trace = trace_; + + final VirtualModelAdapter vma = new VirtualModelAdapter(new ASMModelAdapter(model)); + params.put("modelAdapter", vma); + + Object ret = TCSInjection.inject(factory, model, metamodel, source, params, this.getJarURL()); + + final ExecEnv execEnv_[] = new ExecEnv[1]; + if(problemModel != null) { + + // TODO: only if no parsing error? + VMLauncher vmLauncher = (VMLauncher)params.get("vmLauncher"); + if(vmLauncher != null) { + if(this.hasWFR()) { + /* + Map libraries = new HashMap(); + libraries.put("TCSVirtualProperties", vma.getLibrary(name)); + String libNameAndPathsCSV = getProperty("wfr.libraries"); + if(libNameAndPathsCSV != null) { + String libNameAndPaths[] = libNameAndPathsCSV.split(","); + for(int i = 0 ; i < libNameAndPaths.length ; i++) { + String parts[] = libNameAndPaths[i].split("="); + libraries.put(parts[0], project.getFile(parts[1]).getLocationURI().toURL()); + } + } + Map models = new HashMap(); + models.put(name, metamodel); + models.put("IN", ret); + models.put("Problem", factory.metamodelOf(problemModel)); + models.put("OUT", problemModel); + vmLauncher.launch(wfrFile.getLocationURI().toURL(), models, libraries); + */ + // override VM Launcher to use EMFVM + ILauncher launcher = new EMFVMLauncher(); + launcher.initialize(Collections.emptyMap()); + + EMFModelFactory emfFac = new EMFModelFactory(); + + IReferenceModel pbMM = emfFac.newReferenceModel(); + new EMFInjector().inject(pbMM, ((ASMEMFModel)factory.metamodelOf(problemModel)).getExtent()); + + IReferenceModel mm = emfFac.newReferenceModel(); + new EMFInjector().inject(mm, ((ASMEMFModel)factory.metamodelOf(model)).getExtent()); + + IModel m = emfFac.newModel(mm); + new EMFInjector().inject(m, ((ASMEMFModel)model).getExtent()); + + IModel pbM = emfFac.newModel(pbMM); + new EMFInjector().inject(pbM, ((ASMEMFModel)problemModel).getExtent()); + + launcher.addInModel(mm, this.getName(), "MOF"); + launcher.addInModel(m, "IN", this.getName()); + launcher.addInModel(pbMM, "Problem", "MOF"); + launcher.addOutModel(pbM, "OUT", "Problem"); + + try { + this.addWFRLibraries(launcher); + + Map options = new HashMap(); + List extensionObjects = new ArrayList(); + extensionObjects.add(new LibExtension() { + public void apply(ExecEnv execEnv, Map options) { + execEnv_[0] = execEnv; + // allVirtualProperties global/context-less helper => not possible here because ASMModule + // only created after extensions are called. + // Workaround: register on String (for no specific reason (could be any other type)). + final Set allProperties = vma.getAllProperties(); + + // We keep document order. Until GenericResolver can topologically sort, we must make sure to return in the same order. + // Actually, it should be metamodel order (closer to external resolver with specific metamodel), but document order is even better + // (closer to internal resolver, and therefore same best practices, such as only looking in a reference resolved before, apply). + execEnv.registerOperation(String.class, new Operation(1, "allVirtualProperties") { + public Object exec(AbstractStackFrame frame) { + return allProperties; + } + }); + + final CompletionInformation ci = (CompletionInformation)params.get("completionInformation"); + execEnv.registerOperation(String.class, new Operation(1, "offsetToComplete") { + public Object exec(AbstractStackFrame frame) { + if(ci != null) { + return Integer.valueOf(ci.getOffset()); + } else { + return null; + } + } + }); + + if(params.containsKey("hyperlinks")) { + execEnv.registerOperation(String.class, new Operation(4, "addHyperlink") { + public Object exec(AbstractStackFrame frame) { + Object locals[] = frame.getLocalVars(); + // TODO: generalize this + Object source = ((ASMEMFModel)model_).getASMModelElement((EObject)locals[1]); + Object target = ((ASMEMFModel)model_).getASMModelElement((EObject)locals[3]); + hyperlinks.put( + ((ElementTrace)trace.get(source)).getPropertyLocation((String)locals[2]), + locations.get(target) + ); + return null; + } + }); + } + + // register weaving helpers used to represent virtual properties + for(Iterator i = allProperties.iterator() ; i.hasNext() ; ) { + Tuple t = (Tuple)i.next(); + Object type = t.get(null, "eContainingClass"); + String name = (String)t.get(null, "name"); + execEnv.registerWeavingHelper(type, name, null); + } + + // store values + for(Iterator i = vma.getVirtualProperties().entrySet().iterator() ; i.hasNext() ; ) { + Map.Entry ei = (Map.Entry)i.next(); + Object element = ei.getKey(); + if(element instanceof ASMEMFModelElement) { + element = ((ASMEMFModelElement)element).getObject(); + } + // + Map slots = (Map)ei.getValue(); + for(Iterator j = slots.entrySet().iterator() ; j.hasNext() ; ) { + Map.Entry ej = (Map.Entry)j.next(); + String propertyName = (String)ej.getKey(); + Object value = ej.getValue(); + execEnv.setHelperValue(element, propertyName, value); + } + } + } + }); + + options.put("extensionObjects", extensionObjects); + launcher.launch(ILauncher.RUN_MODE, null, options, new Object[] {this.getWFR()}); + } catch(IOException ioe) { + throw new RuntimeException("could not run WFR transformation", ioe); + } catch(VMException vme) { + vme.printStackTrace(); + } + } + } + } + CompletionInformation ci = (CompletionInformation)params.get("completionInformation"); + if(ci != null) { + if((ci.getProposals().size() == 1) && (ci.getProposals().get(0) instanceof Object[])) { + // deal with external resolver information here + Object args[] = (Object[])ci.getProposals().get(0); + ci.getProposals().clear(); + + if(execEnv_[0] != null) { + EObject ame = ((ASMEMFModelElement)args[0]).getObject(); + String propertyName = (String)args[1]; + String prefix = (String)args[2]; + + ExecEnv execEnv = execEnv_[0]; + Operation op = execEnv.getOperation(ame.eClass(), "getCompletionProposals"); + if(op != null) { + StackFrame stackFrame = new StackFrame(execEnv, null, op); + Object localVars[] = new Object[op.getMaxLocals()]; + localVars[0] = ame; + localVars[1] = propertyName; + stackFrame.setLocalVars(localVars); + Object proposals = op.exec(stackFrame); + // if(proposals instanceof OclUndefined || ret instanceof ASMOclUndefined) { + // ret = null; + // } + // return ret; + ci.getProposals().addAll((Collection)proposals); + ci.setPrefix(prefix); + System.out.println(prefix + " " + proposals); + } + } + } + } + if(hyperlinks != null) { + // Change target to location of "name" attribute if it exists. + + // TODO: + // - make this optional + // - make this generic (i.e., use refersTo information) + // - make it doable from transformation (need to represent ElementTraces as model) + + Map newLocationFromOld = new HashMap(); // only for those that change + for(Iterator i = locations.entrySet().iterator() ; i.hasNext() ; ) { + Map.Entry entry = (Map.Entry)i.next(); + Object element = entry.getKey(); + ElementTrace et = (ElementTrace)trace.get(element); + if(et != null) { + Object newLocation = et.getPropertyLocation("name"); + if(newLocation != null) { + Object oldLocation = entry.getValue(); + newLocationFromOld.put(oldLocation, newLocation); + } + } else { + // e.g., auto-created elements + } + } + + // Remarks: + // - after this transformation, text hovers may be incomplete if hyperlinks are used for this purpose + // => therefore special "ofn=" (old from new) hyperlinks are added + Map oldLocationFromNew = new HashMap(); + for(Iterator i = hyperlinks.entrySet().iterator() ; i.hasNext() ; ) { + Map.Entry entry = (Map.Entry)i.next(); + Object oldTarget = entry.getValue(); + Object newTarget = newLocationFromOld.get(oldTarget); + if(newTarget != null) { + entry.setValue(newTarget); + oldLocationFromNew.put("ofn=" + newTarget, oldTarget); + } + } + hyperlinks.putAll(oldLocationFromNew); + } + + return ret; + } catch (MalformedURLException e) { + throw new RuntimeException("Could not inject", e); + } + } + + public void extract(ModelFactory factory, Object model, OutputStream out, final Map params) { + this.addExtractOptions(params); + + // begin PreExtract + if(this.hasPreExtract()) { + ILauncher launcher = new EMFVMLauncher(); + launcher.initialize(Collections.emptyMap()); + + EMFModelFactory emfFac = new EMFModelFactory(); + + IReferenceModel mm = emfFac.newReferenceModel(); + new EMFInjector().inject(mm, ((ASMEMFModel)factory.metamodelOf(model)).getExtent()); + + IModel m = emfFac.newModel(mm); + new EMFInjector().inject(m, ((ASMEMFModel)model).getExtent()); + + launcher.addInModel(mm, this.getName(), "MOF"); + launcher.addInModel(m, "IN", this.getName()); + + try { + this.addPreExtractLibraries(launcher); + + Map options = new HashMap(); + List extensionObjects = new ArrayList(); + extensionObjects.add(new LibExtension() { + public void apply(final ExecEnv execEnv, Map options) { + execEnv.registerOperation(String.class, new Operation(1, "setASMModule") { + public Object exec(AbstractStackFrame frame) { + ModelAdapter ma = (ModelAdapter)params.get("modelAdapter"); + if(ma == null) { + ma = new org.eclipse.gmt.tcs.extractor.ASMModelAdapter(); + } + VirtualExtractorModelAdapter vma = new VirtualExtractorModelAdapter(ma, execEnv, frame.getAsmModule()); + params.put("modelAdapter", vma); + + return frame.getLocalVars()[0]; + } + }); + } + }); + options.put("extensionObjects", extensionObjects); + launcher.launch(ILauncher.RUN_MODE, null, options, new Object[] {this.getPreExtract()}); + } catch(IOException ioe) { + throw new RuntimeException("Could not execute pre-extract transformation", ioe); + } + } + // end PreExtract + + ASMModel format = null; + Object useTCSLanguage = params.get("useTCSLanguage"); + if(useTCSLanguage != null && ((Boolean)useTCSLanguage).booleanValue()) { + Map oparams = new HashMap(); + format = (ASMModel)LanguageRegistry.getDefault().getLanguage("tcs").inject(factory, format, this.getTCS(), oparams); + } else { + EMFModelLoader ml = (EMFModelLoader)AtlModelHandler.getDefault(AtlModelHandler.AMH_EMF).createModelLoader(); + ASMModel tcsMetamodel = (ASMModel)params.get("tcsMetamodel"); + if(tcsMetamodel == null) { + try { + tcsMetamodel = ml.loadModel("TCS", ml.getMOF(), DSLResourceProvider.getDefault().getResource("TCS/Metamodel/TCS.ecore").asEMFURI()); + } catch(IOException ioe) { + throw new RuntimeException("Could not load TCS metamodel", ioe); + } + } + format = ml.newModel("syntax", "model.xmi", tcsMetamodel); + Map oparams = new HashMap(); + oparams.put("name", "TCS"); + URL tcsJar = (URL)params.get("tcsJar"); + if(tcsJar == null) { + tcsJar = DSLResourceProvider.getDefault().getResource("TCS/Syntax/TCS-parser.jar").asURL(); + } + TCSInjection.inject(factory, format, tcsMetamodel, this.getTCS(), oparams, tcsJar); + } + + params.put("format", format); + new TCSExtractor().extract((ASMModel)model, out, params); + } + + protected abstract void addWFRLibraries(ILauncher launcher) throws IOException; + + protected abstract boolean hasWFR(); + + protected abstract InputStream getWFR() throws IOException; + + protected abstract boolean hasPreExtract(); + + protected abstract InputStream getPreExtract() throws IOException; + + protected abstract void addPreExtractLibraries(ILauncher launcher) throws IOException; + + protected abstract void addExtractOptions(Map params); + + protected abstract TextSource getTCS(); + + protected abstract URL getJarURL() throws MalformedURLException; +} diff --git a/plugins/org.eclipse.gmt.tcs.metadata/src/org/eclipse/gmt/tcs/metadata/adhoc/WorkspaceLanguage.java b/plugins/org.eclipse.gmt.tcs.metadata/src/org/eclipse/gmt/tcs/metadata/adhoc/WorkspaceLanguage.java index c3a66e3..c657cd2 100644 --- a/plugins/org.eclipse.gmt.tcs.metadata/src/org/eclipse/gmt/tcs/metadata/adhoc/WorkspaceLanguage.java +++ b/plugins/org.eclipse.gmt.tcs.metadata/src/org/eclipse/gmt/tcs/metadata/adhoc/WorkspaceLanguage.java @@ -15,57 +15,31 @@ package org.eclipse.gmt.tcs.metadata.adhoc; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.OutputStream; import java.net.MalformedURLException; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; +import java.net.URL; import java.util.Map; import java.util.Properties; -import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.emf.common.util.URI; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.gmt.tcs.extractor.TCSExtractor; -import org.eclipse.gmt.tcs.injector.ASMModelAdapter; -import org.eclipse.gmt.tcs.injector.ElementTrace; +import org.eclipse.gmt.tcs.metadata.AbstractLanguage; import org.eclipse.gmt.tcs.metadata.Language; import org.eclipse.gmt.tcs.metadata.LanguageSource; import org.eclipse.gmt.tcs.metadata.ModelFactory; -import org.eclipse.gmt.tcs.metadata.VMLauncher; -import org.eclipse.m2m.atl.core.IModel; -import org.eclipse.m2m.atl.core.IReferenceModel; -import org.eclipse.m2m.atl.core.emf.EMFInjector; -import org.eclipse.m2m.atl.core.emf.EMFModelFactory; import org.eclipse.m2m.atl.core.launch.ILauncher; -import org.eclipse.m2m.atl.drivers.emf4atl.ASMEMFModel; -import org.eclipse.m2m.atl.drivers.emf4atl.ASMEMFModelElement; -import org.eclipse.m2m.atl.drivers.emf4atl.EMFModelLoader; import org.eclipse.m2m.atl.dsls.DSLResourceProvider; import org.eclipse.m2m.atl.dsls.textsource.IFileTextSource; import org.eclipse.m2m.atl.dsls.textsource.TextSource; -import org.eclipse.m2m.atl.engine.emfvm.VMException; -import org.eclipse.m2m.atl.engine.emfvm.launch.EMFVMLauncher; -import org.eclipse.m2m.atl.engine.emfvm.lib.AbstractStackFrame; -import org.eclipse.m2m.atl.engine.emfvm.lib.ExecEnv; -import org.eclipse.m2m.atl.engine.emfvm.lib.LibExtension; -import org.eclipse.m2m.atl.engine.emfvm.lib.Operation; -import org.eclipse.m2m.atl.engine.emfvm.lib.Tuple; import org.eclipse.m2m.atl.engine.vm.ASM; import org.eclipse.m2m.atl.engine.vm.ASMXMLReader; -import org.eclipse.m2m.atl.engine.vm.AtlModelHandler; -import org.eclipse.m2m.atl.engine.vm.nativelib.ASMModel; /** * * @author Frédéric Jouault */ -public class WorkspaceLanguage implements Language, LanguageSource { +public class WorkspaceLanguage extends AbstractLanguage implements Language, LanguageSource { private static class ModelCacheFromIFile extends ModelCache { private String metamodelName; @@ -225,227 +199,6 @@ public class WorkspaceLanguage implements Language, LanguageSource { return this; } - public Object inject(ModelFactory factory, Object model, TextSource source, final Map params) { - try { - params.put("name", name); - // TODO: support multiple parserGenerators - //params.put("parserGenerator", getParserGenerator()); // not specifying any parserGenerator will default to antlr3 - - Object metamodel = getMetamodel(factory); - - // Grab a reference to problemModel now, because if we get it after the injection, - // it may have been replaced by a model adapter. - Object problemModel = params.get("problems"); - - if(model == null) { - model = factory.newModel("model.xmi", metamodel); - } - final Object model_ = model; - - final Map hyperlinks = (Map)params.get("hyperlinks"); - final Map locations = (Map)params.get("locationByElement"); - Map trace_ = (Map)params.get("trace"); - if((hyperlinks != null) && (trace_ == null)) { - trace_ = new HashMap(); - params.put("trace", trace_); - } - final Map trace = trace_; - - final VirtualModelAdapter vma = new VirtualModelAdapter(new ASMModelAdapter(model)); - params.put("modelAdapter", vma); - - Object ret = TCSInjection.inject(factory, model, metamodel, source, params, jarFile.getLocationURI().toURL()); - - if(problemModel != null) { - // TODO: only if no parsing error? - VMLauncher vmLauncher = (VMLauncher)params.get("vmLauncher"); - if(vmLauncher != null) { - IFile wfrFile = project.getFile("WFR/" + name + ".asm"); - if(wfrFile.exists()) { - /* - Map libraries = new HashMap(); - libraries.put("TCSVirtualProperties", vma.getLibrary(name)); - String libNameAndPathsCSV = getProperty("wfr.libraries"); - if(libNameAndPathsCSV != null) { - String libNameAndPaths[] = libNameAndPathsCSV.split(","); - for(int i = 0 ; i < libNameAndPaths.length ; i++) { - String parts[] = libNameAndPaths[i].split("="); - libraries.put(parts[0], project.getFile(parts[1]).getLocationURI().toURL()); - } - } - Map models = new HashMap(); - models.put(name, metamodel); - models.put("IN", ret); - models.put("Problem", factory.metamodelOf(problemModel)); - models.put("OUT", problemModel); - vmLauncher.launch(wfrFile.getLocationURI().toURL(), models, libraries); - */ - // override VM Launcher to use EMFVM - ILauncher launcher = new EMFVMLauncher(); - launcher.initialize(Collections.emptyMap()); - - EMFModelFactory emfFac = new EMFModelFactory(); - - IReferenceModel pbMM = emfFac.newReferenceModel(); - new EMFInjector().inject(pbMM, ((ASMEMFModel)factory.metamodelOf(problemModel)).getExtent()); - - IReferenceModel mm = emfFac.newReferenceModel(); - new EMFInjector().inject(mm, ((ASMEMFModel)factory.metamodelOf(model)).getExtent()); - - IModel m = emfFac.newModel(mm); - new EMFInjector().inject(m, ((ASMEMFModel)model).getExtent()); - - IModel pbM = emfFac.newModel(pbMM); - new EMFInjector().inject(pbM, ((ASMEMFModel)problemModel).getExtent()); - - launcher.addInModel(mm, name, "MOF"); - launcher.addInModel(m, "IN", name); - launcher.addInModel(pbMM, "Problem", "MOF"); - launcher.addOutModel(pbM, "OUT", "Problem"); - - String libNameAndPathsCSV = getProperty("wfr.libraries"); - try { - if(libNameAndPathsCSV != null) { - String libNameAndPaths[] = libNameAndPathsCSV.split(","); - for(int i = 0 ; i < libNameAndPaths.length ; i++) { - String parts[] = libNameAndPaths[i].split("="); - launcher.addLibrary(parts[0], project.getFile(parts[1]).getLocationURI().toURL().openStream()); - } - } - - Map options = new HashMap(); - List extensionObjects = new ArrayList(); - extensionObjects.add(new LibExtension() { - public void apply(ExecEnv execEnv, Map options) { - // allVirtualProperties global/context-less helper => not possible here because ASMModule - // only created after extensions are called. - // Workaround: register on String (for no specific reason (could be any other type)). - final Set allProperties = vma.getAllProperties(); - - // We keep document order. Until GenericResolver can topologically sort, we must make sure to return in the same order. - // Actually, it should be metamodel order (closer to external resolver with specific metamodel), but document order is even better - // (closer to internal resolver, and therefore same best practices, such as only looking in a reference resolved before, apply). - execEnv.registerOperation(String.class, new Operation(1, "allVirtualProperties") { - public Object exec(AbstractStackFrame frame) { - return allProperties; - } - }); - - if(params.containsKey("hyperlinks")) { - execEnv.registerOperation(String.class, new Operation(4, "addHyperlink") { - public Object exec(AbstractStackFrame frame) { - Object locals[] = frame.getLocalVars(); - // TODO: generalize this - Object source = ((ASMEMFModel)model_).getASMModelElement((EObject)locals[1]); - Object target = ((ASMEMFModel)model_).getASMModelElement((EObject)locals[3]); - hyperlinks.put( - ((ElementTrace)trace.get(source)).getPropertyLocation((String)locals[2]), - locations.get(target) - ); - return null; - } - }); - } - - // register weaving helpers used to represent virtual properties - for(Iterator i = allProperties.iterator() ; i.hasNext() ; ) { - Tuple t = (Tuple)i.next(); - Object type = t.get(null, "eContainingClass"); - String name = (String)t.get(null, "name"); - execEnv.registerWeavingHelper(type, name, null); - } - - // store values - for(Iterator i = vma.getVirtualProperties().entrySet().iterator() ; i.hasNext() ; ) { - Map.Entry ei = (Map.Entry)i.next(); - Object element = ei.getKey(); - if(element instanceof ASMEMFModelElement) { - element = ((ASMEMFModelElement)element).getObject(); - } - // - Map slots = (Map)ei.getValue(); - for(Iterator j = slots.entrySet().iterator() ; j.hasNext() ; ) { - Map.Entry ej = (Map.Entry)j.next(); - String propertyName = (String)ej.getKey(); - Object value = ej.getValue(); - execEnv.setHelperValue(element, propertyName, value); - } - } - } - }); - - options.put("extensionObjects", extensionObjects); - launcher.launch(ILauncher.RUN_MODE, null, options, new Object[] {wfrFile.getLocationURI().toURL().openStream()}); - } catch(IOException ioe) { - throw new RuntimeException("could not run WFR transformation", ioe); - } catch(VMException vme) { - vme.printStackTrace(); - } - } - } - } - if(hyperlinks != null) { - // Change target to location of "name" attribute if it exists. - - // TODO: - // - make this optional - // - make this generic (i.e., use refersTo information) - // - make it doable from transformation (need to represent ElementTraces as model) - - Map newLocationFromOld = new HashMap(); // only for those that change - for(Iterator i = locations.entrySet().iterator() ; i.hasNext() ; ) { - Map.Entry entry = (Map.Entry)i.next(); - Object element = entry.getKey(); - ElementTrace et = (ElementTrace)trace.get(element); - if(et != null) { - Object newLocation = et.getPropertyLocation("name"); - if(newLocation != null) { - Object oldLocation = entry.getValue(); - newLocationFromOld.put(oldLocation, newLocation); - } - } else { - // e.g., auto-created elements - } - } - - // Remarks: - // - after this transformation, text hovers may be incomplete if hyperlinks are used for this purpose - // => therefore special "ofn=" (old from new) hyperlinks are added - Map oldLocationFromNew = new HashMap(); - for(Iterator i = hyperlinks.entrySet().iterator() ; i.hasNext() ; ) { - Map.Entry entry = (Map.Entry)i.next(); - Object oldTarget = entry.getValue(); - Object newTarget = newLocationFromOld.get(oldTarget); - if(newTarget != null) { - entry.setValue(newTarget); - oldLocationFromNew.put("ofn=" + newTarget, oldTarget); - } - } - hyperlinks.putAll(oldLocationFromNew); - } - - return ret; - } catch (MalformedURLException e) { - throw new RuntimeException("Could not inject", e); - } - } - - public void extract(ModelFactory factory, Object model, OutputStream out, Map params) { - EMFModelLoader ml = (EMFModelLoader)AtlModelHandler.getDefault(AtlModelHandler.AMH_EMF).createModelLoader(); - ASMModel tcsMetamodel; - try { - tcsMetamodel = ml.loadModel("TCS", ml.getMOF(), DSLResourceProvider.getDefault().getResource("TCS/Metamodel/TCS.ecore").asEMFURI()); - } catch(IOException ioe) { - throw new RuntimeException("Could not load TCS metamodel", ioe); - } - ASMModel format = ml.newModel("syntax", "model.xmi", tcsMetamodel); - Map oparams = new HashMap(); - oparams.put("name", "TCS"); - TCSInjection.inject(factory, format, tcsMetamodel, new IFileTextSource(tcsFile), oparams, DSLResourceProvider.getDefault().getResource("TCS/Syntax/TCS-parser.jar").asURL()); - params.put("format", format); - new TCSExtractor().extract((ASMModel)model, out, params); - } - public String getExtension() { return extension; } @@ -534,4 +287,72 @@ public class WorkspaceLanguage implements Language, LanguageSource { public IFile getCompilerFile() { return compilerFile; } + + private void addLibraries(ILauncher launcher, String propertyName) throws IOException { + String libNameAndPathsCSV = this.getProperty("wfr.libraries"); + + if(libNameAndPathsCSV != null) { + String libNameAndPaths[] = libNameAndPathsCSV.split(","); + for(int i = 0 ; i < libNameAndPaths.length ; i++) { + String parts[] = libNameAndPaths[i].split("="); + launcher.addLibrary(parts[0], project.getFile(parts[1]).getLocationURI().toURL().openStream()); + } + } + } + + protected void addWFRLibraries(ILauncher launcher) throws IOException { + this.addLibraries(launcher, "wfr.libraries"); + } + + protected void addPreExtractLibraries(ILauncher launcher) throws IOException { + this.addLibraries(launcher, "pre-extract.libraries"); + } + + private IFile getFile(String path) { + return project.getFile(path); + } + + private InputStream getASM(String path) throws IOException { + IFile wfrFile = getFile(path); + if(wfrFile.exists()) { + return wfrFile.getLocationURI().toURL().openStream(); + } else { + return null; + } + } + + protected boolean hasWFR() { + return this.getFile("WFR/" + name + ".asm").exists(); + } + + protected InputStream getWFR() throws IOException { + return this.getASM("WFR/" + name + ".asm"); + } + + protected boolean hasPreExtract() { + return this.getFile("WFR/PreExtract.asm").exists(); + } + + protected InputStream getPreExtract() throws IOException { + return this.getASM("WFR/PreExtract.asm"); + } + + protected void addExtractOptions(Map params) { + String opts = getProperty("extract.options"); + if(opts != null) { + String optsParts[] = opts.split(","); + for(int i = 0 ; i < optsParts.length ; i++) { + String mapping[] = optsParts[i].split("="); + params.put(mapping[0], mapping[1]); + } + } + } + + protected TextSource getTCS() { + return new IFileTextSource(tcsFile); + } + + protected URL getJarURL() throws MalformedURLException { + return jarFile.getLocationURI().toURL(); + } } -- cgit v1.2.3