package org.reuseware.air.comogen.util;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.reuseware.air.language.cmsl.Annotation;
import org.reuseware.air.language.cmsl.BaseLanguageReference;
import org.reuseware.air.language.cmsl.BaseReference;
import org.reuseware.air.language.cmsl.Construct;
import org.reuseware.air.language.cmsl.ConstructReference;
import org.reuseware.air.language.cmsl.Definition;
import org.reuseware.air.language.cmsl.DefinitionConstruct;
import org.reuseware.air.language.cmsl.DefinitionList;
import org.reuseware.air.language.cmsl.DefinitionPart;
import org.reuseware.air.language.cmsl.ExtensionStatement;
import org.reuseware.air.language.cmsl.Fragtypes;
import org.reuseware.air.language.cmsl.Injection;
import org.reuseware.air.language.cmsl.NonTerminal;
import org.reuseware.air.language.cmsl.NonTerminalIdentifier;
import org.reuseware.air.language.cmsl.Reference;
public class CMSLSpecificationUtil {
//private static final String nsURIPrefix = "http://www.reuseware.org/air/language/";
//TODO remove dependencies from these parameters
//private static final String baseLanguagePrefix = "b_";
//private static final String reuseLanguagePrefix = "r_";
/**
* Returns the specified fragment type names.
*
* @param statements
* @return
*/
/** public static List<String> getComponentModelFragTypes(EList<ExtensionStatement> statements) {
Fragtypes fragTypesConstruct = getFirstFragtypesConstruct(statements);
EList<Object> list = fragTypesConstruct.getFragtype();
List<String> types = new LinkedList<String>();
for (Object obj : list) {
// in the base language
if (obj instanceof Reference) {
Reference ref = (Reference)obj;
// add the declared fragment
types.add(baseLanguagePrefix + getNTName(ref.getBase()));
}
// in the reuse language
else if (obj instanceof Construct) {
Construct construct = (Construct)obj;
types.add(reuseLanguagePrefix + getNTName(construct.getName()));
}
}
return types;
}
**/
/**
* Returns the first Fragtypes construct from CMSL statement list.
*
* @param statements - the statement list
* @return first FragType statement in list.
private static Fragtypes getFirstFragtypesConstruct(EList<ExtensionStatement> statements) {
for (Iterator<ExtensionStatement> i = statements.iterator(); i.hasNext(); ) {
ExtensionStatement statement = (ExtensionStatement)i.next();
if (statement instanceof Fragtypes) {
return (Fragtypes)statement;
}
}
return null;
}
*/
/**
* Constructs the signature lists for a possible set of composers. This is done by mapping annotations
* to definitions and the evaluation of the definitions' members.
*
* @param statements
* @return
*/
public static List<MethodStruct> getComposerSignatures(EList<ExtensionStatement> statements) {
List<Definition> definitions = new LinkedList<Definition>();
List<Annotation> annotations = new LinkedList<Annotation>();
Hashtable<String,String> returnTypes = new Hashtable<String,String>();
// treat the statements one by one
for (Iterator<ExtensionStatement> i = statements.iterator(); i.hasNext(); ) {
ExtensionStatement statement = (ExtensionStatement)i.next();
if (statement instanceof Definition) {
definitions.add((Definition)statement);
}
else if (statement instanceof Annotation) {
annotations.add((Annotation)statement);
}
else if (statement instanceof Injection) {
Injection injection = (Injection)statement;
// save relationship between newly defined construct, and its injection point,
// this information is used to derive return type for composer implementations
returnTypes.put(getNTName(injection.getSource()), getNTName(injection.getTarget()));
}
}
List<MethodStruct> signatures = new LinkedList<MethodStruct>();
for (Annotation annotation : annotations) {
String annotationName = getNTName(annotation.getTarget());
// verify that it is the correct annotation
if (annotationName != null && annotationName.equals("Composer")) {
String annotatedName = getNTName(annotation.getSource());
if (annotatedName != null) {
// get the parameter list
List<String> parameters = getParameters(annotatedName, definitions);
// TODO: fix proper return type
MethodStruct methodStruct =
new MethodStruct(returnTypes.get(annotatedName), cup(annotatedName), parameters);
methodStruct.setOrigName(annotatedName);
signatures.add(methodStruct);
}
}
}
return signatures;
}
/**
* Constructs the signature for a method corresponding to a composer
*
* NB: The first item on the signature list is the name of the "method"
* (actually, the name of the annotation, e.g.. @ReusewairComposer("[constructName]"))
*
* @param constructName
* @param definitions
* @return
*/
private static List<String> getParameters(String constructName, List<Definition> definitions) {
List<String> parameters = new LinkedList<String>();
for (Definition def : definitions) {
// the definition must be a construct definition (DefinitionConstruct from cmsl.as)
if (def instanceof DefinitionConstruct) {
String nonTermName = getNTName(((DefinitionConstruct)def).getNewConstruct());
// check that we found the right construct
if (nonTermName != null && nonTermName.equals(constructName)) {
// construct the signature
DefinitionList defList = ((DefinitionConstruct)def).getDefinition();
@SuppressWarnings("unchecked")
EList<DefinitionPart> parts = (EList<DefinitionPart>)defList.getRefs();
for (DefinitionPart part : parts) {
ConstructReference cRef = part.getConstruct();
if (cRef instanceof Reference) {
String name = getNTName((Reference)cRef);
if (name != null)
parameters.add(name);
} else if (cRef instanceof Construct) {
String name = getNTName(((Construct)cRef).getName());
if (name != null)
parameters.add(name);
}
}
}
} else {
System.err.println("Trying to extract composer parameter list from a DefinitionChoice.");
}
}
return parameters;
}
/**
* Loads the language model from EPackage registry.
*
* @param Namespace URI
* @return EPackage containing the requested language model
*/
public static EPackage loadLanguageModelFromRegistry(URI nsuri) {
//TODO simply delegate to loadLanguageModel(nsuri,nsuri)?
EPackage ePackage = EPackage.Registry.INSTANCE.getEPackage(nsuri.toString());
return ePackage;
}
/**
* Loads
*
* @param url
* @param nsuri
* @return
*/
public static EPackage loadLanguageModel(URI url, URI nsuri){
ResourceSet resourceSet = new ResourceSetImpl();
Resource resource = resourceSet.getResource(url,true);
if(resource==null||resource.getContents().isEmpty())
return null;
for(EObject eObject:resource.getContents()){
if(eObject instanceof EPackage){
EPackage pck = (EPackage)eObject;
if(nsuri.toString().equals(pck.getNsURI())){
return pck;
}
}
}
return null;
}
/**
* Retrieves the name of a nonterminal
*
* @param nonTerminal
* @return
*/
public static String getNTName(NonTerminal nonTerminal) {
return ((NonTerminalIdentifier)nonTerminal).getValue();
}
/**
* Retrieves the name of a Reference
*
* @param reference
* @return
*/
private static String getNTName(Reference reference) {
return getNTName(((BaseLanguageReference)reference.getBase()).getBase());
}
/**
* Retrieves the name of a BaseReference
*
* @param reference
* @return
*/
public static String getNTName(BaseReference reference) {
return getNTName(((BaseLanguageReference)reference).getBase());
}
/**
* Make sure that the first letter in a string is lower case
*
* @param str
* @return
*/
private static String cup(String str) {
return str.substring(0,1).toLowerCase() + str.substring(1);
}
}