package com.github.sommeri.less4j.core.parser; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.List; import org.antlr.runtime.CommonToken; import org.antlr.runtime.Token; import org.antlr.runtime.tree.CommonTree; import com.github.sommeri.less4j.LessSource; public class HiddenTokenAwareTree extends CommonTree implements Cloneable { private final LessSource source; private List<CommonToken> preceding = new LinkedList<CommonToken>(); private List<CommonToken> orphans = new LinkedList<CommonToken>(); private List<CommonToken> following = new LinkedList<CommonToken>(); private CommonToken tokenAsCommon; private LexerLogic grammarKnowledge = new LexerLogic(); protected int generalType = -3; private Token stopToken; public HiddenTokenAwareTree(CommonToken payload, LessSource source) { super(payload); this.source = source; tokenAsCommon = payload; } public HiddenTokenAwareTree(LessSource source) { super(); this.source = source; } public HiddenTokenAwareTree(CommonTree node, LessSource source) { super(node); this.source = source; } public LessSource getSource() { return source; } @Override public HiddenTokenAwareTree getChild(int i) { return (HiddenTokenAwareTree) super.getChild(i); } @SuppressWarnings("unchecked") public List<HiddenTokenAwareTree> getChildren() { List<? extends Object> result = super.getChildren(); if (result == null) result = Collections.emptyList(); return (List<HiddenTokenAwareTree>) result; } public boolean hasChildren() { @SuppressWarnings("rawtypes") List children = super.getChildren(); return children!=null && !children.isEmpty(); } @Override public HiddenTokenAwareTree getParent() { return (HiddenTokenAwareTree) super.getParent(); } public List<CommonToken> getPreceding() { return preceding; } public List<CommonToken> chopPreceedingUpToLastOfType(int type) { List<CommonToken> result = new ArrayList<CommonToken>(); List<CommonToken> preceding = getPreceding(); int index = lastTokenOfType(preceding, type); for (int i = 0; i <= index; i++) { CommonToken next = preceding.remove(0); result.add(next); } return result; } private int lastTokenOfType(List<CommonToken> list, int type) { if (list.isEmpty()) return -1; for (int i = list.size() - 1; i >= 0; i--) { Token token = (Token) list.get(i); if (token.getType() == type) return i; } return -1; } public List<CommonToken> getFollowing() { return following; } public List<CommonToken> getOrphans() { return orphans; } public void addPreceding(CommonToken token) { preceding.add(token); } public void addPreceding(List<CommonToken> tokens) { preceding.addAll(tokens); } public void addBeforePreceding(List<CommonToken> tokens) { preceding.addAll(0, tokens); } public void addOrphan(CommonToken token) { orphans.add(token); } public void addOrphans(List<CommonToken> tokens) { orphans.addAll(tokens); } public void addFollowing(CommonToken token) { following.add(token); } public void addBeforeFollowing(List<CommonToken> tokens) { following.addAll(0, tokens); } public void addFollowing(List<CommonToken> tokens) { following.addAll(tokens); } public void pushHiddenToKids() { List<HiddenTokenAwareTree> children = getChildren(); if (children == null || children.isEmpty()) return; HiddenTokenAwareTree first = children.get(0); first.addBeforePreceding(getPreceding()); removePreceding(); HiddenTokenAwareTree last = children.get(children.size() - 1); last.addFollowing(getFollowing()); removeFollowing(); } public void giveHidden(HiddenTokenAwareTree previous, HiddenTokenAwareTree next) { if (previous != null) previous.addFollowing(getPreceding()); if (next != null) next.addBeforePreceding(getFollowing()); } public void moveHidden(HiddenTokenAwareTree previous, HiddenTokenAwareTree next) { if (previous != null) { previous.addFollowing(getPreceding()); preceding = new LinkedList<CommonToken>(); } if (next != null) { next.addBeforePreceding(getFollowing()); following = new LinkedList<CommonToken>(); } } public HiddenTokenAwareTree getLastChild() { return getChild(getChildCount() - 1); } /** * Lines numbering starts with 1. */ public int getLine() { if ( !isReal() ) { HiddenTokenAwareTree realChild = getFirstRealDescendant(); if ( realChild!=null ) { return realChild.getLine(); } return 0; } return token.getLine(); } /** * Columns numbering starts with 1. */ public int getColumn() { if ( !isReal() ) { HiddenTokenAwareTree realChild = getFirstRealDescendant(); if ( realChild!=null ) { return realChild.getCharPositionInLine(); } return 0; } return token.getCharPositionInLine(); } private HiddenTokenAwareTree getFirstRealDescendant() { for (HiddenTokenAwareTree child : getChildren()) { if (child.isReal()) return child; else { HiddenTokenAwareTree descendant = child.getFirstRealDescendant(); if (descendant!=null) return descendant; } } return null; } public int getCharPositionInLine() { if ( !isReal() ) { HiddenTokenAwareTree realChild = getFirstRealDescendant(); if ( realChild!=null ) { return realChild.getCharPositionInLine(); } return 1; } return token.getCharPositionInLine(); } public String toString() { return super.toString() + " " + getLine() + ":" + getCharPositionInLine() + 1; } public HiddenTokenAwareTree getNextSibling() { if (getParent() == null) return null; List<HiddenTokenAwareTree> siblings = getParent().getChildren(); int indx = siblings.indexOf(this) + 1; return indx >= siblings.size() ? null : siblings.get(indx); } public HiddenTokenAwareTree getPreviousSibling() { if (getParent() == null) return null; List<HiddenTokenAwareTree> siblings = getParent().getChildren(); int indx = siblings.indexOf(this) - 1; return indx < 0 ? null : siblings.get(indx); } public void pushHiddenToSiblings() { pushPreviousHiddenToSibling(); pushFollowingHiddenToSibling(); } public void pushFollowingHiddenToSibling() { HiddenTokenAwareTree nextSibling = getNextSibling(); if (nextSibling != null) { nextSibling.addBeforePreceding(getFollowing()); getFollowing().clear(); } } public void pushPreviousHiddenToSibling() { HiddenTokenAwareTree previousSibling = getPreviousSibling(); if (previousSibling != null) { previousSibling.addFollowing(getPreceding()); getPreceding().clear(); } } public void removePreceding() { preceding = new ArrayList<CommonToken>(); } public void removeFollowing() { following = new ArrayList<CommonToken>(); } public boolean isReal() { return tokenAsCommon!=null && tokenAsCommon.getTokenIndex()!=-1; } public HiddenTokenAwareTree commentsLessClone() { try { HiddenTokenAwareTree clone = (HiddenTokenAwareTree) super.clone(); clone.preceding = new LinkedList<CommonToken>(); clone.orphans = new LinkedList<CommonToken>(); clone.following = new LinkedList<CommonToken>(); return clone; } catch (CloneNotSupportedException e) { throw new IllegalStateException(); } } @Override @Deprecated public int getType() { return super.getType(); } public int getGeneralType() { if ( generalType==-3 ) { generalType = generalizeTokenType(super.getType()); } return generalType; } private int generalizeTokenType(int type) { if (grammarKnowledge.isAtName(type)) return LessLexer.AT_NAME; if (grammarKnowledge.isIdentifier(type)) return LessLexer.IDENT; return type; } public int getTokenIndex() { if ( token!=null ) { return token.getTokenIndex(); } // return startIndex; } public void setStopToken(Token stopToken) { this.stopToken = stopToken; } public Token getStopToken() { return this.stopToken; } }