blob: 9a3c6b9d9e0616b3cd49a99abdc50d7e54e80e62 [file] [log] [blame]
/*
* [The "BSD licence"]
* Copyright (c) 2005-2008 Terence Parr
* All rights reserved.
*
* Conversion to C#:
* Copyright (c) 2008-2009 Sam Harwell, Pixel Mine, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace Antlr.Runtime.Tree {
using System.Collections.Generic;
using Console = System.Console;
using IList = System.Collections.IList;
using InvalidOperationException = System.InvalidOperationException;
using StringBuilder = System.Text.StringBuilder;
/** <summary>A buffered stream of tree nodes. Nodes can be from a tree of ANY kind.</summary>
*
* This node stream sucks all nodes out of the tree specified in
* the constructor during construction and makes pointers into
* the tree using an array of Object pointers. The stream necessarily
* includes pointers to DOWN and UP and EOF nodes.
*
* This stream knows how to mark/release for backtracking.
*
* This stream is most suitable for tree interpreters that need to
* jump around a lot or for tree parsers requiring speed (at cost of memory).
* There is some duplicated functionality here with UnBufferedTreeNodeStream
* but just in bookkeeping, not tree walking etc...
*
* TARGET DEVELOPERS:
*
* This is the old CommonTreeNodeStream that buffered up entire node stream.
* No need to implement really as new CommonTreeNodeStream is much better
* and covers what we need.
*
* @see CommonTreeNodeStream
*/
public class BufferedTreeNodeStream : ITreeNodeStream, ITokenStreamInformation {
public const int DEFAULT_INITIAL_BUFFER_SIZE = 100;
public const int INITIAL_CALL_STACK_SIZE = 10;
protected sealed class StreamIterator : IEnumerator<object> {
BufferedTreeNodeStream _outer;
int _index;
public StreamIterator(BufferedTreeNodeStream outer) {
_outer = outer;
_index = -1;
}
#region IEnumerator<object> Members
public object Current {
get {
if (_index < _outer.nodes.Count)
return _outer.nodes[_index];
return _outer.eof;
}
}
#endregion
#region IDisposable Members
public void Dispose() {
}
#endregion
#region IEnumerator Members
public bool MoveNext() {
if (_index < _outer.nodes.Count)
_index++;
return _index < _outer.nodes.Count;
}
public void Reset() {
_index = -1;
}
#endregion
}
// all these navigation nodes are shared and hence they
// cannot contain any line/column info
protected object down;
protected object up;
protected object eof;
/** <summary>The complete mapping from stream index to tree node.
* This buffer includes pointers to DOWN, UP, and EOF nodes.
* It is built upon ctor invocation. The elements are type
* Object as we don't what the trees look like.</summary>
*
* Load upon first need of the buffer so we can set token types
* of interest for reverseIndexing. Slows us down a wee bit to
* do all of the if p==-1 testing everywhere though.
*/
protected IList nodes;
/** <summary>Pull nodes from which tree?</summary> */
protected object root;
/** <summary>IF this tree (root) was created from a token stream, track it.</summary> */
protected ITokenStream tokens;
/** <summary>What tree adaptor was used to build these trees</summary> */
ITreeAdaptor adaptor;
/** <summary>Reuse same DOWN, UP navigation nodes unless this is true</summary> */
bool uniqueNavigationNodes = false;
/** <summary>The index into the nodes list of the current node (next node
* to consume). If -1, nodes array not filled yet.</summary>
*/
protected int p = -1;
/** <summary>Track the last mark() call result value for use in rewind().</summary> */
protected int lastMarker;
/** <summary>Stack of indexes used for push/pop calls</summary> */
protected Stack<int> calls;
public BufferedTreeNodeStream(object tree)
: this(new CommonTreeAdaptor(), tree) {
}
public BufferedTreeNodeStream(ITreeAdaptor adaptor, object tree)
: this(adaptor, tree, DEFAULT_INITIAL_BUFFER_SIZE) {
}
public BufferedTreeNodeStream(ITreeAdaptor adaptor, object tree, int initialBufferSize) {
this.root = tree;
this.adaptor = adaptor;
nodes = new List<object>(initialBufferSize);
down = adaptor.Create(TokenTypes.Down, "DOWN");
up = adaptor.Create(TokenTypes.Up, "UP");
eof = adaptor.Create(TokenTypes.EndOfFile, "EOF");
}
#region Properties
public virtual int Count {
get {
if (p == -1) {
throw new InvalidOperationException("Cannot determine the Count before the buffer is filled.");
}
return nodes.Count;
}
}
public virtual object TreeSource {
get {
return root;
}
}
public virtual string SourceName {
get {
return TokenStream.SourceName;
}
}
public virtual ITokenStream TokenStream {
get {
return tokens;
}
set {
tokens = value;
}
}
public virtual ITreeAdaptor TreeAdaptor {
get {
return adaptor;
}
set {
adaptor = value;
}
}
public virtual bool UniqueNavigationNodes {
get {
return uniqueNavigationNodes;
}
set {
uniqueNavigationNodes = value;
}
}
public virtual IToken LastToken {
get {
return TreeAdaptor.GetToken(LB(1));
}
}
public virtual IToken LastRealToken {
get {
int i = 0;
IToken token;
do {
i++;
token = TreeAdaptor.GetToken(LB(i));
} while (token != null && token.Line <= 0);
return token;
}
}
public virtual int MaxLookBehind {
get {
return int.MaxValue;
}
}
#endregion
/** Walk tree with depth-first-search and fill nodes buffer.
* Don't do DOWN, UP nodes if its a list (t is isNil).
*/
protected virtual void FillBuffer() {
FillBuffer(root);
//Console.Out.WriteLine( "revIndex=" + tokenTypeToStreamIndexesMap );
p = 0; // buffer of nodes intialized now
}
public virtual void FillBuffer(object t) {
bool nil = adaptor.IsNil(t);
if (!nil) {
nodes.Add(t); // add this node
}
// add DOWN node if t has children
int n = adaptor.GetChildCount(t);
if (!nil && n > 0) {
AddNavigationNode(TokenTypes.Down);
}
// and now add all its children
for (int c = 0; c < n; c++) {
object child = adaptor.GetChild(t, c);
FillBuffer(child);
}
// add UP node if t has children
if (!nil && n > 0) {
AddNavigationNode(TokenTypes.Up);
}
}
/** What is the stream index for node? 0..n-1
* Return -1 if node not found.
*/
protected virtual int GetNodeIndex(object node) {
if (p == -1) {
FillBuffer();
}
for (int i = 0; i < nodes.Count; i++) {
object t = nodes[i];
if (t == node) {
return i;
}
}
return -1;
}
/** As we flatten the tree, we use UP, DOWN nodes to represent
* the tree structure. When debugging we need unique nodes
* so instantiate new ones when uniqueNavigationNodes is true.
*/
protected virtual void AddNavigationNode(int ttype) {
object navNode = null;
if (ttype == TokenTypes.Down) {
if (UniqueNavigationNodes) {
navNode = adaptor.Create(TokenTypes.Down, "DOWN");
} else {
navNode = down;
}
} else {
if (UniqueNavigationNodes) {
navNode = adaptor.Create(TokenTypes.Up, "UP");
} else {
navNode = up;
}
}
nodes.Add(navNode);
}
public virtual object this[int i] {
get {
if (p == -1) {
throw new InvalidOperationException("Cannot get the node at index i before the buffer is filled.");
}
return nodes[i];
}
}
public virtual object LT(int k) {
if (p == -1) {
FillBuffer();
}
if (k == 0) {
return null;
}
if (k < 0) {
return LB(-k);
}
//System.out.print("LT(p="+p+","+k+")=");
if ((p + k - 1) >= nodes.Count) {
return eof;
}
return nodes[p + k - 1];
}
public virtual object GetCurrentSymbol() {
return LT(1);
}
#if false
public virtual object getLastTreeNode()
{
int i = Index;
if ( i >= size() )
{
i--; // if at EOF, have to start one back
}
Console.Out.WriteLine( "start last node: " + i + " size==" + nodes.Count );
while ( i >= 0 &&
( adaptor.getType( this[i] ) == TokenTypes.EOF ||
adaptor.getType( this[i] ) == TokenTypes.UP ||
adaptor.getType( this[i] ) == TokenTypes.DOWN ) )
{
i--;
}
Console.Out.WriteLine( "stop at node: " + i + " " + nodes[i] );
return nodes[i];
}
#endif
/** <summary>Look backwards k nodes</summary> */
protected virtual object LB(int k) {
if (k == 0) {
return null;
}
if ((p - k) < 0) {
return null;
}
return nodes[p - k];
}
public virtual void Consume() {
if (p == -1) {
FillBuffer();
}
p++;
}
public virtual int LA(int i) {
return adaptor.GetType(LT(i));
}
public virtual int Mark() {
if (p == -1) {
FillBuffer();
}
lastMarker = Index;
return lastMarker;
}
public virtual void Release(int marker) {
// no resources to release
}
public virtual int Index {
get {
return p;
}
}
public virtual void Rewind(int marker) {
Seek(marker);
}
public virtual void Rewind() {
Seek(lastMarker);
}
public virtual void Seek(int index) {
if (p == -1) {
FillBuffer();
}
p = index;
}
/** <summary>
* Make stream jump to a new location, saving old location.
* Switch back with pop().
* </summary>
*/
public virtual void Push(int index) {
if (calls == null) {
calls = new Stack<int>();
}
calls.Push(p); // save current index
Seek(index);
}
/** <summary>
* Seek back to previous index saved during last push() call.
* Return top of stack (return index).
* </summary>
*/
public virtual int Pop() {
int ret = calls.Pop();
Seek(ret);
return ret;
}
public virtual void Reset() {
p = 0;
lastMarker = 0;
if (calls != null) {
calls.Clear();
}
}
public virtual IEnumerator<object> Iterator() {
if (p == -1) {
FillBuffer();
}
return new StreamIterator(this);
}
// TREE REWRITE INTERFACE
public virtual void ReplaceChildren(object parent, int startChildIndex, int stopChildIndex, object t) {
if (parent != null) {
adaptor.ReplaceChildren(parent, startChildIndex, stopChildIndex, t);
}
}
/** <summary>Used for testing, just return the token type stream</summary> */
public virtual string ToTokenTypeString() {
if (p == -1) {
FillBuffer();
}
StringBuilder buf = new StringBuilder();
for (int i = 0; i < nodes.Count; i++) {
object t = nodes[i];
buf.Append(" ");
buf.Append(adaptor.GetType(t));
}
return buf.ToString();
}
/** <summary>Debugging</summary> */
public virtual string ToTokenString(int start, int stop) {
if (p == -1) {
FillBuffer();
}
StringBuilder buf = new StringBuilder();
for (int i = start; i < nodes.Count && i <= stop; i++) {
object t = nodes[i];
buf.Append(" ");
buf.Append(adaptor.GetToken(t));
}
return buf.ToString();
}
public virtual string ToString(object start, object stop) {
Console.Out.WriteLine("toString");
if (start == null || stop == null) {
return null;
}
if (p == -1) {
throw new InvalidOperationException("Buffer is not yet filled.");
}
//Console.Out.WriteLine( "stop: " + stop );
if (start is CommonTree)
Console.Out.Write("toString: " + ((CommonTree)start).Token + ", ");
else
Console.Out.WriteLine(start);
if (stop is CommonTree)
Console.Out.WriteLine(((CommonTree)stop).Token);
else
Console.Out.WriteLine(stop);
// if we have the token stream, use that to dump text in order
if (tokens != null) {
int beginTokenIndex = adaptor.GetTokenStartIndex(start);
int endTokenIndex = adaptor.GetTokenStopIndex(stop);
// if it's a tree, use start/stop index from start node
// else use token range from start/stop nodes
if (adaptor.GetType(stop) == TokenTypes.Up) {
endTokenIndex = adaptor.GetTokenStopIndex(start);
} else if (adaptor.GetType(stop) == TokenTypes.EndOfFile) {
endTokenIndex = Count - 2; // don't use EOF
}
return tokens.ToString(beginTokenIndex, endTokenIndex);
}
// walk nodes looking for start
object t = null;
int i = 0;
for (; i < nodes.Count; i++) {
t = nodes[i];
if (t == start) {
break;
}
}
// now walk until we see stop, filling string buffer with text
StringBuilder buf = new StringBuilder();
t = nodes[i];
while (t != stop) {
string text = adaptor.GetText(t);
if (text == null) {
text = " " + adaptor.GetType(t).ToString();
}
buf.Append(text);
i++;
t = nodes[i];
}
// include stop node too
string text2 = adaptor.GetText(stop);
if (text2 == null) {
text2 = " " + adaptor.GetType(stop).ToString();
}
buf.Append(text2);
return buf.ToString();
}
}
}