package com.sap.furcas.parsergenerator.tcs.t2m.grammar;
import java.util.ArrayList;
import java.util.Collection;
import com.sap.furcas.metamodel.FURCAS.TCS.ClassTemplate;
import com.sap.furcas.metamodel.FURCAS.TCS.OperatorTemplate;
import com.sap.furcas.metamodel.FURCAS.TCS.Sequence;
import com.sap.furcas.metamodel.FURCAS.TCS.Template;
import com.sap.furcas.parsergenerator.util.VarStringBuffer;
import com.sap.furcas.runtime.common.exceptions.MetaModelLookupException;
import com.sap.furcas.runtime.common.exceptions.SyntaxElementException;
import com.sap.furcas.runtime.tcs.TemplateNamingHelper;
public class SemanticDisambiguateHandler {
private final Collection<? extends Template> templates;
private final SemanticErrorBucket errorBucket;
private final TemplateNamingHelper<?> namingHelper;
private final ArrayList<String> usedSyntacticDisambiguates;
private boolean listHasSyntacticDisambiguate;
private boolean listHasSemanticDisambiguate;
private boolean firstSemanticDisambiguate;
public SemanticDisambiguateHandler(
Collection<? extends Template> templates,
SemanticErrorBucket errorBucket,
TemplateNamingHelper<?> namingHelper) {
this.templates = templates;
this.errorBucket = errorBucket;
this.namingHelper = namingHelper;
usedSyntacticDisambiguates = new ArrayList<String>();
firstSemanticDisambiguate = true;
analyze();
}
private void analyze() {
listHasSyntacticDisambiguate = false;
for (Template subtemp : templates) {
if (!listHasSyntacticDisambiguate && hasSyntacticDisambiguate(subtemp))
listHasSyntacticDisambiguate = true;
if (!listHasSemanticDisambiguate && subtemp.getSemDisambiguate() != null)
listHasSemanticDisambiguate = true;
}
}
public boolean shouldUseSemanticDisambiguate(
Template templateWithSyntacticDisambiguate) {
if (!listHasSemanticDisambiguate)
return false;
boolean relevantSemDisambFound = false;
for (Template subtemp : templates) {
if (templateWithSyntacticDisambiguate.equals(subtemp))
continue;
if (hasSyntacticDisambiguate(subtemp)) {
// TODO implement a more tolerant comparison that can also handle whitespace differences
if (subtemp.getDisambiguateV3().equals(
templateWithSyntacticDisambiguate.getDisambiguateV3())) {
if (subtemp.getSemDisambiguate() != null)
relevantSemDisambFound = true;
else {
errorBucket.addError(
"A subtemplate misses a SemanticDisambiguate",
subtemp);
return false;
}
}
} else if (subtemp.getSemDisambiguate() != null)
relevantSemDisambFound = true;
else {
errorBucket.addError(
"A subtemplate misses a SemanticDisambiguate", subtemp);
return false;
}
}
return relevantSemDisambFound;
}
public boolean addSemanticDisambiguateRule(Template template,
VarStringBuffer rulebody,
RuleBodyBufferFactory ruleBodyBufferFactory,
ClassTemplate operatorParentTemplate, String metaObjectListParam, boolean addedSemanticDisambiguateRule)
throws MetaModelLookupException {
if (hasSyntacticDisambiguate(template)) {
if (usedSyntacticDisambiguates.contains(template
.getDisambiguateV3()))
return false;
else {
usedSyntacticDisambiguates.add(template.getDisambiguateV3());
if (!firstSemanticDisambiguate)
rulebody.append("\n | ");
// add disambiguation rule
rulebody.append("(" + template.getDisambiguateV3() + ")=>("); // b2
}
}
if (!listHasSyntacticDisambiguate && !firstSemanticDisambiguate)
return false;
if (!firstSemanticDisambiguate && !hasSyntacticDisambiguate(template))
rulebody.append("\n | ");
String semOcl = template.getSemDisambiguate();
String opnameParameter = "null";
Sequence sequence;
//placeholder replacement
//TODO refactor this to ClassTemplate and OperatorTemplate in a common superclass
boolean isOperatorTemplate = template instanceof OperatorTemplate;
if (isOperatorTemplate)
sequence = ((OperatorTemplate) template).getTemplateSequence();
else
sequence = ((ClassTemplate) template).getTemplateSequence();
// TODO change this character to a better intuitive version maybe ${...}
// TODO support more than one use of a feature
int beginRef = semOcl.indexOf("${");
String semReference = null;
if (beginRef >= 0)
semReference = semOcl.substring(beginRef + 2, semOcl.indexOf('}',
beginRef + 1));
//find a rule representation for temporary parsing
String rulePrefix = ruleBodyBufferFactory
.getNewRuleBodyForSemDisambiguate(sequence, semReference);
if(rulePrefix != null)
rulebody.append(rulePrefix);
// collect templatenames and ocls for all subtemplates
rulebody.append("\n{List<SemanticDisambRuleData> semDisambRuleData = "
+ "new ArrayList<SemanticDisambRuleData>();\n");
for (Template subtemp : templates) {
if (hasSyntacticDisambiguate(template)) {
if (!template.getDisambiguateV3().equals(
subtemp.getDisambiguateV3()))
continue;
}
String ruleName;
try {
// TODO check if it is better to make a superclass and call
// only one of the instance of parts to remove the instanceof call
if (subtemp instanceof OperatorTemplate) {
ruleName = namingHelper.getRuleName(subtemp);
opnameParameter = "opName";
} else {
ruleName = namingHelper.getRuleNameForMode(subtemp,
((ClassTemplate) subtemp).getMode());
}
} catch (SyntaxElementException ex) {
errorBucket.addException(ex);
return false;
}
if (subtemp.getSemDisambiguate() == null)
errorBucket.addError("No semantic disambiguate in template.",
subtemp);
else {
rulebody
.append("semDisambRuleData.add(new SemanticDisambRuleData(\""
+ ruleName
+ "\",\""
+ subtemp.getSemDisambiguate() + "\"));\n");
}
}
if (isOperatorTemplate) {
rulebody.append("Object lefthand = ret;\n");
String proxyStr = ClassTemplateHandler
.createModelElementProxyString(operatorParentTemplate,
true, metaObjectListParam);
rulebody.append(proxyStr);
rulebody
.append("setSemDisambiguate(ret,lefthand,"
+ opnameParameter
+ ",semRef,semDisambRuleData,false, (ANTLR3LocationToken)firstToken);\n}");
} else {
rulebody
.append("setSemDisambiguate(ret,null,"
+ opnameParameter
+ ",semRef,semDisambRuleData,false, (ANTLR3LocationToken)firstToken);\n}");
}
if (hasSyntacticDisambiguate(template))
rulebody.append(")");
firstSemanticDisambiguate = false;
return true;
}
public boolean subtemplatesHaveSemanticDisambiguate() {
for (Template subtemp : templates) {
if (subtemp.getSemDisambiguate() != null) {
return true;
}
}
return false;
}
private boolean hasSyntacticDisambiguate(Template template) {
return template.getDisambiguateV3() != null;
}
}