Package com.dci.intellij.dbn.language.common.element.lookup

Source Code of com.dci.intellij.dbn.language.common.element.lookup.AbstractElementTypeLookupCache

package com.dci.intellij.dbn.language.common.element.lookup;

import com.dci.intellij.dbn.language.common.SharedTokenTypeBundle;
import com.dci.intellij.dbn.language.common.TokenType;
import com.dci.intellij.dbn.language.common.element.ElementType;
import com.dci.intellij.dbn.language.common.element.ElementTypeBundle;
import com.dci.intellij.dbn.language.common.element.IdentifierElementType;
import com.dci.intellij.dbn.language.common.element.IterationElementType;
import com.dci.intellij.dbn.language.common.element.LeafElementType;
import com.dci.intellij.dbn.language.common.element.QualifiedIdentifierElementType;
import com.dci.intellij.dbn.language.common.element.SequenceElementType;
import com.dci.intellij.dbn.language.common.element.TokenElementType;
import com.dci.intellij.dbn.language.common.element.impl.WrappingDefinition;
import com.dci.intellij.dbn.language.common.element.util.IdentifierCategory;
import com.dci.intellij.dbn.language.common.element.util.IdentifierType;
import com.dci.intellij.dbn.object.common.DBObjectType;
import gnu.trove.THashMap;
import gnu.trove.THashSet;

import java.util.Map;
import java.util.Set;

public abstract class AbstractElementTypeLookupCache<T extends ElementType> implements ElementTypeLookupCache<T> {
    private T elementType;

    //protected Set<IdentifierCacheElement> identifierTypes;
    protected Map<DBObjectType, Map<IdentifierType, Set<IdentifierCategory>>> identifierTypes;
    protected Set<DBObjectType> virtualObjects;
    protected Set<LeafElementType> allPossibleLeafs = new THashSet<LeafElementType>();
    protected Set<LeafElementType> firstPossibleLeafs = new THashSet<LeafElementType>();
    protected Set<LeafElementType> firstRequiredLeafs = new THashSet<LeafElementType>();
    protected Set<TokenType> allPossibleTokens = new THashSet<TokenType>();
    protected Set<TokenType> firstPossibleTokens = new THashSet<TokenType>();
    protected Set<TokenType> firstRequiredTokens = new THashSet<TokenType>();
    private Map<TokenType, Boolean> landmarkTokens;
    private Boolean startsWithIdentifier;

    private Set<TokenType> nextPossibleTokens;
    private Set<TokenType> nextRequiredTokens;


    public AbstractElementTypeLookupCache(T elementType) {
        this.elementType = elementType;
        if (!elementType.isLeaf()) {
            landmarkTokens = new THashMap<TokenType, Boolean>();
        }
        WrappingDefinition wrapping = getElementType().getWrapping();
        if (wrapping != null) {
            TokenType wrappingBeginTokenType = wrapping.getBeginElementType().getTokenType();
            TokenType wrappingEndTokenType = wrapping.getEndElementType().getTokenType();
            allPossibleTokens.add(wrappingBeginTokenType);
            allPossibleTokens.add(wrappingEndTokenType);
            firstPossibleTokens.add(wrappingBeginTokenType);
        }
    }

    public void init() {}

    public T getElementType() {
        return elementType;
    }

    private ElementTypeBundle getBundle() {
        return elementType.getElementBundle();
    }


    public boolean containsToken(TokenType tokenType) {
        return allPossibleTokens != null && allPossibleTokens.contains(tokenType);
    }

    public boolean containsLeaf(LeafElementType leafElementType) {
        return leafElementType == getElementType() || (allPossibleLeafs != null && allPossibleLeafs.contains(leafElementType));
    }

    public boolean containsVirtualObject(DBObjectType objectType) {
        return virtualObjects != null && virtualObjects.contains(objectType);
    }

    public boolean containsIdentifier(DBObjectType objectType, IdentifierType identifierType, IdentifierCategory identifierCategory) {
        if (identifierTypes != null) {
            Map<IdentifierType, Set<IdentifierCategory>> identifierTypeMap = identifierTypes.get(objectType);
            if (identifierTypeMap != null) {
                Set<IdentifierCategory> identifierCategorySet = identifierTypeMap.get(identifierType);
                if (identifierCategorySet != null) {
                    return identifierCategory == IdentifierCategory.ALL || identifierCategorySet.contains(identifierCategory);
                }
            }
        }

        DBObjectType genericType = objectType.getGenericType() != objectType ? objectType.getGenericType() : null;
        while (genericType != null) {
            if (containsIdentifier(genericType, identifierType, identifierCategory)) return true;
            genericType = genericType.getGenericType() != genericType ? genericType.getGenericType() : null;
        }
        return false;
    }

    public boolean containsIdentifier(DBObjectType objectType, IdentifierType identifierType) {
        return containsIdentifier(objectType, identifierType, IdentifierCategory.ALL);
    }

