/******************************************************************************* * 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 java.util.ArrayList; import java.util.List; import com.sap.furcas.metamodel.FURCAS.TCS.Alternative; import com.sap.furcas.metamodel.FURCAS.TCS.Block; import com.sap.furcas.metamodel.FURCAS.TCS.ConditionalElement; import com.sap.furcas.metamodel.FURCAS.TCS.CustomSeparator; import com.sap.furcas.metamodel.FURCAS.TCS.FunctionCall; import com.sap.furcas.metamodel.FURCAS.TCS.InjectorActionsBlock; import com.sap.furcas.metamodel.FURCAS.TCS.Literal; import com.sap.furcas.metamodel.FURCAS.TCS.LiteralRef; import com.sap.furcas.metamodel.FURCAS.TCS.Property; import com.sap.furcas.metamodel.FURCAS.TCS.Sequence; import com.sap.furcas.metamodel.FURCAS.TCS.SequenceElement; import com.sap.furcas.parsergenerator.tcs.t2m.grammar.constraints.RuleBodyPropertyConstraint; 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.parser.exceptions.SyntaxParsingException; import com.sap.furcas.runtime.tcs.SyntaxLookup; import com.sap.furcas.runtime.tcs.TemplateNamingHelper; /** * Utility class to make Interfaces easier to understand. * Works as a combination of a StringBuffer and a Class to be called recursively. * This class calls handlers which during that call may call this class again, to produce nested production rule bodies. * * @author C5107456 */ public class RuleBodyStringBuffer { // elements protected to make unit testing a bit easier /** The alternative handler. */ protected final AlternativeHandler alternativeHandler; private final InjectorActionsHandler<?> injectorActionsHandler; /** The block handler. */ protected final BlockTypeHandler blockHandler; /** The con el handler. */ protected final ConditionalElementHandler<?> conElHandler; /** The property handler. */ protected final PropertyTypeHandler<?> propertyHandler; /** The syntax lookup. */ protected final SyntaxLookup syntaxLookup; /** The buf. */ private final VarStringBuffer buf = new VarStringBuffer(); protected final TemplateNamingHelper<?> namingHelper; private final List<RuleBodyPropertyConstraint> constraints = new ArrayList<RuleBodyPropertyConstraint>(); protected final SemanticErrorBucket errorBucket; /** * Instantiates a new rule body string buffer. * * @param newAlternativeHandler the alternative handler * @param blockHandler the block handler * @param conElHandler the con el handler * @param propertyHandler the property handler * @param syntaxLookup the syntax lookup * @param namingHelper * @param errorBucket * @param newInjectorActionsHandler */ public RuleBodyStringBuffer(AlternativeHandler newAlternativeHandler, BlockTypeHandler blockHandler, ConditionalElementHandler<?> conElHandler, PropertyTypeHandler<?> propertyHandler, SyntaxLookup syntaxLookup, TemplateNamingHelper<?> namingHelper, InjectorActionsHandler<?> newInjectorActionsHandler, SemanticErrorBucket errorBucket) { super(); this.alternativeHandler = newAlternativeHandler; this.injectorActionsHandler = newInjectorActionsHandler; this.blockHandler = blockHandler; this.conElHandler = conElHandler; this.propertyHandler = propertyHandler; this.syntaxLookup = syntaxLookup; this.namingHelper = namingHelper; this.errorBucket = errorBucket; } /** * Append. * * @param object the object */ public void append(Object object) { if (object != null ) { buf.append(object); } } /** * Appends the array of objects. * @param objectArr */ public void append(Object... objectArr) { if (objectArr != null ) { buf.append(objectArr); } } /** * Append. * * @param character the character */ public void append(char character) { buf.append(character); } /** * Gets the result. * * @return the result */ public String getResult() { return buf.toString(); } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return getResult(); } protected void addToRuleFragment(Sequence seq) throws MetaModelLookupException { if (seq == null) { return; } blockHandler.addElement(seq, this); } /** * recursive call for elements that do not create a rule of their own, but influence creation of a rule body. * * @param element the element * * @throws SyntaxParsingException the syntax parsing exception * @throws MetaModelLookupException the meta model lookup exception */ protected void addToRuleFragment(SequenceElement element) throws MetaModelLookupException { try { if (element == null) { return; } this.append(ObservationDirectivesHelper.getEnterSequenceElementNotification(element)); if (element instanceof Block) { Block seq = (Block) element; blockHandler.addElement(seq, this); } else if (element instanceof Property) { Property prop = (Property) element; propertyHandler.addElement(prop, this); } else if (element instanceof Literal) { Literal lit = (Literal) element; this.append(lit.getValue()); } else if (element instanceof LiteralRef) { LiteralRef lit = (LiteralRef) element; if (lit.getReferredLiteral() == null) { throw new RuntimeException("Bug: Missing reference, check that references were set after parsing in " + element); } String value = lit.getReferredLiteral().getValue(); this.append(syntaxLookup.getSymbolRule(value)); } else if (element instanceof ConditionalElement) { ConditionalElement conEl = (ConditionalElement) element; conElHandler.addElement(conEl, this); } else if (element instanceof Alternative) { Alternative alt = (Alternative) element; alternativeHandler.addElement(alt, this); } else if (element instanceof InjectorActionsBlock) { InjectorActionsBlock block = (InjectorActionsBlock) element; injectorActionsHandler.addElement(block, this); } else if (element instanceof CustomSeparator) { // CustomSeparator conEl = (CustomSeparator) element; // ignore here, only relevant for serializing // throw new RuntimeException("CustomSeparator mapping not implemented yet in " + element.getLocation()); } else if (element instanceof FunctionCall) { FunctionCall funcCall = (FunctionCall) element; if (funcCall.getCalledFunction() == null) { throw new RuntimeException("Bug: Missing Function Template in function call in " + element); } String rulename = namingHelper.getRuleName(funcCall.getCalledFunction()); this.append(rulename + "[ret]"); } else { // should never happen, as long as TCS defines only the SequenceElement subclasses above throw new RuntimeException("Unknown kind of SequenceElement " + element.getClass()); } } catch (SyntaxElementException e) { errorBucket.addException(e); } this.append(ObservationDirectivesHelper.getExitSequenceElementNotification()); } /** * @param inverseConstraint * @return */ public RuleBodyPropertyConstraint setPropertyConstraint( RuleBodyPropertyConstraint constraint) { constraints.add(constraint); return constraint; } /** * to be used by PropertyHandler * @return */ public List<RuleBodyPropertyConstraint> getCurrentConstraints() { return constraints; } /** * to be used by ConditionalElementHandler after body building. * @param constraint */ public void removeConstraint(RuleBodyPropertyConstraint constraint) { if (constraints.indexOf(constraint) == constraints.size()-1) { constraints.remove(constraint); } else { // should never happen throw new RuntimeException("Constraint to be removed but not last in list: " + constraints + " : " + constraint); } } }