001package gudusoft.gsqlparser.resolver2.scope;
002
003import gudusoft.gsqlparser.nodes.TParseTreeNode;
004import gudusoft.gsqlparser.resolver2.ScopeType;
005import gudusoft.gsqlparser.resolver2.matcher.INameMatcher;
006import gudusoft.gsqlparser.resolver2.model.QualifiedName;
007import gudusoft.gsqlparser.resolver2.model.ScopeChild;
008import gudusoft.gsqlparser.resolver2.namespace.INamespace;
009
010import java.util.Collections;
011import java.util.List;
012
013/**
014 * Abstract base class for all scopes.
015 * Implements delegation pattern - most methods delegate to parent.
016 *
017 * Subclasses only need to override methods where they have special behavior.
018 */
019public abstract class AbstractScope implements IScope {
020
021    /** Parent scope (never null - root has EmptyScope parent) */
022    protected final IScope parent;
023
024    /** Associated AST node */
025    protected final TParseTreeNode node;
026
027    /** Scope type */
028    protected final ScopeType scopeType;
029
030    protected AbstractScope(IScope parent, TParseTreeNode node, ScopeType scopeType) {
031        if (parent == null) {
032            throw new IllegalArgumentException("Parent scope cannot be null. Use EmptyScope for root.");
033        }
034        this.parent = parent;
035        this.node = node;
036        this.scopeType = scopeType;
037    }
038
039    @Override
040    public IScope getParent() {
041        return parent;
042    }
043
044    @Override
045    public TParseTreeNode getNode() {
046        return node;
047    }
048
049    @Override
050    public ScopeType getScopeType() {
051        return scopeType;
052    }
053
054    /**
055     * Default implementation: delegate to parent
056     */
057    @Override
058    public void resolve(List<String> names,
059                       INameMatcher matcher,
060                       boolean deep,
061                       IResolved resolved) {
062        parent.resolve(names, matcher, deep, resolved);
063    }
064
065    /**
066     * Default implementation: delegate to parent
067     */
068    @Override
069    public INamespace resolveTable(String tableName) {
070        return parent.resolveTable(tableName);
071    }
072
073    /**
074     * Default implementation: not supported (most scopes don't have children)
075     */
076    @Override
077    public void addChild(INamespace namespace, String alias, boolean nullable) {
078        throw new UnsupportedOperationException(
079            "Scope type " + scopeType + " does not support adding children");
080    }
081
082    /**
083     * Default implementation: empty list
084     */
085    @Override
086    public List<ScopeChild> getChildren() {
087        return Collections.emptyList();
088    }
089
090    /**
091     * Default implementation: delegate to parent
092     */
093    @Override
094    public List<INamespace> getVisibleNamespaces() {
095        return parent.getVisibleNamespaces();
096    }
097
098    /**
099     * Default implementation: delegate to parent
100     */
101    @Override
102    public QualifiedName fullyQualify(String name) {
103        return parent.fullyQualify(name);
104    }
105
106    /**
107     * Default implementation: check ancestry
108     */
109    @Override
110    public boolean isWithin(IScope ancestorScope) {
111        if (this == ancestorScope) {
112            return true;
113        }
114        if (parent == null) {
115            return false;
116        }
117        return parent.isWithin(ancestorScope);
118    }
119
120    @Override
121    public String toString() {
122        StringBuilder sb = new StringBuilder();
123        sb.append(scopeType);
124        if (node != null) {
125            sb.append("(").append(node.getClass().getSimpleName()).append(")");
126        }
127        return sb.toString();
128    }
129}