package com.sap.ide.cts.parser.incremental;
import static com.sap.furcas.runtime.textblocks.TbNavigationUtil.getNextInSubTree;
import static com.sap.furcas.runtime.textblocks.TbNavigationUtil.getSubNodeAt;
import static com.sap.furcas.runtime.textblocks.TbNavigationUtil.getSubNodes;
import static com.sap.furcas.runtime.textblocks.TbNavigationUtil.isLastInSubTree;
import static com.sap.furcas.runtime.textblocks.TbNavigationUtil.isToken;
import static com.sap.furcas.runtime.textblocks.modifcation.TbMarkingUtil.isEOS;
import static com.sap.furcas.runtime.textblocks.modifcation.TbMarkingUtil.marked;
import static com.sap.furcas.runtime.textblocks.modifcation.TbVersionUtil.getOtherVersion;
import java.util.List;
import com.sap.furcas.metamodel.FURCAS.textblocks.AbstractToken;
import com.sap.furcas.metamodel.FURCAS.textblocks.Bostoken;
import com.sap.furcas.metamodel.FURCAS.textblocks.DocumentNode;
import com.sap.furcas.metamodel.FURCAS.textblocks.Eostoken;
import com.sap.furcas.metamodel.FURCAS.textblocks.TextBlock;
import com.sap.furcas.metamodel.FURCAS.textblocks.TextblocksFactory;
import com.sap.furcas.metamodel.FURCAS.textblocks.Version;
public abstract class IncrementalRecognizer {
public static final String EOS = "EOS";
public static final String BOS = "BOS";
protected Bostoken bosRef;
protected Eostoken eosRef;
protected TextblocksFactory textblocksFactory = TextblocksFactory.eINSTANCE;
/**
* As the Beginning of Stream (BOS) token is always the first token in the root textblock this token is used here
*
* @param root
* The root textblock of the document to lex
*/
protected void setBOSFromRoot(TextBlock root) {
bosRef = (Bostoken) root.getSubNodes().get(0);
}
/**
* As the End of Stream (EOS) token is always the last token in the root textblock this token is used here
*
* @param root
* The root textblock of the document to lex
*/
protected void setEOSFromRoot(TextBlock root) {
eosRef = (Eostoken) root.getSubNodes().get(root.getSubNodes().size() - 1);
}
/**
* Find the next marked token within or after node.
*/
protected AbstractToken findNextRegion(DocumentNode node) {
if (isEOS(node) || (isToken(node) && marked((AbstractToken) node))) {
return (AbstractToken) node;
}
if (node instanceof TextBlock && hasNestedChanges((TextBlock) node, Version.PREVIOUS)) {
return findNextRegion(getSubNodeAt(((TextBlock) node), 0));
}
if (node instanceof TextBlock && ((TextBlock) node).getParent() == null) {
// node is the parent block and there were no changes detected so
// return EOS which
// is always the last token within the Root Textblock
return eosRef;
}
return findNextRegion(nextSubtree(node));
}
protected DocumentNode nextSubtree(DocumentNode node) {
TextBlock parent = node.getParent();
if (parent == null) {
// node is the root node so there is no further subtree
return eosRef;
}
if (isLastInSubTree(node)) {
while (parent.getParent() != null && isLastInSubTree(parent)) {
// its the last element, so traverse to the next subtree and
// find the first leaf there
parent = parent.getParent();
}
DocumentNode child = getNextInSubTree(parent);
return child;
} else {
List<? extends DocumentNode> parentSubNodes = getSubNodes(parent);
return parentSubNodes.get(parentSubNodes.indexOf(node) + 1);
}
}
/**
* This method should be overridden if a parser uses another token type for eof/oes than -1
*
* @return the token type representing end of stream
*/
protected static int getEOSTokenType() {
return -1;
}
/**
* This method should be overridden if a parser uses another token type for bof/bes than -1
*
* @return the token type representing beginning of stream
*/
protected static int getBOSTokenType() {
return -2;
}
protected static boolean hasNestedChanges(TextBlock node, Version reference) {
TextBlock otherVersion = getOtherVersion(node, reference);
if (otherVersion == null) {
// this means it is a new block which also means that the block is changed
return true;
} else {
return otherVersion.isChildrenChanged();
}
}
protected static boolean wasReLexed(AbstractToken token) {
// TODO check if this is correct here
return token.isRelexingNeeded();
}
}