/**
* This file Copyright (c) 2005-2008 Aptana, Inc. This program is
* dual-licensed under both the Aptana Public License and the GNU General
* Public license. You may elect to use one or the other of these licenses.
*
* This program is distributed in the hope that it will be useful, but
* AS-IS and WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, TITLE, or
* NONINFRINGEMENT. Redistribution, except as permitted by whichever of
* the GPL or APL you select, is prohibited.
*
* 1. For the GPL license (GPL), you can redistribute and/or modify this
* program under the terms of the GNU General Public License,
* Version 3, as published by the Free Software Foundation. You should
* have received a copy of the GNU General Public License, Version 3 along
* with this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Aptana provides a special exception to allow redistribution of this file
* with certain other free and open source software ("FOSS") code and certain additional terms
* pursuant to Section 7 of the GPL. You may view the exception and these
* terms on the web at http://www.aptana.com/legal/gpl/.
*
* 2. For the Aptana Public License (APL), this program and the
* accompanying materials are made available under the terms of the APL
* v1.0 which accompanies this distribution, and is available at
* http://www.aptana.com/legal/apl/.
*
* You may view the GPL, Aptana's exception and additional terms, and the
* APL in the file titled license.html at the root of the corresponding
* plugin containing this source file.
*
* Any modifications to this file must keep this entire header intact.
*/
package com.aptana.ide.parsing;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import com.aptana.ide.lexer.IRange;
import com.aptana.ide.lexer.Offset;
/**
* @author Kevin Lindsey
*/
public class ErrorList
{
private List<IErrorMessage> _errors;
/**
* Create a new error list
*/
public ErrorList()
{
this._errors = new ArrayList<IErrorMessage>();
}
/**
* Get the error node at the specified index
*
* @param index
* The index of the node to retrieve from this list
* @return Returns the node at the specified index
*/
public IErrorMessage get(int index)
{
return this._errors.get(index);
}
/**
* Return this list of errors as an IErrorMessage array
*
* @return Returns an array of the error nodes in this collection
*/
public IErrorMessage[] getErrors()
{
return this._errors.toArray(new IErrorMessage[0]);
}
/**
* Return the size of this list
*
* @return Returns the size of this list
*/
public int size()
{
return this._errors.size();
}
/**
* Temporary for testing only
*/
public void sanityCheck()
{
// int size = this._errors.size();
//
// for (int i = 0; i < size; i++)
// {
// IErrorMessage error = this.get(i);
//
// if (error.size() == 0)
// {
// throw new IllegalStateException("empty error node in error list");
// }
//
// // make sure this doesn't overlap with the following lexemes
// for (int j = i + 1; j < size; j++)
// {
// IErrorMessage test = this.get(j);
//
// if (error.isOverlapping(test))
// {
// throw new IllegalStateException("An error list cannot contain overlapping error nodes");
// }
// }
//
// error.sanityCheck();
// }
}
/**
* Add an error to this error list
*
* @param error
* The error to add to this list
*/
public void add(IErrorMessage error)
{
if (error == null)
{
throw new IllegalArgumentException(Messages.ErrorList_CannotAddNullErrorNode);
}
// if (error.isAtEOF())
// {
// throw new IllegalArgumentException("Cannot add an EOF error node to an error list");
// }
int insertIndex = Collections.binarySearch(this._errors, error);
if (insertIndex >= 0)
{
throw new IllegalArgumentException(Messages.ErrorList_ListAlreadyContainsErrorInSameRange);
}
// find insertion point
insertIndex = -(insertIndex + 1);
// insert to list
this._errors.add(insertIndex, error);
// set error node's owner
error.setOwningList(this);
}
/**
* Clear all errors from this list
*/
public void clear()
{
while (this._errors.size() > 0)
{
// This will clear all lexemes in the referenced IErrorMessage and as a side-effect, the error node will be
// deleted from this collection
this.get(0).clear();
}
}
/**
* Determine the index of this
*
* @param offset
* The offset that must be contained by an error in this list
* @return Returns the index of the error that contains the specified index. -1 is returned if the offset is not
* contained by any of the errors in this list
*/
public int indexOf(int offset)
{
return Collections.binarySearch(this._errors, new Offset(offset));
}
/**
* Remove the specified error node
*
* @param error
* The error to remove
*/
public void remove(IErrorMessage error)
{
int index = this._errors.indexOf(error);
if (0 <= index && index < this._errors.size() && this.get(index) == error)
{
// remove node
this._errors.remove(index);
// clear out reference to parent
error.setOwningList(null);
}
else
{
throw new IllegalStateException(Messages.ErrorList_ListDoesNotContainErrorBeingDeleted);
}
}
/**
* Remove all errors in the specified range
*
* @param range
* The source offset range to remove from this list
*/
public void remove(IRange range)
{
this.remove(range.getStartingOffset(), range.getEndingOffset());
}
/**
* Remove all errors in the specified offset range
*
* @param startingOffset
* The starting offset to remove
* @param endingOffset
* The ending offset to remove
*/
public void remove(int startingOffset, int endingOffset)
{
int startingIndex = this.indexOf(startingOffset);
int endingIndex = this.indexOf(endingOffset);
if (startingIndex < 0)
{
startingIndex = -(startingIndex + 1);
}
if (endingIndex < 0)
{
endingIndex = -(endingIndex + 1);
}
else
{
endingIndex++;
}
int count = endingIndex - startingIndex;
while (count > 0)
{
// This will end up calling remove(IErrorMessage) above which will to the actual delete. We need to call
// clear
// to null out the lexeme parent nodes
this.get(startingIndex).clear();
count--;
}
}
}