001 package org.maltparser.core.syntaxgraph.node;
002
003 import java.util.NoSuchElementException;
004 import java.util.Set;
005 import java.util.SortedSet;
006 import java.util.TreeSet;
007
008 import org.maltparser.core.exception.MaltChainedException;
009 import org.maltparser.core.helper.SystemLogger;
010 import org.maltparser.core.symbol.SymbolTable;
011 import org.maltparser.core.syntaxgraph.LabelSet;
012 import org.maltparser.core.syntaxgraph.SyntaxGraphException;
013 import org.maltparser.core.syntaxgraph.edge.Edge;
014
015
016 public class Token extends GraphNode implements TokenNode, DependencyNode, PhraseStructureNode {
017 /**
018 * the previous terminal node in the linear precedence
019 */
020 protected TokenNode predecessor = null;
021 /**
022 * the next terminal node in the linear precedence
023 */
024 protected TokenNode successor = null;
025
026 /**
027 * a reference to a node where the node is part of a component. If the node is unconnected it will reference to it self.
028 */
029 protected DependencyNode component;
030 protected int rank;
031
032 protected int index;
033
034 protected PhraseStructureNode parent;
035 protected final SortedSet<DependencyNode> heads;
036 protected final SortedSet<DependencyNode> leftDependents;
037 protected final SortedSet<DependencyNode> rightDependents;
038
039
040 public Token() throws MaltChainedException {
041 parent = null;
042 heads = new TreeSet<DependencyNode>();
043 leftDependents = new TreeSet<DependencyNode>();
044 rightDependents = new TreeSet<DependencyNode>();
045 clear();
046 }
047
048 /**
049 * Sets the predecessor terminal node in the linear order of the terminal nodes.
050 *
051 * @param predecessor the predecessor terminal node
052 */
053 public void setPredecessor(TokenNode predecessor) {
054 this.predecessor = predecessor;
055 }
056
057 /**
058 * Sets the predecessor terminal node in the linear order of the terminal nodes.
059 *
060 * @param successor the successor terminal node
061 */
062 public void setSuccessor(TokenNode successor) {
063 this.successor = successor;
064 }
065
066 /**
067 * Returns the predecessor terminal node in the linear order of the terminal nodes.
068 *
069 * @return the predecessor terminal node in the linear order of the terminal nodes.
070 */
071 public TokenNode getPredecessor() {
072 return predecessor;
073 }
074
075 /**
076 * Returns the successor terminal node in the linear order of the terminal nodes.
077 *
078 * @return the successor terminal node in the linear order of the terminal nodes.
079 */
080 public TokenNode getSuccessor() {
081 return successor;
082 }
083
084 public int getRank() {
085 return rank;
086 }
087
088 public void setRank(int r) {
089 this.rank = r;
090 }
091
092 public DependencyNode findComponent() {
093 return findComponent(this);
094 }
095
096 private DependencyNode findComponent(DependencyNode x) {
097 if (x != x.getComponent()) {
098 x.setComponent(findComponent(x.getComponent()));
099 }
100 return x.getComponent();
101 }
102
103 public DependencyNode getComponent() {
104 return component;
105 }
106
107 public void setComponent(DependencyNode x) {
108 this.component = x;
109 }
110
111 public void addIncomingEdge(Edge in) throws MaltChainedException {
112 super.addIncomingEdge(in);
113 if (in.getSource() != null) {
114 if (in.getType() == Edge.DEPENDENCY_EDGE && in.getSource() instanceof DependencyNode) {
115 if (heads.size() >= 1) {
116 heads.add((DependencyNode)in.getSource());
117 } else {
118 heads.add((DependencyNode)in.getSource());
119 }
120 } else if (in.getType() == Edge.PHRASE_STRUCTURE_EDGE && in.getSource() instanceof PhraseStructureNode) {
121 parent = (PhraseStructureNode)in.getSource();
122 }
123 }
124 }
125
126 public void removeIncomingEdge(Edge in) throws MaltChainedException {
127 super.removeIncomingEdge(in);
128 if (in.getSource() != null) {
129 if (in.getType() == Edge.DEPENDENCY_EDGE && in.getSource() instanceof DependencyNode) {
130 heads.remove((DependencyNode)in.getSource());
131 } else if (in.getType() == Edge.PHRASE_STRUCTURE_EDGE && in.getSource() instanceof PhraseStructureNode) {
132 if (in.getSource() == parent) {
133 this.parent = null;
134 }
135 }
136 }
137 }
138
139 public void addOutgoingEdge(Edge out) throws MaltChainedException {
140 super.addOutgoingEdge(out);
141 if (out.getType() == Edge.DEPENDENCY_EDGE && out.getTarget() instanceof DependencyNode) {
142 final DependencyNode dependent = (DependencyNode)out.getTarget();
143 if (compareTo(dependent) > 0) {
144 leftDependents.add((DependencyNode)dependent);
145 } else if (compareTo(dependent) < 0) {
146 rightDependents.add((DependencyNode)dependent);
147 }
148 }
149 }
150
151 public void removeOutgoingEdge(Edge out) throws MaltChainedException {
152 super.removeOutgoingEdge(out);
153 if (out.getType() == Edge.DEPENDENCY_EDGE && out.getTarget() instanceof DependencyNode) {
154 final DependencyNode dependent = (DependencyNode)out.getTarget();
155 if (compareTo(dependent) > 0) {
156 leftDependents.remove((DependencyNode)dependent);
157 } else if (compareTo(dependent) < 0) {
158 rightDependents.remove((DependencyNode)dependent);
159 }
160 }
161 }
162
163 public void setIndex(int index) throws MaltChainedException {
164 if (index > 0) {
165 this.index = index;
166 } else {
167 throw new SyntaxGraphException("A terminal node must have a positive integer value and not index "+index+". ");
168 }
169 }
170
171 public int getIndex() {
172 return index;
173 }
174
175 public int getCompareToIndex() {
176 return index;
177 }
178
179 public boolean isRoot() {
180 return false;
181 }
182
183 public DependencyNode getAncestor() throws MaltChainedException {
184 if (!this.hasHead()) {
185 return this;
186 }
187
188 DependencyNode tmp = this;
189 while (tmp.hasHead()) {
190 tmp = tmp.getHead();
191 }
192 return tmp;
193 }
194
195 public DependencyNode getProperAncestor() throws MaltChainedException {
196 if (!this.hasHead()) {
197 return null;
198 }
199
200 DependencyNode tmp = this;
201 while (tmp.hasHead()) {
202 tmp = tmp.getHead();
203 }
204 return tmp;
205 }
206
207 public ComparableNode getLeftmostProperDescendant() throws MaltChainedException {
208 ComparableNode candidate = null;
209 ComparableNode tmp = null;
210 for (DependencyNode ldep : leftDependents) {
211 if (candidate == null) {
212 candidate = ldep;
213 } else if (ldep.getIndex() < candidate.getIndex() ) {
214 candidate = ldep;
215 }
216 tmp = ((Token)ldep).getLeftmostProperDescendant();
217 if (tmp == null) {
218 continue;
219 }
220 if (candidate == null) {
221 candidate = tmp;
222 } else if (tmp.getIndex() < candidate.getIndex() ) {
223 candidate = tmp;
224 }
225 if (candidate.getIndex() == 1) {
226 return candidate;
227 }
228 }
229 for (DependencyNode rdep : rightDependents) {
230 if (candidate == null) {
231 candidate = rdep;
232 } else if (rdep.getIndex() < candidate.getIndex() ) {
233 candidate = rdep;
234 }
235 tmp = ((Token)rdep).getLeftmostProperDescendant();
236 if (tmp == null) {
237 continue;
238 }
239 if (candidate == null) {
240 candidate = tmp;
241 } else if (tmp.getIndex() < candidate.getIndex() ) {
242 candidate = tmp;
243 }
244 if (candidate.getIndex() == 1) {
245 return candidate;
246 }
247 }
248 return candidate;
249 }
250
251 public ComparableNode getRightmostProperDescendant() throws MaltChainedException {
252 ComparableNode candidate = null;
253 ComparableNode tmp = null;
254 for (DependencyNode ldep : leftDependents) {
255 if (candidate == null) {
256 candidate = ldep;
257 } else if (ldep.getIndex() > candidate.getIndex() ) {
258 candidate = ldep;
259 }
260 tmp = ((Token)ldep).getRightmostProperDescendant();
261 if (tmp == null) {
262 continue;
263 }
264 if (candidate == null) {
265 candidate = tmp;
266 } else if (tmp.getIndex() > candidate.getIndex() ) {
267 candidate = tmp;
268 }
269 }
270 for (DependencyNode rdep : rightDependents) {
271 if (candidate == null) {
272 candidate = rdep;
273 } else if (rdep.getIndex() > candidate.getIndex() ) {
274 candidate = rdep;
275 }
276 tmp = ((Token)rdep).getRightmostProperDescendant();
277 if (tmp == null) {
278 continue;
279 }
280 if (candidate == null) {
281 candidate = tmp;
282 } else if (tmp.getIndex() > candidate.getIndex() ) {
283 candidate = tmp;
284 }
285 }
286 return candidate;
287 }
288
289 public ComparableNode getLeftmostDescendant() throws MaltChainedException {
290 ComparableNode candidate = this;
291 ComparableNode tmp = null;
292 for (DependencyNode ldep : leftDependents) {
293 if (candidate == null) {
294 candidate = ldep;
295 } else if (ldep.getIndex() < candidate.getIndex() ) {
296 candidate = ldep;
297 }
298 tmp = ((Token)ldep).getLeftmostDescendant();
299 if (tmp == null) {
300 continue;
301 }
302 if (candidate == null) {
303 candidate = tmp;
304 } else if (tmp.getIndex() < candidate.getIndex() ) {
305 candidate = tmp;
306 }
307 if (candidate.getIndex() == 1) {
308 return candidate;
309 }
310 }
311 for (DependencyNode rdep : rightDependents) {
312 if (candidate == null) {
313 candidate = rdep;
314 } else if (rdep.getIndex() < candidate.getIndex() ) {
315 candidate = rdep;
316 }
317 tmp = ((Token)rdep).getLeftmostDescendant();
318 if (tmp == null) {
319 continue;
320 }
321 if (candidate == null) {
322 candidate = tmp;
323 } else if (tmp.getIndex() < candidate.getIndex() ) {
324 candidate = tmp;
325 }
326 if (candidate.getIndex() == 1) {
327 return candidate;
328 }
329 }
330 return candidate;
331 }
332
333 public ComparableNode getRightmostDescendant() throws MaltChainedException {
334 ComparableNode candidate = this;
335 ComparableNode tmp = null;
336 for (DependencyNode ldep : leftDependents) {
337 if (candidate == null) {
338 candidate = ldep;
339 } else if (ldep.getIndex() > candidate.getIndex() ) {
340 candidate = ldep;
341 }
342 tmp = ((Token)ldep).getRightmostDescendant();
343 if (tmp == null) {
344 continue;
345 }
346 if (candidate == null) {
347 candidate = tmp;
348 } else if (tmp.getIndex() > candidate.getIndex() ) {
349 candidate = tmp;
350 }
351 }
352 for (DependencyNode rdep : rightDependents) {
353 if (candidate == null) {
354 candidate = rdep;
355 } else if (rdep.getIndex() > candidate.getIndex() ) {
356 candidate = rdep;
357 }
358 tmp = ((Token)rdep).getRightmostDescendant();
359 if (tmp == null) {
360 continue;
361 }
362 if (candidate == null) {
363 candidate = tmp;
364 } else if (tmp.getIndex() > candidate.getIndex() ) {
365 candidate = tmp;
366 }
367 }
368 return candidate;
369 }
370
371 public PhraseStructureNode getParent() {
372 return parent;
373 }
374
375 public Edge getParentEdge() throws MaltChainedException {
376 for (Edge e : incomingEdges) {
377 if (e.getSource() == parent && e.getType() == Edge.PHRASE_STRUCTURE_EDGE) {
378 return e;
379 }
380 }
381 return null;
382 }
383
384 public String getParentEdgeLabelSymbol(SymbolTable table) throws MaltChainedException {
385 for (Edge e : incomingEdges) {
386 if (e.getSource() == parent && e.getType() == Edge.PHRASE_STRUCTURE_EDGE) {
387 return e.getLabelSymbol(table);
388 }
389 }
390 return null;
391 }
392
393 public int getParentEdgeLabelCode(SymbolTable table) throws MaltChainedException {
394 for (Edge e : incomingEdges) {
395 if (e.getSource() == parent && e.getType() == Edge.PHRASE_STRUCTURE_EDGE) {
396 return e.getLabelCode(table);
397 }
398 }
399 return -1;
400 }
401
402 public boolean hasParentEdgeLabel(SymbolTable table) throws MaltChainedException {
403 for (Edge e : incomingEdges) {
404 if (e.getSource() == parent && e.getType() == Edge.PHRASE_STRUCTURE_EDGE) {
405 return e.hasLabel(table);
406 }
407 }
408 return false;
409 }
410
411 public boolean hasAtMostOneHead() {
412 return heads.size() <= 1;
413 }
414
415 public boolean hasAncestorInside(int left, int right) throws MaltChainedException {
416 DependencyNode tmp = this;
417 if (tmp.getHead() != null) {
418 tmp = tmp.getHead();
419 if (tmp.getIndex() >= left && tmp.getIndex() <= right) {
420 return true;
421 }
422 }
423 return false;
424 }
425
426 public Set<Edge> getHeadEdges() throws MaltChainedException {
427 return incomingEdges;
428 }
429
430 public Set<DependencyNode> getHeads() throws MaltChainedException {
431 return heads;
432 }
433
434 public boolean hasHead() {
435 return heads.size() != 0;
436 }
437
438 public DependencyNode getHead() throws MaltChainedException {
439 if (!hasHead()) {
440 return null;
441 }
442 if (heads.size() > 1) {
443 throw new SyntaxGraphException("The dependency node is multi-headed and it is ambigious to return a single-head dependency node. ");
444 }
445 // heads.first();
446 for (DependencyNode head : heads) {
447 return head;
448 }
449 return null;
450 }
451
452 public Edge getHeadEdge() throws MaltChainedException {
453 if (heads.size() == 0) {
454 return null;
455 }
456 if (incomingEdges.size() == 1 && incomingEdges.first() instanceof DependencyNode) {
457 return incomingEdges.first();
458 }
459 if (heads.size() == 1) {
460 for (Edge e : incomingEdges) {
461 if (e.getSource() == heads.first()) {
462 return e;
463 }
464 }
465 }
466 return null;
467 }
468
469 public void addHeadEdgeLabel(SymbolTable table, String symbol) throws MaltChainedException {
470 if (hasHead()) {
471 getHeadEdge().addLabel(table, symbol);
472 }
473 }
474
475 public void addHeadEdgeLabel(SymbolTable table, int code) throws MaltChainedException {
476 if (hasHead()) {
477 getHeadEdge().addLabel(table, code);
478 }
479 }
480
481 public void addHeadEdgeLabel(LabelSet labelSet) throws MaltChainedException {
482 if (hasHead()) {
483 getHeadEdge().addLabel(labelSet);
484 }
485 }
486
487 public boolean hasHeadEdgeLabel(SymbolTable table) throws MaltChainedException {
488 if (!hasHead()) {
489 return false;
490 }
491 return getHeadEdge().hasLabel(table);
492 }
493
494 public String getHeadEdgeLabelSymbol(SymbolTable table) throws MaltChainedException {
495 return getHeadEdge().getLabelSymbol(table);
496 }
497
498 public int getHeadEdgeLabelCode(SymbolTable table) throws MaltChainedException {
499 if (!hasHead()) {
500 return 0;
501 }
502 return getHeadEdge().getLabelCode(table);
503 }
504
505 public boolean isHeadEdgeLabeled() throws MaltChainedException {
506 if (!hasHead()) {
507 return false;
508 }
509 return getHeadEdge().isLabeled();
510 }
511
512 public int nHeadEdgeLabels() throws MaltChainedException {
513 if (!hasHead()) {
514 return 0;
515 }
516 return getHeadEdge().nLabels();
517 }
518
519 public Set<SymbolTable> getHeadEdgeLabelTypes() throws MaltChainedException {
520 return getHeadEdge().getLabelTypes();
521 }
522
523 public LabelSet getHeadEdgeLabelSet() throws MaltChainedException {
524 return getHeadEdge().getLabelSet();
525 }
526
527 public boolean hasDependent() {
528 return hasLeftDependent() || hasRightDependent();
529 }
530
531 /**
532 * Returns <code>true</code> if the node has one or more left dependents, otherwise <code>false</code>.
533 *
534 * @return <code>true</code> if the node has one or more left dependents, otherwise <code>false</code>.
535 */
536 public boolean hasLeftDependent() {
537 return !leftDependents.isEmpty();
538 }
539
540 /**
541 * Returns the left dependent at the position <code>index</code>, where <code>index==0</code> equals the left most dependent.
542 *
543 * @param index the index
544 * @return the left dependent at the position <code>index</code>, where <code>index==0</code> equals the left most dependent
545 */
546 public DependencyNode getLeftDependent(int index) {
547 if (0 <= index && index < leftDependents.size()) {
548 int i = 0;
549 DependencyNode candidate = null;
550
551 for (DependencyNode node : leftDependents) {
552 candidate = node;
553 if (i == index) {
554 return candidate;
555 }
556 i++;
557 }
558 }
559 return null;
560 }
561
562 /**
563 * Return the number of left dependents
564 *
565 * @return the number of left dependents
566 */
567 public int getLeftDependentCount() {
568 return leftDependents.size();
569 }
570
571 public SortedSet<DependencyNode> getLeftDependents() {
572 return leftDependents;
573 }
574
575 /**
576 * Returns the left sibling if it exists, otherwise <code>null</code>
577 *
578 * @return the left sibling if it exists, otherwise <code>null</code>
579 */
580 public DependencyNode getLeftSibling() throws MaltChainedException {
581 if (getHead() == null) {
582 return null;
583 }
584
585 DependencyNode candidate = null;
586 for (DependencyNode node : getHead().getLeftDependents()) {
587 if (node == this) {
588 return candidate;
589 }
590 candidate = node;
591 }
592 for (DependencyNode node : getHead().getRightDependents()) {
593 if (node == this) {
594 return candidate;
595 }
596 candidate = node;
597 }
598 return null;
599 }
600
601 /**
602 * Returns the left sibling at the same side of head as the node it self. If not found <code>null</code is returned
603 *
604 * @return the left sibling at the same side of head as the node it self. If not found <code>null</code is returned
605 */
606 public DependencyNode getSameSideLeftSibling() throws MaltChainedException {
607 if (getHead() == null) {
608 return null;
609 } else if (this.getIndex() < getHead().getIndex()) {
610 try {
611 return getHead().getLeftDependents().headSet(this).last();
612 } catch (NoSuchElementException e) {
613 return null;
614 }
615 } else if (this.getIndex() > getHead().getIndex()) {
616 try {
617 return getHead().getRightDependents().headSet(this).last();
618 } catch (NoSuchElementException e) {
619 return null;
620 }
621 }
622 return null;
623 }
624
625 /**
626 * Returns the closest left dependent to the node it self, if not found <code>null</code> is returned.
627 *
628 * @return the closest left dependent to the node it self, if not found <code>null</code> is returned.
629 */
630 public DependencyNode getClosestLeftDependent() {
631 try {
632 return leftDependents.last();
633 } catch (NoSuchElementException e) {
634 return null;
635 }
636 }
637
638 public DependencyNode getLeftmostDependent() {
639 for (DependencyNode dep : leftDependents) {
640 return dep;
641 }
642 return null;
643 // try {
644 // return leftDependents.first();
645 // } catch (NoSuchElementException e) {
646 // return null;
647 // }
648 }
649
650 public DependencyNode getRightDependent(int index) {
651 int size = rightDependents.size();
652 if (index < size) {
653 return rightDependents.toArray(new DependencyNode[size])[size - 1 - index];
654 }
655 return null;
656 // if (0 <= index && index < rightDependents.size()) {
657 // int i = 0;
658 // DependencyNode candidate = null;
659 //
660 // for (DependencyNode node : rightDependents) {
661 // candidate = node;
662 // if (i == index) {
663 // return candidate;
664 // }
665 // i++;
666 // }
667 // }
668 // return null;
669 }
670
671 /**
672 * Return the number of right dependents
673 *
674 * @return the number of right dependents
675 */
676 public int getRightDependentCount() {
677 return rightDependents.size();
678 }
679
680 /**
681 * Returns a sorted set of right dependents.
682 *
683 * @return a sorted set of right dependents.
684 */
685 public SortedSet<DependencyNode> getRightDependents() {
686 return rightDependents;
687 }
688
689 /**
690 * Returns the right sibling if it exists, otherwise <code>null</code>
691 *
692 * @return the right sibling if it exists, otherwise <code>null</code>
693 */
694 public DependencyNode getRightSibling() throws MaltChainedException {
695 if (getHead() == null) {
696 return null;
697 }
698
699 for (DependencyNode node : getHead().getLeftDependents()) {
700 if (node.getIndex() > this.getIndex()) {
701 return node;
702 }
703 }
704 for (DependencyNode node : getHead().getRightDependents()) {
705 if (node.getIndex() > this.getIndex()) {
706 return node;
707 }
708 }
709 return null;
710 }
711
712 /**
713 * Returns the right sibling at the same side of head as the node it self. If not found <code>null</code is returned
714 *
715 * @return the right sibling at the same side of head as the node it self. If not found <code>null</code is returned
716 */
717 public DependencyNode getSameSideRightSibling() throws MaltChainedException {
718 if (getHead() == null) {
719 return null;
720 } else if (this.getIndex() < getHead().getIndex()) {
721 final SortedSet<DependencyNode> tailSet = getHead().getLeftDependents().tailSet(this);
722 if (tailSet.size() <= 1) {
723 return null;
724 }
725 return tailSet.toArray(new DependencyNode[tailSet.size()])[1];
726 } else if (this.getIndex() > getHead().getIndex()) {
727 final SortedSet<DependencyNode> tailSet = getHead().getRightDependents().tailSet(this);
728 if (tailSet.size() <= 1) {
729 return null;
730 }
731 return tailSet.toArray(new DependencyNode[tailSet.size()])[1];
732 }
733 return null;
734 }
735
736 /**
737 * Returns the closest right dependent to the node it self, if not found <code>null</code> is returned.
738 *
739 * @return the closest right dependent to the node it self, if not found <code>null</code> is returned.
740 */
741 public DependencyNode getClosestRightDependent() {
742 for (DependencyNode dep : rightDependents) {
743 return dep;
744 }
745 return null;
746 // try {
747 // return rightDependents.first();
748 // } catch (NoSuchElementException e) {
749 // return null;
750 // }
751 }
752
753 public DependencyNode getRightmostDependent() {
754 int n = rightDependents.size();
755 int i = 1;
756 for (DependencyNode node : rightDependents) {
757 if (i == n) {
758 return node;
759 }
760 i++;
761 }
762 return null;
763 // try {
764 // return rightDependents.last();
765 // } catch (NoSuchElementException e) {
766 // return null;
767 // }
768 }
769
770 protected void getDependencyDominationSet(SortedSet<DependencyNode> dominationSet) {
771 if (leftDependents.size() > 0 || rightDependents.size() > 0) {
772 dominationSet.addAll(leftDependents);
773 dominationSet.addAll(rightDependents);
774
775 for (DependencyNode node : leftDependents) {
776 ((Token)node).getDependencyDominationSet(dominationSet);
777 }
778 for (DependencyNode node : rightDependents) {
779 ((Token)node).getDependencyDominationSet(dominationSet);
780 }
781 }
782 }
783
784 // private SortedSet<DependencyNode> getDependencyDominationSet() {
785 // SortedSet<DependencyNode> dominationSet = new TreeSet<DependencyNode>();
786 // getDependencyDominationSet(dominationSet);
787 // return dominationSet;
788 // }
789
790
791 /**
792 * Returns <code>true</code> if the node has one or more right dependents, otherwise <code>false</code>.
793 *
794 * @return <code>true</code> if the node has one or more right dependents, otherwise <code>false</code>.
795 */
796 public boolean hasRightDependent() {
797 return !rightDependents.isEmpty();
798 }
799
800 public boolean isProjective() throws MaltChainedException {
801 if (hasHead() && !getHead().isRoot()) {
802 final DependencyNode head = getHead();
803 if (getHead().getIndex() < this.getIndex()) {
804 TokenNode terminals = ((TokenNode)head);
805 DependencyNode tmp = null;
806 while (true) {
807 if (terminals == null || terminals.getSuccessor() == null) {
808 return false;
809 }
810 if (terminals.getSuccessor() == this) {
811 break;
812 }
813 tmp = terminals = terminals.getSuccessor();
814 while (tmp != this && tmp != head) {
815 if (!tmp.hasHead()) {
816 return false;
817 }
818 tmp = tmp.getHead();
819 }
820 }
821 } else {
822 TokenNode terminals = ((TokenNode)this);
823 DependencyNode tmp = null;
824 while (true) {
825 if (terminals == null || terminals.getSuccessor() == null) {
826 return false;
827 }
828 if (terminals.getSuccessor() == head) {
829 break;
830 }
831 tmp = terminals = terminals.getSuccessor();
832 while (tmp != this && tmp != head) {
833 if (!tmp.hasHead()) {
834 return false;
835 }
836 tmp = tmp.getHead();
837 }
838 }
839 }
840 }
841 return true;
842 }
843
844 public int getDependencyNodeDepth() throws MaltChainedException {
845 DependencyNode tmp = this;
846 int depth = 0;
847 while (tmp.hasHead()) {
848 depth++;
849 tmp = tmp.getHead();
850 }
851 return depth;
852 }
853
854 public void clear() throws MaltChainedException {
855 super.clear();
856 predecessor = null;
857 successor = null;
858 component = this;
859 rank = 0;
860 parent = null;
861 heads.clear();
862 leftDependents.clear();
863 rightDependents.clear();
864 }
865
866 @Override
867 public int compareTo(ComparableNode that) {
868 final int BEFORE = -1;
869 final int EQUAL = 0;
870 final int AFTER = 1;
871 if (this == that) return EQUAL;
872
873 if (that instanceof TokenNode) {
874 if (this.index < that.getCompareToIndex()) return BEFORE;
875 if (this.index > that.getCompareToIndex()) return AFTER;
876 return super.compareTo(that);
877 }
878 if (that instanceof NonTerminalNode) {
879 try {
880 final int thisLCorner = this.index;
881 final int thatLCorner = that.getLeftmostProperDescendantIndex();
882 final int thisRCorner = this.index;
883 final int thatRCorner = that.getRightmostProperDescendantIndex();
884
885 // if (thisLCorner == -1 || thatLCorner == -1) {
886 // if (thisRCorner < thatRCorner) return BEFORE;
887 // if (thisRCorner > thatRCorner) return AFTER;
888 // }
889 // if (thisRCorner == -1 || thatRCorner == -1) {
890 // if (thisLCorner < thatLCorner) return BEFORE;
891 // if (thisLCorner > thatLCorner) return AFTER;
892 // }
893
894 if (thisLCorner != -1 && thatLCorner != -1 && thisRCorner != -1 && thatRCorner != -1) {
895 if (thisLCorner < thatLCorner && thisRCorner < thatRCorner) return BEFORE;
896 if (thisLCorner > thatLCorner && thisRCorner > thatRCorner) return AFTER;
897 if (thisLCorner > thatLCorner && thisRCorner < thatRCorner) return BEFORE;
898 if (thisLCorner < thatLCorner && thisRCorner > thatRCorner) return AFTER;
899 } else {
900 if (thisLCorner != -1 && thatLCorner != -1) {
901 if (thisLCorner < thatLCorner) return BEFORE;
902 if (thisLCorner > thatLCorner) return AFTER;
903 }
904 if (thisRCorner != -1 && thatRCorner != -1) {
905 if (thisRCorner < thatRCorner) return BEFORE;
906 if (thisRCorner > thatRCorner) return AFTER;
907 }
908 }
909
910
911
912 // final int thisLCorner = this.index;
913 // final int thatLCorner = that.getLeftmostDescendantIndex();
914 // final int thisRCorner = this.index;
915 // final int thatRCorner = that.getRightmostDescendantIndex();
916 //
917 // if (thisLCorner == -1 || thatLCorner == -1) {
918 // if (thisRCorner < thatRCorner) return BEFORE;
919 // if (thisRCorner > thatRCorner) return AFTER;
920 // }
921 // if (thisRCorner == -1 || thatRCorner == -1) {
922 // if (thisLCorner < thatLCorner) return BEFORE;
923 // if (thisLCorner > thatLCorner) return AFTER;
924 // }
925 // if (thisLCorner < thatLCorner && thisRCorner < thatRCorner) return BEFORE;
926 // if (thisLCorner > thatLCorner && thisRCorner > thatRCorner) return AFTER;
927 // if (thisLCorner > thatLCorner && thisRCorner < thatRCorner) return BEFORE;
928 // if (thisLCorner < thatLCorner && thisRCorner > thatRCorner) return AFTER;
929
930
931
932 // int corner = that.getLeftmostDescendantIndex();
933 // if (corner != -1) {
934 // if (this.index < corner) return BEFORE;
935 // if (this.index > corner) return AFTER;
936 // }
937 // corner = that.getRightmostDescendantIndex();
938 // if (corner != -1) {
939 // if (this.index < corner) return BEFORE;
940 // if (this.index > corner) return AFTER;
941 // }
942 } catch (MaltChainedException e) {
943 if (SystemLogger.logger().isDebugEnabled()) {
944 SystemLogger.logger().debug("",e);
945 } else {
946 SystemLogger.logger().error(e.getMessageChain());
947 }
948 System.exit(1);
949 }
950 }
951 if (this.index < that.getCompareToIndex()) return BEFORE;
952 if (this.index > that.getCompareToIndex()) return AFTER;
953 return super.compareTo(that);
954 }
955
956 public boolean equals(Object obj) {
957 Token v = (Token)obj;
958 if (!(this.predecessor == v.predecessor && this.successor == v.successor)) return false;
959 return super.equals(obj);
960 }
961
962 public int hashCode() {
963 int hash = 7;
964 hash = 31 * hash + (null == predecessor ? 0 : predecessor.hashCode());
965 hash = 31 * hash + (null == successor ? 0 : successor.hashCode());
966 return 31 * hash + super.hashCode();
967 }
968
969
970 public String toString() {
971 final StringBuilder sb = new StringBuilder();
972 sb.append(super.toString());
973 return sb.toString();
974 }
975 }