// The Nova Project by Ken Beckett.
// Copyright (C) 2007-2012 Inevitable Software, all rights reserved.
// Released under the Common Development and Distribution License, CDDL-1.0: http://opensource.org/licenses/cddl1.php
using System.Collections.Generic;
using Nova.CodeDOM;
namespace Nova.Parsing
{
/// <summary>
/// The general type of a <see cref="Token"/>.
/// </summary>
public enum TokenType : byte { None, Identifier, Symbol, VerbatimString, String, Char, Numeric, Comment,
DocCommentStart, DocCommentTag, DocCommentSymbol, DocCommentString, CompilerDirective }
/// <summary>
/// Represents a discreet unit of text parsed from the input stream, along with location
/// and formatting information, and any trailing comments.
/// </summary>
public class Token : ParsedObject
{
#region /* FIELDS */
/// <summary>
/// The text of the <see cref="Token"/>.
/// </summary>
public string Text;
/// <summary>
/// The <see cref="TokenType"/> of the <see cref="Token"/>.
/// </summary>
public TokenType TokenType;
/// <summary>
/// True if the <see cref="Token"/> was escaped.
/// </summary>
public bool WasEscaped;
/// <summary>
/// True if inside a documentation comment.
/// </summary>
protected bool _inDocComment;
/// <summary>
/// The line number of the <see cref="Token"/> (1 to N).
/// </summary>
public int LineNumber;
/// <summary>
/// The column number of the <see cref="Token"/> (1 to N).
/// </summary>
public ushort ColumnNumber;
/// <summary>
/// The number of new lines preceeding the <see cref="Token"/>.
/// </summary>
public ushort NewLines;
/// <summary>
/// Any leading whitespace on the <see cref="Token"/>. Will be empty if none (not null).
/// </summary>
public string LeadingWhitespace;
/// <summary>
/// Any trailing comments on the <see cref="Token"/>.
/// </summary>
public List<CommentBase> TrailingComments;
#if DEBUG
/// <summary>
/// The parent <see cref="CodeUnit"/> (used in Debug mode to track lost comments).
/// </summary>
public CodeUnit CodeUnit;
#endif
#endregion
#region /* CONSTRUCTORS */
#if DEBUG
/// <summary>
/// Create a <see cref="Token"/>.
/// </summary>
public Token(string text, TokenType tokenType, bool wasEscaped, bool inDocComment, int lineNumber, int columnNumber, int newLines, string leadingWhitespace, CodeUnit codeUnit)
#else
public Token(string text, TokenType tokenType, bool wasEscaped, bool inDocComment, int lineNumber, int columnNumber, int newLines, string leadingWhitespace)
#endif
{
Text = text;
TokenType = tokenType;
WasEscaped = wasEscaped;
_inDocComment = inDocComment;
LineNumber = lineNumber;
ColumnNumber = (ushort)columnNumber;
NewLines = (ushort)newLines;
LeadingWhitespace = leadingWhitespace;
#if DEBUG
CodeUnit = codeUnit;
#endif
}
#if DEBUG
/// <summary>
/// Enable this finalizer to trace lost comments
/// </summary>
~Token()
{
if (TrailingComments != null && TrailingComments.Count > 0)
{
string error;
CommentBase comment = TrailingComments[0];
if (Text != null)
error = "Line# " + LineNumber + ": LOST COMMENTS on token '" + Text + "'";
else
error = "Line# " + comment.LineNumber + ": LOST COMMENTS";
error += ": \"" + comment.AsString().Split('\n')[0] + "\"";
CodeUnit.LogAndAttachMessage(error, MessageSeverity.Error, MessageSource.Parse);
}
}
#endif
#endregion
#region /* PROPERTIES */
/// <summary>
/// Get the non-verbatim version of the text (without the '@' prefix, if any).
/// </summary>
public string NonVerbatimText
{
get { return (Text[0] == '@' ? Text.Substring(1) : Text); }
}
/// <summary>
/// True if the <see cref="Token"/> is the first one on the current line.
/// </summary>
public bool IsFirstOnLine
{
get { return (NewLines > 0); }
}
/// <summary>
/// True if the <see cref="Token"/> is an identifier.
/// </summary>
public bool IsIdentifier
{
get { return (TokenType == TokenType.Identifier); }
}
/// <summary>
/// True if the <see cref="Token"/> is a symbol.
/// </summary>
public bool IsSymbol
{
get { return (TokenType == TokenType.Symbol); }
}
/// <summary>
/// True if the <see cref="Token"/> is numeric.
/// </summary>
public bool IsNumeric
{
get { return (TokenType == TokenType.Numeric); }
}
/// <summary>
/// True if the <see cref="Token"/> is a comment.
/// </summary>
public bool IsComment
{
get { return (TokenType == TokenType.Comment); }
}
/// <summary>
/// True if the <see cref="Token"/> is the start of a documentation comment.
/// </summary>
public bool IsDocCommentStart
{
get { return (TokenType == TokenType.DocCommentStart); }
}
/// <summary>
/// True if the <see cref="Token"/> is a documentation comment XML tag name.
/// </summary>
public bool IsDocCommentTag
{
get { return (TokenType == TokenType.DocCommentTag); }
}
/// <summary>
/// True if inside a documentation comment.
/// </summary>
public override bool InDocComment
{
get { return _inDocComment; }
}
/// <summary>
/// True if there are any trailing comments.
/// </summary>
public override bool HasTrailingComments
{
get { return (TrailingComments != null && TrailingComments.Count > 0); }
}
#endregion
#region /* METHODS */
/// <summary>
/// Return this <see cref="Token"/>.
/// </summary>
public override Token AsToken()
{
return this;
}
/// <summary>
/// Get this token as a string.
/// </summary>
public override string ToString()
{
return Text;
}
#endregion
}
}