    private void addIdentifier(DBObjectType objectType, IdentifierType identifierType, IdentifierCategory identifierCategory){
        if (identifierTypes == null) {
            identifierTypes = new THashMap<DBObjectType, Map<IdentifierType, Set<IdentifierCategory>>>();
        }

        Map<IdentifierType, Set<IdentifierCategory>> identifierTypeMap = identifierTypes.get(objectType);
        if (identifierTypeMap == null) {
            identifierTypeMap = new THashMap<IdentifierType, Set<IdentifierCategory>>();
            identifierTypes.put(objectType, identifierTypeMap);
        }

        Set<IdentifierCategory> identifierCategorySet = identifierTypeMap.get(identifierType);
        if (identifierCategorySet == null) {
            identifierCategorySet = new THashSet<IdentifierCategory>();
            identifierTypeMap.put(identifierType, identifierCategorySet);
        }
        identifierCategorySet.add(identifierCategory);

        for (DBObjectType inheritingObjectType : objectType.getInheritingTypes()) {
            addIdentifier(inheritingObjectType, identifierType, identifierCategory);
        }

    }

    public boolean containsIdentifier(IdentifierElementType identifierElementType) {
        return containsIdentifier(
                identifierElementType.getObjectType(),
                identifierElementType.getIdentifierType(),
                identifierElementType.isReference() ? IdentifierCategory.REFERENCE : IdentifierCategory.DEFINITION);
    }

    public Set<LeafElementType> getFirstPossibleLeafs() {
        return firstPossibleLeafs;
    }

    public Set<TokenType> getFirstPossibleTokens() {
        return firstPossibleTokens;
    }

    public Set<LeafElementType> getFirstRequiredLeafs() {
        return firstRequiredLeafs;
    }

    public Set<TokenType> getFirstRequiredTokens() {
        return firstRequiredTokens;
    }

    public boolean canStartWithLeaf(LeafElementType leafElementType) {
        return firstPossibleLeafs.contains(leafElementType);
    }

    public boolean canStartWithToken(TokenType tokenType) {
        return firstPossibleTokens.contains(tokenType);
    }

    public boolean shouldStartWithLeaf(LeafElementType leafElementType) {
        return firstRequiredLeafs.contains(leafElementType);
    }

    public boolean shouldStartWithToken(TokenType tokenType) {
        return firstRequiredTokens.contains(tokenType);
    }

    public void registerLeaf(LeafElementType leaf, ElementType pathChild) {
        boolean initAllElements = !containsLeaf(leaf);
        boolean isFirstPossibleElements = isFirstPossibleLeaf(leaf, pathChild);
        boolean isFirstRequiredLeaf = isFirstRequiredLeaf(leaf, pathChild);

        // register first possible leafs
        ElementTypeLookupCache lookupCache = leaf.getLookupCache();
        if (isFirstPossibleElements) {
            firstPossibleLeafs.add(leaf);
            firstPossibleTokens.addAll(lookupCache.getFirstPossibleTokens());
        }

        // register first required leafs
        if (isFirstRequiredLeaf) {
            firstRequiredLeafs.add(leaf);
            firstRequiredTokens.addAll(lookupCache.getFirstRequiredTokens());
        }

        if (initAllElements) {
            // register all possible leafs
            allPossibleLeafs.add(leaf);

            // register all possible tokens
            if (leaf instanceof IdentifierElementType) {
                SharedTokenTypeBundle sharedTokenTypes = getElementType().getLanguage().getSharedTokenTypes();
                allPossibleTokens.add(sharedTokenTypes.getIdentifier());
                allPossibleTokens.add(sharedTokenTypes.getQuotedIdentifier());
            } else {
                allPossibleTokens.add(leaf.getTokenType());
            }

            // register identifiers
            if (leaf instanceof IdentifierElementType) {
                IdentifierElementType identifierElementType = (IdentifierElementType) leaf;
                if (!containsIdentifier(identifierElementType)) {
                    addIdentifier(
                            identifierElementType.getObjectType(),
                            identifierElementType.getIdentifierType(),
                            identifierElementType.isReference() ? IdentifierCategory.REFERENCE : IdentifierCategory.DEFINITION);
                }

            }

        }

        if (isFirstPossibleElements || isFirstRequiredLeaf || initAllElements) {
            // walk the tree up
            registerLeafInParent(leaf);
        }
    }

    protected void registerLeafInParent(LeafElementType leaf) {
        ElementType parent = getElementType().getParent();
        if (parent != null) {
            parent.getLookupCache().registerLeaf(leaf, getElementType());
        }
    }

    public void registerVirtualObject(DBObjectType objectType) {
        if (virtualObjects == null) {
            virtualObjects = new THashSet<DBObjectType>();
        }
        virtualObjects.add(objectType);
        ElementType parent = getElementType().getParent();
        if (parent != null) {
            parent.getLookupCache().registerVirtualObject(objectType);
        }

    }

