/*
* ParentheticListUpdateDelegate.java
*
* Copyright (c) 2006 David Holroyd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package uk.co.badgersinfoil.metaas.impl;
import org.asdt.core.internal.antlr.AS3Parser;
import uk.co.badgersinfoil.metaas.impl.antlr.LinkedListToken;
import uk.co.badgersinfoil.metaas.impl.antlr.LinkedListTree;
import uk.co.badgersinfoil.metaas.impl.antlr.TreeTokenListUpdateDelegate;
public class ParentheticListUpdateDelegate implements TreeTokenListUpdateDelegate {
// TODO: many methods simply duplicate those in
// BasicListUpdateDelegate, maybe just subclass it?
private int tokenTypeOpen;
private int tokenTypeClose;
public ParentheticListUpdateDelegate(int tokenTypeOpen, int tokenTypeClose) {
this.tokenTypeOpen = tokenTypeOpen;
this.tokenTypeClose = tokenTypeClose;
}
public void addedChild(LinkedListTree parent, LinkedListTree child) {
LinkedListToken insert = findClose(parent).getPrev();
insertAfter(insert, insert.getNext(),
child.getStartToken(), child.getStopToken());
}
private LinkedListToken findOpen(LinkedListTree parent) {
for (LinkedListToken tok=parent.getStartToken(); tok!=null; tok=tok.getNext()) {
if (tok.getType() == tokenTypeOpen) {
return tok;
}
}
return null;
}
private LinkedListToken findClose(LinkedListTree parent) {
for (LinkedListToken tok=parent.getStopToken(); tok!=null; tok=tok.getPrev()) {
if (tok.getType() == tokenTypeClose) {
return maybeSkiptoLinePreceeding(tok);
}
}
return null;
}
private LinkedListToken maybeSkiptoLinePreceeding(LinkedListToken target) {
for (LinkedListToken tok=target.getPrev(); tok!=null; tok=tok.getPrev()) {
switch (tok.getType()) {
case AS3Parser.WS:
continue;
case AS3Parser.NL:
return tok;
default:
return target;
}
}
return target;
}
protected static void insertAfter(LinkedListToken target, LinkedListToken targetNext,
LinkedListToken start, LinkedListToken stop)
{
if (target == null && targetNext == null) {
throw new IllegalArgumentException("At least one of target and targetNext must be non-null");
}
if (start != null) {
// i.e. we're not adding an imaginary node that currently
// has no real children
if (target != null) {
target.setNext(start);
}
stop.setNext(targetNext);
if (targetNext != null) {
targetNext.setPrev(stop);
}
}
}
public void addedChild(LinkedListTree tree, int index, LinkedListTree child) {
LinkedListToken target;
LinkedListToken targetNext;
if (index == 0) {
target = findOpen(tree);
targetNext = target.getNext();
} else {
LinkedListTree prev = (LinkedListTree)tree.getChild(index - 1);
target = prev.getStopToken();
targetNext = target.getNext();
}
insertAfter(target, targetNext,
child.getStartToken(), child.getStopToken());
}
public void appendToken(LinkedListTree parent, LinkedListToken append) {
LinkedListToken insert = findClose(parent).getPrev();
insertAfter(insert, insert.getNext(),
append, append);
}
public void addToken(LinkedListTree parent, int index, LinkedListToken append) {
LinkedListToken target;
LinkedListToken targetNext;
if (index == 0) {
target = findOpen(parent);
targetNext = target.getNext();
} else {
LinkedListTree beforeChild = (LinkedListTree)parent.getChild(index);
targetNext = beforeChild.getStartToken();
target = targetNext.getPrev();
}
insertAfter(target, targetNext,
append, append);
}
public void deletedChild(LinkedListTree parent, int index, LinkedListTree child) {
LinkedListToken start = child.getStartToken();
LinkedListToken stop = child.getStopToken();
LinkedListToken startPrev = start.getPrev();
LinkedListToken stopNext = stop.getNext();
if (startPrev != null) {
startPrev.setNext(stopNext);
} else if (stopNext != null) {
stopNext.setPrev(startPrev);
}
// just to save possible confusion, break links out from the
// removed token list too,
start.setPrev(null);
stop.setNext(null);
}
public void replacedChild(LinkedListTree tree, int index, LinkedListTree child, LinkedListTree oldChild) {
// link the new child's tokens in place of the old,
oldChild.getStartToken().getPrev().setNext(child.getStartToken());
oldChild.getStopToken().getNext().setPrev(child.getStopToken());
// just to save possible confusion, break links out from the
// removed token list too,
oldChild.getStartToken().setPrev(null);
oldChild.getStopToken().setNext(null);
}
}