/** * */ package com.sap.furcas.runtime.tcs; import java.util.Iterator; import java.util.List; import com.sap.furcas.metamodel.FURCAS.TCS.ClassTemplate; import com.sap.furcas.metamodel.FURCAS.TCS.FunctionTemplate; import com.sap.furcas.metamodel.FURCAS.TCS.PrimitiveTemplate; import com.sap.furcas.metamodel.FURCAS.TCS.QualifiedNamedElement; import com.sap.furcas.metamodel.FURCAS.TCS.Template; import com.sap.furcas.runtime.common.exceptions.MetaModelLookupException; import com.sap.furcas.runtime.common.exceptions.NameResolutionFailedException; import com.sap.furcas.runtime.common.exceptions.SyntaxElementException; import com.sap.furcas.runtime.common.interfaces.ResolvedNameAndReferenceBean; /** * Helps dealing with qualified names in syntaxes. Uses the Metamodel to qualify unqualified names when necessary and possible. */ public class TemplateNamingHelper<Type extends Object> { public static final String ABSTRACT_CONTENTS_SUFFIX = "_abstractContents"; private final MetaModelElementResolutionHelper<Type> resolutionHelper; /** * Creates a new Helper that can use the Metamodel to resolve unqualified names. * @param lookup * @param separator * @param resolutionHelper */ public TemplateNamingHelper(MetaModelElementResolutionHelper<Type> resolutionHelper) { this.resolutionHelper = resolutionHelper; } /** * return rulename modified to allow for mode * @param qNamedElement * @param mode * @return * @throws SyntaxElementException */ public String getRuleNameForMode(QualifiedNamedElement qNamedElement, String mode) throws SyntaxElementException { String result = getRuleName(qNamedElement); if (mode != null) { if (!mode.trim().equals("")) { result += getModeSuffix(mode); } } return result; } public static String getModeSuffix(String mode) { return '_' + mode; } /** * gets the ANTLR grammar rule name for the metamodel element referenced in the template. * For primitive templates, this is the templateName, and not the name of the DataType, as in TCS * on DataType may have several templates. * @param qNamedElement * @return * @throws SyntaxParsingException * @throws SyntaxElementException */ public String getRuleName(QualifiedNamedElement qNamedElement ) throws SyntaxElementException { if (qNamedElement instanceof PrimitiveTemplate) { return ((PrimitiveTemplate) qNamedElement).getTemplateName(); } if (qNamedElement instanceof FunctionTemplate) { return ((FunctionTemplate) qNamedElement).getFunctionName().toLowerCase(); } try { ResolvedNameAndReferenceBean<Type> resolvedName = resolutionHelper.resolve(qNamedElement); return buildRuleName(resolvedName); } catch (NameResolutionFailedException e) { throw new SyntaxElementException(e.getMessage(), qNamedElement); } } // public String getRuleName(ResolvedNameAndReferenceBean refBean ) throws SyntaxElementException, MetaModelLookupException, MetamodelNameResolvingException { // if (refBean == null) { // return null; // } // return resolveAndGetRuleName(refBean.getNames()); // } /** * resolves name against metamodel (non-qualified to qualified), then builds String by concatenating name parts. * @param qualifiedName * @return */ public String buildRuleName(ResolvedNameAndReferenceBean<Type> refBean) { List<String> nameList = refBean.getNames(); String result = null; if (nameList.size() == 1) { // used unqualified name, returning direct to avoid Stringbuilder creation for nothing result = nameList.get(0).toLowerCase(); } else { StringBuilder builder = new StringBuilder(nameList.size() * 10); for (Iterator<String> iterator = nameList.iterator(); iterator.hasNext();) { String name = iterator.next(); builder.append(name.toLowerCase()); if (iterator.hasNext()) { builder.append('_'); } } // TODO check generated name does not conflict with other similar intended name result = builder.toString(); } if(refBean.getOperators() != null) { StringBuilder builder = new StringBuilder(refBean.getOperators().size() * 10); for (String op : refBean.getOperators()) { builder.append('_'); builder.append(op); } result += builder.toString(); } return result; } // /** // * private util method dealing with resolving names against metamodel. // * Will return the same output as input if no extra qualification was needed. // * Only returns null if metamodel returns null as a naming candidate. // * @param names // * @return // * @throws MetaModelLookupException // * @throws SyntaxParsingException // */ // private ResolvedNameAndReferenceBean<Type> resolveName(List<String> names) throws MetamodelNameResolvingException, MetaModelLookupException { // if (names == null || names.size() == 0) { // return null; // } // // ResolvedNameAndReferenceBean<Type> resolvedName = null; // // is name a valid metamodel element? // // TODO change interface isClassName() to getClassName // if (! mmLookup.isClassName(names)) { // // // was name used unqualified? // if (names.size() == 1) { // // // use metamodel to try qualify name if it was unqualified // String name = names.iterator().next(); // // // get the real name of this element // List<ResolvedNameAndReferenceBean<Type>> candidates = mmLookup.qualifyName(name); // if (candidates == null || candidates.size() == 0) { // throw new MetamodelNameResolvingException("Unknown classifier :" + names); // } else if (candidates.size() > 1) { // throw new MetamodelNameResolvingException("Ambiguous classifier : " + names); // } // resolvedName = (ResolvedNameAndReferenceBean<Type>) candidates.get(0); // } else { // // is qualified, but not recognized by metamodel // throw new MetamodelNameResolvingException("Unknown or ambiguous qualified classifier :" + names); // } // // } else { // resolvedName = new ResolvedNameAndReferenceBean<Type>(names, null); // } // // return resolvedName; // } /** * return a String by which other code may identify a ModelElement. * @param reference * @return * @throws SyntaxParsingException */ public String getMetaTypeListParameter(ResolvedNameAndReferenceBean<Type> reference) { String returnName = createListParameter(reference); return returnName; } /** * qualifies template name if unqualified, and returns a String by which other code may identify a ModelElement. * @param reference * @return * @throws SyntaxParsingException */ public String getMetaTypeListParameter(Template template) throws SyntaxElementException { ResolvedNameAndReferenceBean<Type> refBean; try { refBean = resolutionHelper.resolve(template); } catch (NameResolutionFailedException e) { throw new SyntaxElementException(e.getMessage(), template); } String returnName = createListParameter(refBean); return returnName; } /** * @param metaModelTypeOfPropertyListName * @return * @throws MetamodelNameResolvingException * @throws MetaModelLookupException */ public String getMetaTypeListParameter( List<String> names) throws MetamodelNameResolvingException, MetaModelLookupException { ResolvedNameAndReferenceBean<Type> qname = resolutionHelper.resolve(names); if (qname != null) { return createListParameter(qname); } else { throw new MetamodelNameResolvingException("Could not resolve name " + names); } } /** * creates a String saying 'list("name1", "name2")' which supposedly is a method call that will return a List of Strings. * @param refBean * @return */ private String createListParameter(ResolvedNameAndReferenceBean<Type> refBean) { List<String> stringList = refBean.getNames(); StringBuilder builder = new StringBuilder(stringList.size() ); builder.append("list("); String returnName; for (Iterator<String> iterator = stringList.iterator(); iterator.hasNext();) { String name = iterator.next(); builder.append('\"'); builder.append(name); builder.append('\"'); if (iterator.hasNext()) { builder.append(','); } } builder.append(')'); returnName = builder.toString(); return returnName; } public String getRuleNameForTemplate(Template template) throws SyntaxElementException { if(template instanceof ClassTemplate) { if(((ClassTemplate)template).getMode() != null){ return getRuleNameForMode(template, ((ClassTemplate)template).getMode()); } } return getRuleName(template); } /** * Gives the name of the grammar rule resulting from the given template. * * @param template * @param syntaxLookup the {@link SyntaxLookup} that should be used in order to resolve the templates * @return * @throws SyntaxElementException */ public String getConcreteRuleNameForTemplate(Template template, SyntaxLookup syntaxLookup) throws SyntaxElementException { try { List<ResolvedNameAndReferenceBean<Type>> subtypes = null; ResolvedNameAndReferenceBean<Type> resolvedBean = resolutionHelper.resolve(template); subtypes = this.resolutionHelper.getMetaLookup().getDirectSubTypes(resolvedBean); String ruleNameForTemplate = getRuleNameForTemplate(template); if(TcsUtil.areSubTypesWithTemplates(subtypes, TcsUtil.getTemplateMode(template), syntaxLookup)) { return ruleNameForTemplate + "__impl"; } else { return ruleNameForTemplate; } } catch (NameResolutionFailedException e) { throw new SyntaxElementException(e.getMessage(), template); } catch (MetaModelLookupException e) { throw new SyntaxElementException(e.getMessage(), template); } } }