/*******************************************************************************
* Copyright (c) 2008 SAP
* see https://research.qkal.sap.corp/mediawiki/index.php/CoMONET
*
* Date: $Date: 2009-09-18 14:13:44 +0200 (Fr, 18 Sep 2009) $
* @version $Revision: 7886 $
* @author: $Author: c5106462 $
*******************************************************************************/
package com.sap.furcas.parsergenerator.tcs.t2m.grammar;
import static com.sap.furcas.parsergenerator.util.StringConcatUtil.concat;
import java.util.Collection;
import java.util.Iterator;
import com.sap.furcas.metamodel.FURCAS.TCS.ContextTags;
import com.sap.furcas.metamodel.FURCAS.TCS.Operator;
import com.sap.furcas.metamodel.FURCAS.TCS.OperatorTemplate;
import com.sap.furcas.metamodel.FURCAS.TCS.PropertyReference;
import com.sap.furcas.metamodel.FURCAS.TCS.Sequence;
import com.sap.furcas.parsergenerator.tcs.t2m.grammar.rules.OperatorTemplateProductionRule;
import com.sap.furcas.parsergenerator.util.VarStringBuffer;
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;
import com.sap.furcas.runtime.parser.exceptions.SyntaxParsingException;
import com.sap.furcas.runtime.tcs.MessageHelper;
import com.sap.furcas.runtime.tcs.MetaModelElementResolutionHelper;
import com.sap.furcas.runtime.tcs.SyntaxLookup;
import com.sap.furcas.runtime.tcs.TemplateNamingHelper;
/**
* The Class OperatorTemplateHandler.
*/
public class OperatorTemplateHandler<Type extends Object> {
/** The writer. */
ANTLR3GrammarWriter writer;
SyntaxLookup syntaxLookup;
private TemplateNamingHelper<Type> namingHelper;
private MetaModelElementResolutionHelper<Type> resolutionHelper;
/**
* Instantiates a new operator template handler.
*
* @param writer the writer
* @param lookup
* @param metaLookup
* @param namingHelper
* @param resHelper
* @param errorBucket
*/
OperatorTemplateHandler(ANTLR3GrammarWriter writer, SyntaxLookup lookup, TemplateNamingHelper<Type> namingHelper,
MetaModelElementResolutionHelper<Type> resHelper) {
this.writer = writer;
this.syntaxLookup = lookup;
this.namingHelper = namingHelper;
this.resolutionHelper = resHelper;
}
/**
* @param handlerConfig
*/
public OperatorTemplateHandler(SyntaxElementHandlerConfigurationBean<Type> handlerConfig) {
this(handlerConfig.getWriter(), handlerConfig.getSyntaxLookup(), handlerConfig.getNamingHelper(), handlerConfig
.getResolutionHelper());
}
/**
* Adds the template.
*
* @param template the template
* @throws SyntaxParsingException
* @throws MetaModelLookupException
*/
public void addTemplate(OperatorTemplate template, RuleBodyBufferFactory ruleBodyBufferFactory)
throws MetaModelLookupException, SyntaxElementException {
VarStringBuffer rulebody = new VarStringBuffer(); // first add ANTLR rule to Rulebody, then Java elements
Collection<Operator> ops = template.getOperators();
boolean allOperatorsPostFix = true;
for (Operator operator : ops) {
if (!operator.isPostfix()) {
allOperatorsPostFix = false;
}
}
if (allOperatorsPostFix) {
// TODO: Understand and Support specific operator templates
//throw new RuntimeException("Operator Template with all operators being postfix not supported yet");
}
try {
ResolvedNameAndReferenceBean<Type> refbean = resolutionHelper.resolve(template);
String returnDeclaration = concat("java.lang.String opName, Object left, org.antlr.runtime.Token firstToken");
String metaObjectListParam = namingHelper.getMetaTypeListParameter(refbean);
StringBuilder initString = new StringBuilder(); // TODO cleanup string construction
if (template.isIsReferenceOnly()) {
initString.append(concat("List<String> metaType=", metaObjectListParam, ";\n",
ObservationDirectivesHelper.getEnterTemplateNotification(template),
"IModelElementProxy ret=(getBacktrackingLevel()==0) ? createReferenceProxy(metaType) : null;\n\n"));
} else {
initString.append(concat("List<String> metaType=", metaObjectListParam, ";\n",
ObservationDirectivesHelper.getEnterTemplateNotification(template),
"IModelElementProxy ret=(getBacktrackingLevel()==0) ? createModelElementProxy(metaType, ",
template.isIsContext(), ", false"));
ContextTags tags = template.getContextTags();
if (tags != null && tags.getTags() != null && tags.getTags().size() > 0) {
initString.append(", new String[]{");
for (Iterator<String> iterator = tags.getTags().iterator(); iterator.hasNext();) {
String tag = iterator.next();
initString.append("\"").append(tag).append("\"");
if (iterator.hasNext()) {
initString.append(", ");
}
}
initString.append("}");
}
initString.append(") : null;\n\n");
}
if (template.getTemplateSequence() != null) {
Sequence sequence = template.getTemplateSequence();
String rulefragment = ruleBodyBufferFactory.getNewRuleBodyFragment(sequence);
rulebody.append(rulefragment);
}
rulebody.append("{\n");
String operatorStorageName = getOperatorStorageName(template);
if (operatorStorageName != null) {
rulebody.append("setProperty(ret,\"", operatorStorageName, "\" , opName);\n");
} else {
rulebody.append("// discarding operator name instead of storing it here\n");
}
rulebody.append("setProperty(ret,\"", getSourceStorageName(template), "\" , left);\n");
rulebody.append("ret2 = createOrResolve(ret, firstToken);\n");
rulebody.append("onRuleElementCreationCommited(ret2);\n");
if (template.isIsContext()) {
rulebody.append("leaveContext();\n");
// leave context after sub-elements are done with add to context
}
rulebody.append("\n}");
writer.addRule(new OperatorTemplateProductionRule(namingHelper.getRuleName(template), returnDeclaration,
"Object ret2", initString.toString(), rulebody.toString()));
} catch (NameResolutionFailedException e) {
throw new SyntaxElementException("OperatorTemplate name could not be resolved: "
+ MessageHelper.getTemplateName(template), template, e);
}
}
/**
* @param template
* @return
*/
private static String getOperatorStorageName(OperatorTemplate template) {
if (template != null) {
PropertyReference propRef = template.getStoreOperatorTo();
if (propRef != null) {
if (propRef.getStrucfeature() != null) {
return propRef.getStrucfeature().getName();
} else {
return propRef.getName();
}
}
}
return null;
}
/**
* @param template
* @return
*/
private static String getSourceStorageName(OperatorTemplate template) {
if (template != null) {
PropertyReference propRef = template.getStoreLeftSideTo();
if (propRef.getStrucfeature() != null) {
return propRef.getStrucfeature().getName();
} else {
return propRef.getName();
}
}
return null;
}
// TODO findout why TCS does this and whether we need it.
// /**
// * Checks if is specific.
// *
// * @param template the template
// *
// * @return true, if is specific
// */
// private static boolean isSpecific(OperatorTemplate template) {
//// not self.otSequence.oclIsUndefined();
//// ---- self.storeRightTo.oclIsUndefined();
// // -- 20070724: if storeRightTo is specified then otSequence may be
// // defined as a complex operator
// if (template.getStoreOpTo() == null
// && (template.getOtSequence() != null)) {
// List<Operator> ops = template.getOperators();
// for (Iterator<Operator> iterator = ops.iterator(); iterator
// .hasNext();) {
// Operator operator = (Operator) iterator.next();
// if (operator.getArity() <= 1) {
// return false;
// }
// }
// return true;
// }
// return false;
// }
}