blob: ea263b9c8090b37cec315b6c5666db4e221348e9 [file]
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
using System;
using System.Collections.Generic;
using Antlr4.Runtime;
using Antlr4.Runtime.Sharpen;
namespace Antlr4.Runtime
{
/// <summary>
/// Provides an implementation of
/// <see cref="ITokenSource"/>
/// as a wrapper around a list
/// of
/// <see cref="IToken"/>
/// objects.
/// <p>If the final token in the list is an
/// <see cref="TokenConstants.EOF"/>
/// token, it will be used
/// as the EOF token for every call to
/// <see cref="NextToken()"/>
/// after the end of the
/// list is reached. Otherwise, an EOF token will be created.</p>
/// </summary>
public class ListTokenSource : ITokenSource
{
/// <summary>
/// The wrapped collection of
/// <see cref="IToken"/>
/// objects to return.
/// </summary>
protected internal readonly IList<IToken> tokens;
/// <summary>The name of the input source.</summary>
/// <remarks>
/// The name of the input source. If this value is
/// <see langword="null"/>
/// , a call to
/// <see cref="SourceName()"/>
/// should return the source name used to create the
/// the next token in
/// <see cref="tokens"/>
/// (or the previous token if the end of
/// the input has been reached).
/// </remarks>
private readonly string sourceName;
/// <summary>
/// The index into
/// <see cref="tokens"/>
/// of token to return by the next call to
/// <see cref="NextToken()"/>
/// . The end of the input is indicated by this value
/// being greater than or equal to the number of items in
/// <see cref="tokens"/>
/// .
/// </summary>
protected internal int i;
/// <summary>This field caches the EOF token for the token source.</summary>
/// <remarks>This field caches the EOF token for the token source.</remarks>
protected internal IToken eofToken;
/// <summary>
/// This is the backing field for the <see cref="TokenFactory"/> property.
/// </summary>
private ITokenFactory _factory = CommonTokenFactory.Default;
/// <summary>
/// Constructs a new
/// <see cref="ListTokenSource"/>
/// instance from the specified
/// collection of
/// <see cref="IToken"/>
/// objects.
/// </summary>
/// <param name="tokens">
/// The collection of
/// <see cref="IToken"/>
/// objects to provide as a
/// <see cref="ITokenSource"/>
/// .
/// </param>
/// <exception>
/// NullPointerException
/// if
/// <paramref name="tokens"/>
/// is
/// <see langword="null"/>
/// </exception>
public ListTokenSource(IList<IToken> tokens)
: this(tokens, null)
{
}
/// <summary>
/// Constructs a new
/// <see cref="ListTokenSource"/>
/// instance from the specified
/// collection of
/// <see cref="IToken"/>
/// objects and source name.
/// </summary>
/// <param name="tokens">
/// The collection of
/// <see cref="IToken"/>
/// objects to provide as a
/// <see cref="ITokenSource"/>
/// .
/// </param>
/// <param name="sourceName">
/// The name of the
/// <see cref="ITokenSource"/>
/// . If this value is
/// <see langword="null"/>
/// ,
/// <see cref="SourceName()"/>
/// will attempt to infer the name from
/// the next
/// <see cref="IToken"/>
/// (or the previous token if the end of the input has
/// been reached).
/// </param>
/// <exception>
/// NullPointerException
/// if
/// <paramref name="tokens"/>
/// is
/// <see langword="null"/>
/// </exception>
public ListTokenSource(IList<IToken> tokens, string sourceName)
{
if (tokens == null)
{
throw new ArgumentNullException("tokens cannot be null");
}
this.tokens = tokens;
this.sourceName = sourceName;
}
/// <summary><inheritDoc/></summary>
public virtual int Column
{
get
{
if (i < tokens.Count)
{
return tokens[i].Column;
}
else
{
if (eofToken != null)
{
return eofToken.Column;
}
else
{
if (tokens.Count > 0)
{
// have to calculate the result from the line/column of the previous
// token, along with the text of the token.
IToken lastToken = tokens[tokens.Count - 1];
string tokenText = lastToken.Text;
if (tokenText != null)
{
int lastNewLine = tokenText.LastIndexOf('\n');
if (lastNewLine >= 0)
{
return tokenText.Length - lastNewLine - 1;
}
}
return lastToken.Column + lastToken.StopIndex - lastToken.StartIndex + 1;
}
}
}
// only reach this if tokens is empty, meaning EOF occurs at the first
// position in the input
return 0;
}
}
/// <summary><inheritDoc/></summary>
public virtual IToken NextToken()
{
if (i >= tokens.Count)
{
if (eofToken == null)
{
int start = -1;
if (tokens.Count > 0)
{
int previousStop = tokens[tokens.Count - 1].StopIndex;
if (previousStop != -1)
{
start = previousStop + 1;
}
}
int stop = Math.Max(-1, start - 1);
eofToken = _factory.Create(Tuple.Create((ITokenSource)this, InputStream), TokenConstants.EOF, "EOF", TokenConstants.DefaultChannel, start, stop, Line, Column);
}
return eofToken;
}
IToken t = tokens[i];
if (i == tokens.Count - 1 && t.Type == TokenConstants.EOF)
{
eofToken = t;
}
i++;
return t;
}
/// <summary><inheritDoc/></summary>
public virtual int Line
{
get
{
if (i < tokens.Count)
{
return tokens[i].Line;
}
else
{
if (eofToken != null)
{
return eofToken.Line;
}
else
{
if (tokens.Count > 0)
{
// have to calculate the result from the line/column of the previous
// token, along with the text of the token.
IToken lastToken = tokens[tokens.Count - 1];
int line = lastToken.Line;
string tokenText = lastToken.Text;
if (tokenText != null)
{
for (int j = 0; j < tokenText.Length; j++)
{
if (tokenText[j] == '\n')
{
line++;
}
}
}
// if no text is available, assume the token did not contain any newline characters.
return line;
}
}
}
// only reach this if tokens is empty, meaning EOF occurs at the first
// position in the input
return 1;
}
}
/// <summary><inheritDoc/></summary>
public virtual ICharStream InputStream
{
get
{
if (i < tokens.Count)
{
return tokens[i].InputStream;
}
else
{
if (eofToken != null)
{
return eofToken.InputStream;
}
else
{
if (tokens.Count > 0)
{
return tokens[tokens.Count - 1].InputStream;
}
}
}
// no input stream information is available
return null;
}
}
/// <summary><inheritDoc/></summary>
public virtual string SourceName
{
get
{
if (sourceName != null)
{
return sourceName;
}
ICharStream inputStream = InputStream;
if (inputStream != null)
{
return inputStream.SourceName;
}
return "List";
}
}
/// <summary><inheritDoc/></summary>
/// <summary><inheritDoc/></summary>
public virtual ITokenFactory TokenFactory
{
get
{
return _factory;
}
set
{
ITokenFactory factory = value;
this._factory = factory;
}
}
}
}