    public synchronized boolean containsLandmarkToken(TokenType tokenType) {
        if (getElementType().isLeaf()) return containsToken(tokenType);

        Boolean value = landmarkTokens.get(tokenType);
        if (value == null) {
            value = containsLandmarkToken(tokenType, null);
            landmarkTokens.put(tokenType, value);
        }
        return value;
    }


    public synchronized boolean startsWithIdentifier() {
        if (startsWithIdentifier == null) {
            startsWithIdentifier =  startsWithIdentifier(null);
        }
        return startsWithIdentifier;
    }

    public boolean containsIdentifiers() {
        return containsToken(getBundle().getTokenTypeBundle().getIdentifier());
    }

    /**
     * This method returns all possible tokens (optional or not) which may follow current element.
     *
     * NOTE: to be used only for limited scope, since the tree walk-up
     * is done only until first named element is hit.
     * (named elements do not have parents)
     */
    public Set<TokenType> getNextPossibleTokens() {
        if (nextPossibleTokens == null) {
            nextPossibleTokens = new THashSet<TokenType>();
            ElementType elementType = getElementType();
            ElementType parentElementType = elementType.getParent();
            while (parentElementType != null) {
                if (parentElementType instanceof SequenceElementType) {
                    SequenceElementType sequenceElementType = (SequenceElementType) parentElementType;
                    int elementsCount = sequenceElementType.getElementTypes().length;
                    int index = sequenceElementType.indexOf(elementType, 0);

                    for (int i = index + 1; i < elementsCount; i++) {
                        ElementType next = sequenceElementType.getElementTypes()[i];
                        nextPossibleTokens.addAll(next.getLookupCache().getFirstPossibleTokens());
                        if (!sequenceElementType.isOptional(i)) {
                            parentElementType = null;
                            break;
                        }
                    }
                } else if (parentElementType instanceof IterationElementType) {
                    IterationElementType iteration = (IterationElementType) parentElementType;
                    TokenElementType[] separatorTokens = iteration.getSeparatorTokens();
                    if (separatorTokens != null) {
                        for (TokenElementType separatorToken : separatorTokens) {
                            nextPossibleTokens.add(separatorToken.getTokenType());
                        }
                    }
                }
                if (parentElementType != null) {
                    elementType = parentElementType;
                    parentElementType = elementType.getParent();
                }
            }
        }
        return nextPossibleTokens;
    }

    /**
     * This method returns all required tokens which may follow current element.
     *
     * NOTE: to be used only for limited scope, since the tree walk-up
     * is done only until first named element is hit.
     * (named elements do not have parents)
     */
    public Set<TokenType> getNextRequiredTokens() {
        if (nextRequiredTokens == null) {
            nextRequiredTokens = new THashSet<TokenType>();
            ElementType elementType = getElementType();
            ElementType parentElementType = elementType.getParent();
            while (parentElementType != null) {
                if (parentElementType instanceof SequenceElementType) {
                    SequenceElementType sequence = (SequenceElementType) parentElementType;
                    int elementsCount = sequence.getElementTypes().length;
                    int index = sequence.indexOf(elementType, 0);

                    for (int i = index + 1; i < elementsCount; i++) {
                        if (!sequence.isOptional(i)) {
                            ElementType next = sequence.getElementTypes()[i];
                            nextRequiredTokens.addAll(next.getLookupCache().getFirstPossibleTokens());
                            parentElementType = null;
                            break;
                        }
                    }
                } else if (parentElementType instanceof IterationElementType) {
                    IterationElementType iteration = (IterationElementType) parentElementType;
                    TokenElementType[] separatorTokens = iteration.getSeparatorTokens();
                    if (separatorTokens == null) {
                        nextRequiredTokens.addAll(iteration.getLookupCache().getFirstPossibleTokens());
                    } else {
                        for (TokenElementType separatorToken : separatorTokens) {
                            nextRequiredTokens.add(separatorToken.getTokenType());
                        }
                    }
                } else if (parentElementType instanceof QualifiedIdentifierElementType){
                    QualifiedIdentifierElementType qualifiedIdentifier = (QualifiedIdentifierElementType) parentElementType;
                    for (LeafElementType[] variant : qualifiedIdentifier.getVariants()) {
                        for (int i=0; i<variant.length; i++) {
                            if (variant[i] == elementType && i < variant.length-1) {
                                nextRequiredTokens.add(qualifiedIdentifier.getSeparatorToken().getTokenType());
                                parentElementType = null;
                                break;
                            }
                        }
                    }
                }
                if (parentElementType != null) {
                    elementType = parentElementType;
                    parentElementType = elementType.getParent();
                }
            }
        }
        return nextRequiredTokens;
    }
}
TOP

Related Classes of com.dci.intellij.dbn.language.common.element.lookup.AbstractElementTypeLookupCache

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.