blob: 7497748065de5668a60faea91606b227b6a197db [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2015, 2018 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
*
* Contributors:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.examples.build.xtend;
import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.eclipse.emf.codegen.ecore.genmodel.GenPackage;
import org.eclipse.emf.common.notify.Notifier;
import org.eclipse.emf.common.util.TreeIterator;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EEnumLiteral;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.mwe.core.WorkflowContext;
import org.eclipse.emf.mwe.core.issues.Issues;
import org.eclipse.emf.mwe.core.lib.AbstractWorkflowComponent;
import org.eclipse.emf.mwe.core.monitor.ProgressMonitor;
import org.eclipse.emf.mwe.utils.StandaloneSetup;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.ocl.examples.codegen.generator.AbstractGenModelHelper;
import org.eclipse.ocl.pivot.internal.manager.PivotMetamodelManager;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.OCL;
import org.eclipse.ocl.pivot.utilities.PivotUtil;
import org.eclipse.xtext.AbstractRule;
import org.eclipse.xtext.EnumRule;
import org.eclipse.xtext.Grammar;
import org.eclipse.xtext.ParserRule;
import org.eclipse.xtext.ReferencedMetamodel;
import org.eclipse.xtext.TerminalRule;
import org.eclipse.xtext.resource.impl.BinaryGrammarResourceFactoryImpl;
import org.eclipse.xtext.util.Strings;
public abstract class GenerateGrammar extends AbstractWorkflowComponent
{
protected Logger log = Logger.getLogger(getClass());
protected ResourceSet resourceSet = null;
protected String languageName;
protected String javaFolder;
protected String javaPackageName;
protected String grammarFileStem;
protected String sourceFile;
protected AbstractGenModelHelper genModelHelper;
private Map<EClassifier, Map<Notifier, String>> nameMaps = new HashMap<EClassifier, Map<Notifier, String>>();
private Map<String, Grammar> name2grammar = new HashMap<String, Grammar>();
@Override
public void checkConfiguration(Issues issues) {
if (javaFolder == null) {
issues.addError(this, "javaFolder not specified.");
}
if (javaPackageName == null) {
issues.addError(this, "javaPackageName not specified.");
}
if (grammarFileStem == null) {
issues.addError(this, "grammarFileStem not specified.");
}
if (languageName == null) {
languageName = javaPackageName + "." + grammarFileStem;
}
}
protected @NonNull String emitEClassifierLiteral(@NonNull EClassifier eClassifier) {
EPackage ePackage = ClassUtil.nonNullEMF(eClassifier.getEPackage());
GenPackage genPackage = genModelHelper.getGenPackage(ePackage);
if (genPackage == null) {
return "<<" + ePackage.getNsURI() + ">>";
}
return genPackage.getQualifiedPackageInterfaceName() + ".Literals" + "." + genModelHelper.getLiteralName(eClassifier);
}
protected @NonNull String emitEPackageLiteral(@NonNull EPackage ePackage) {
GenPackage genPackage = genModelHelper.getGenPackage(ePackage);
if (genPackage == null) {
return "<<" + ePackage.getNsURI() + ">>";
}
return genPackage.getQualifiedPackageInterfaceName() + ".eINSTANCE";
}
protected @NonNull String emitEEnumLiteral(@NonNull EEnumLiteral enumLiteral) {
EClassifier eClassifier = enumLiteral.getEEnum();
EPackage ePackage = ClassUtil.nonNullEMF(eClassifier.getEPackage());
GenPackage genPackage = genModelHelper.getGenPackage(ePackage);
if (genPackage == null) {
return "<<" + ePackage.getNsURI() + ">>";
}
return genPackage.getQualifiedPackageInterfaceName() + ".Literals" + "." + genModelHelper.getLiteralName(eClassifier)+".getEEnumLiteral(\""+ enumLiteral.getName() + "\")";
}
protected @NonNull String emitParserRuleLiteral(@NonNull Grammar grammar, @NonNull ParserRule parserRule) {
Grammar referencedGrammar = (Grammar)parserRule.eContainer();
if ((referencedGrammar == null) || (referencedGrammar == grammar)) {
return "PR_" + parserRule.getName();
}
else {
return getGrammarPackageName(referencedGrammar)+ ".PR_" + parserRule.getName();
}
}
protected @NonNull String emitEnumRuleLiteral(@NonNull Grammar grammar, @NonNull EnumRule enumRule) {
Grammar referencedGrammar = (Grammar)enumRule.eContainer();
if ((referencedGrammar == null) || (referencedGrammar == grammar)) {
return "ER_" + enumRule.getName();
}
else {
return getGrammarPackageName(referencedGrammar)+ ".ER_" + enumRule.getName();
}
}
protected @NonNull String emitReferencedMetamodelName(@NonNull Grammar grammar, @NonNull ReferencedMetamodel referencedMetamodel) {
String alias = referencedMetamodel.getAlias();
if (alias == null) {
return "MM";
}
else {
return "MM_" + alias;
}
}
protected @NonNull String emitSymbol(EClassifier eClass, @NonNull Notifier eObject) {
Map<Notifier, String> names = nameMaps.get(eClass);
if (names == null) {
names = new HashMap<Notifier, String>();
nameMaps.put(eClass, names);
}
String name = names.get(eObject);
if (name == null) {
name = eClass.getName() + "_" + names.size();
names.put(eObject, name);
}
return name;
}
protected @NonNull String emitTerminalRuleLiteral(@NonNull Grammar grammar, @NonNull TerminalRule terminalRule) {
Grammar referencedGrammar = (Grammar)terminalRule.eContainer();
if ((referencedGrammar == null) || (referencedGrammar == grammar)) {
return "TR_" + terminalRule.getName();
}
else {
return getGrammarPackageName(referencedGrammar)+ ".TR_" + terminalRule.getName();
}
}
@SuppressWarnings("null")
protected @NonNull String emitValue(Object value) {
if (value instanceof Boolean) {
return value.toString();
}
if (value instanceof Number) {
return value.toString();
}
return value != null ? ("\"" + Strings.convertToJavaString(value.toString())+ "\"") : "null";
}
protected abstract /*@NonNull*/ String generate(/*@NonNull*/ Resource grammarResource);
protected String getGetAccessorName(@NonNull EStructuralFeature eStructuralFeature) {
return genModelHelper.getGetAccessor(eStructuralFeature);
}
protected @NonNull String getGrammarPackageName(@NonNull Grammar grammar) {
String name = grammar.getName();
int index = name.lastIndexOf(".");
if (index >= 0) {
name = "_" + name.substring(index+1);
}
else {
name = "_" + name;
}
Grammar theGrammar = name2grammar.get(name);
if (theGrammar == null) {
theGrammar = grammar;
name2grammar.put(name, theGrammar);
}
if (theGrammar == grammar) {
return name;
}
return "_" + grammar.getName().replaceAll("\\.", "_");
}
protected ResourceSet getResourceSet() {
if (resourceSet == null) {
resourceSet = new ResourceSetImpl();
}
return resourceSet;
}
protected String getSetAccessorName(@NonNull EStructuralFeature eStructuralFeature) {
return genModelHelper.getSetAccessor(eStructuralFeature);
}
protected <AR extends AbstractRule> List<AR> getSortedAbstractRules(@NonNull Grammar grammar, Class<AR> type) {
List<AR> abstractRules = new ArrayList<AR>();
for (TreeIterator<EObject> tit = grammar.eAllContents(); tit.hasNext(); ) {
EObject eObject = tit.next();
if (type.isInstance(eObject)) {
abstractRules.add(type.cast(eObject));
}
}
Collections.sort(abstractRules, new Comparator<@NonNull AR>()
{
@Override
public int compare(@NonNull AR o1, @NonNull AR o2) {
return ClassUtil.safeCompareTo(o1.getName(), o2.getName());
}
});
return abstractRules;
}
protected List<ReferencedMetamodel> getSortedReferencedMetamodels(@NonNull Grammar grammar) {
List<ReferencedMetamodel> referencedMetamodels = new ArrayList<ReferencedMetamodel>();
for (TreeIterator<EObject> tit = grammar.eAllContents(); tit.hasNext(); ) {
EObject eObject = tit.next();
if (eObject instanceof ReferencedMetamodel) {
referencedMetamodels.add((ReferencedMetamodel)eObject);
}
}
Collections.sort(referencedMetamodels, new Comparator<ReferencedMetamodel>()
{
@Override
public int compare(ReferencedMetamodel o1, ReferencedMetamodel o2) {
String n1 = o1.getAlias();
String n2 = o2.getAlias();
if (n1 == null) n1 = "";
if (n2 == null) n2 = "";
return ClassUtil.safeCompareTo(n1, n2);
}
});
return referencedMetamodels;
}
@Override
protected void invokeInternal(WorkflowContext ctx, ProgressMonitor monitor, Issues issues) {
OCL ocl = OCL.newInstance();
PivotMetamodelManager metamodelManager = (PivotMetamodelManager) ocl.getMetamodelManager();
genModelHelper = new AbstractGenModelHelper(metamodelManager);
String rootPath = StandaloneSetup.getPlatformRootPath();
File folder = new File(rootPath + javaFolder + "/" + javaPackageName.replace(".", "/"));
try {
sourceFile = new File(folder, grammarFileStem + ".xtextbin").toString();
URI fileURI = URI.createFileURI(sourceFile);
log.info("Loading Grammar '" + fileURI);
ResourceSet resourceSet = getResourceSet();
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("xtextbin", new BinaryGrammarResourceFactoryImpl());
Resource grammarResource = resourceSet.getResource(fileURI, true);
String message = PivotUtil.formatResourceDiagnostics(ClassUtil.nonNullEMF(grammarResource.getErrors()), "Grammar load failure", "\n");
if (message != null) {
issues.addError(this, message, null, null, null);
return;
}
String fileName = folder + "/" + grammarFileStem + "GrammarResource.java";
// log.info("Generating '" + fileName + "'");
@SuppressWarnings("null")@NonNull String metamodel = generate(grammarResource);
MergeWriter fw = new MergeWriter(fileName);
fw.append(metamodel);
fw.close();
} catch (RuntimeException e) {
throw e;
} catch (Exception e) {
throw new RuntimeException("Problems running " + getClass().getSimpleName(), e);
} finally {
ocl.dispose();
}
}
/**
* The stem for grammr files such as grammarFileStem.xtextbin. (e.g. "EssentialOCL")
*/
public void setGrammarFileStem(String grammarFileStem) {
this.grammarFileStem = grammarFileStem;
}
/**
* The platform relative path to the Java generated source folder (e.g. "/org.eclipse.ocl.pivot/emf-src")
*/
public void setJavaFolder(String javaFolder) {
this.javaFolder = javaFolder;
}
/**
* The Java package path for the grammar. (e.g. "org.eclipse.ocl.pivot.path")
*/
public void setJavaPackageName(String javaPackageName) {
this.javaPackageName = javaPackageName;
}
/**
* The languageName for the grammar. (e.g. "org.eclipse.ocl.xtext.essentialocl.EssentialOCL")
*/
public void setLanguageName(String languageName) {
this.languageName = languageName;
}
/**
* An optional ResourceSet that MWE components may share to reduce model loading.
*/
public void setResourceSet(ResourceSet resourceSet) {
this.resourceSet = resourceSet;
}
}