package com.sap.furcas.runtime.parser.impl; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.regex.Pattern; import org.eclipse.emf.ecore.EObject; import antlr.Token; import com.sap.furcas.runtime.common.exceptions.ModelAdapterException; import com.sap.furcas.runtime.common.implementation.ResolvedModelElementProxy; import com.sap.furcas.runtime.common.interfaces.IModelElementProxy; import com.sap.furcas.runtime.parser.ANTLR3LocationToken; import com.sap.furcas.runtime.parser.IModelAdapter; import com.sap.furcas.runtime.parser.ModelElementCreationException; import com.sap.furcas.runtime.parser.ParsingError; import com.sap.furcas.runtime.parser.exceptions.UnknownProductionRuleException; import com.sap.furcas.runtime.parser.impl.context.ContextManager; public class SemanticDisambiguateDelayedReference extends DelayedReference { public SemanticDisambiguateDelayedReference(IModelElementProxy currentContextElement, Object proxy, Object element, Object opTemplateLefthand, String opName, List<SemanticDisambRuleData> preds, ANTLR3LocationToken lastToken, ANTLR3LocationToken firstToken, boolean hasContext, boolean b) { super(currentContextElement, DelayedReference.ReferenceType.SEMANTIC_DISAMBIGUATE, proxy, element, opTemplateLefthand, opName, preds, lastToken, firstToken, hasContext, b); } public boolean isSemanticDisambiguatedOperatorRule() { return opTemplateLefthand != null; } public boolean setDelayedReference(DelayedReference reference, IModelAdapter modelAdapter, ContextManager contextManager, ObservableInjectingParser parser) { Object contextElement = reference.getContextElement(); if (contextElement instanceof IModelElementProxy) { IModelElementProxy proxyContext = (IModelElementProxy) contextElement; contextElement = proxyContext.getRealObject(); } try { Iterator<SemanticDisambRuleData> dataIt = reference.getSemRulData().iterator(); boolean resultFound = false; while (dataIt.hasNext()) { SemanticDisambRuleData nextRuleData = dataIt.next(); int beginRef = nextRuleData.getOcl().indexOf("${"); String flattenOCL = DelayedReferencesHelper.appendFlattenToOclQuery(nextRuleData.getOcl()); if (beginRef >= 0) { String semReference = nextRuleData.getOcl().substring(beginRef, nextRuleData.getOcl().indexOf('}', beginRef + 1) + 1); String replacedBy; // TODO support other types than string if (isBasicType(reference.getSemanticObject())) { replacedBy = "'" + reference.getSemanticObject().toString() + "'"; } else { replacedBy = "?"; } String replacedOCL = nextRuleData.getOcl().replaceAll(Pattern.quote(semReference), replacedBy); if (replacedOCL.contains("#source")) { replacedOCL = replacedOCL.replace("#source", "self"); } flattenOCL = DelayedReferencesHelper.appendFlattenToOclQuery(replacedOCL); } // evaluate the predicate by OCL, return value is a list of // objects Object currentContextElement; if (nextRuleData.getOcl().contains("#source") && reference.isSemanticDisambiguatedOperatorRule()) { if (reference.getOpTemplateLefthand() instanceof ModelElementProxy) { currentContextElement = ((ModelElementProxy) reference.getOpTemplateLefthand()).getRealObject(); } else { currentContextElement = reference.getOpTemplateLefthand(); } } else { currentContextElement = contextElement; } Collection<?> result = modelAdapter.evaluateOCLQuery(currentContextElement, null, flattenOCL, currentContextElement); // if there is no result it will be null if (result.isEmpty()) { resultFound = false; } else { Iterator<?> resultIt = result.iterator(); // loop over the results to handle them one by one boolean ruleFound = false; while (resultIt.hasNext()) { Object nextResult = resultIt.next(); if (nextResult instanceof Boolean) { if (((Boolean) nextResult).booleanValue()) { if (ruleFound) { parser.getInjector().addError(new ParsingError("The semantic disambiguate matches more than one rule", reference.getToken())); return false; } ruleFound = true; resultFound = true; setReferenceForSemanticDisambiguatedRule(parser, reference, nextRuleData.getRule(), modelAdapter); } } else { parser.getInjector().addError(new ParsingError("The rule " + nextRuleData.getRule() + " has a semantic disambiguate which does not evaluate to a bool value", reference.getToken())); return false; } } } } if (!resultFound) { parser.getInjector().addError(new ParsingError("The semantic disambiguate did not match any rule", reference.getToken())); return false; } } catch (IllegalAccessException e) { parser.getInjector().addError(new ParsingError(e.getMessage(), reference.getToken())); return false; } catch (SecurityException e) { parser.getInjector().addError(new ParsingError(e.getMessage(), reference.getToken())); return false; } catch (IllegalArgumentException e) { parser.getInjector().addError(new ParsingError(e.getMessage(), reference.getToken())); return false; } catch (UnknownProductionRuleException e) { parser.getInjector().addError(new ParsingError(e.getMessage(), reference.getToken())); return false; } catch (NoSuchMethodException e) { parser.getInjector().addError(new ParsingError(e.getMessage(), reference.getToken())); return false; } catch (InvocationTargetException e) { parser.getInjector().addError(new ParsingError(e.getMessage(), reference.getToken())); return false; } catch (ModelElementCreationException e) { parser.getInjector().addError(new ParsingError(e.getMessage(), reference.getToken())); return false; } catch (ModelAdapterException e) { parser.getInjector().addError(new ParsingError(e.getMessage(), reference.getToken())); return false; } return true; } private void setReferenceForSemanticDisambiguatedRule(ObservableInjectingParser parser, DelayedReference reference, String ruleName, IModelAdapter modelAdapter) throws SecurityException, UnknownProductionRuleException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, ModelElementCreationException, ModelAdapterException { // invoke the parser to execute the template Method methodToCall = parser.getClass().getMethod(ruleName, String.class, Object.class, Token.class); if (!Modifier.isFinal(methodToCall.getModifiers())) { throw new UnknownProductionRuleException(ruleName + " is not a production rule in generated Parser."); } boolean originalResolveProxiesValue = parser.isResolveProxies(); parser.setResolveProxies(false); parser.reset(); IModelElementProxy proxyForContextElement = null; if (reference.getContextElement() instanceof IModelElementProxy) { proxyForContextElement = (IModelElementProxy) reference.getContextElement(); } else { proxyForContextElement = new ResolvedModelElementProxy(reference.getContextElement()); } if (parser.getContextManager().getContextForElement(reference.getContextElement()) == null) { parser.addContext(proxyForContextElement); if (proxyForContextElement.getRealObject() != null && reference.getContextElement() instanceof EObject) { parser.getContextManager().notifyProxyResolvedWith(proxyForContextElement, reference.getContextElement(), /* * no creation context element needs to be provided here because * the proxy has just been created and has not been added to any * other context */null); } } else { parser.getCurrentContextStack().push(proxyForContextElement); // the Context object was already created // elsewhere } try { parser.getTokenStream().seek(reference.getFirstToken().getTokenIndex()); Object parseReturn; if (reference.isSemanticDisambiguatedOperatorRule()) { parseReturn = methodToCall.invoke(parser, reference.getPropertyName(), reference.getOpTemplateLefthand(), reference.getFirstToken()); } else { parseReturn = methodToCall.invoke(parser); } // add the parsed part to the object parser.setResolveProxies(originalResolveProxiesValue); reference.setRealValue(parser.getInjector().createOrResolve((ModelElementProxy) parseReturn, null, null)); // by default use partition of reference.getModelElement if (reference.getModelElement() instanceof EObject && reference.getRealValue() instanceof EObject) { ((EObject) reference.getContextElement()).eResource().getContents() .add((EObject) reference.getRealValue()); } ModelElementProxy oldModelElement = ((ModelElementProxy) reference.getModelElement()); oldModelElement.setRealObject(reference.getRealValue()); Object parentProxy = oldModelElement.getParent(); Object parentElement = ((ModelElementProxy) parentProxy).getRealObject(); String parentPropertyName = oldModelElement.getParentPropertyName(); modelAdapter.set(parentElement, parentPropertyName, reference.getRealValue()); } finally { if (reference.hasContext()) { parser.leaveContext(); } parser.getCurrentContextStack().pop(); } } // TODO support the other basic types as well private boolean isBasicType(Object ref) { if (ref instanceof String) { return true; } return false; } }