/*       Copyright (c) Eric Ledoux.  All rights reserved.       */
/* See http://www.dwell.net/terms for code sharing information. */

// SourceFile.cs
//
// Implements class SourceFile and related types.
//

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using DwellNet.CodeDoc;
using CodeDocApi.Properties;

namespace DwellNet.CodeDoc
{

SourceFile Class

Represents a source code file in a programming language such as C#.

public abstract class SourceFile : TokenList
{
    //////////////////////////////////////////////////////////////////////////
    // Internal Constants
    //

    
SourceFile.LBrace Field

Left brace (to make brace matching work better in text editor).

    internal const char LBrace = '{';

    
SourceFile.RBrace Field

Right brace (to make brace matching work better in text editor).

    internal const char RBrace = '}';

    
SourceFile.LParen Field

Left parenthesis (to make parenthesis matching work better in a text editor).

    internal const char LParen = '(';

    
SourceFile.RParen Field

Right parenthesis (to make parenthesis matching work better in a text editor).

    internal const char RParen = ')';

    
SourceFile.LSquare Field

Left square bracket (to make square bracket matching work better in a text editor).

    internal const char LSquare = '[';

    
SourceFile.RSquare Field

Right square bracket (to make square bracket matching work better in a text editor).

    internal const char RSquare = ']';

    
SourceFile.LAngle Field

Left angle bracket (to make angle bracket matching work better in a text editor).

    internal const char LAngle = '<';

    
SourceFile.RAngle Field

Right angle bracket (to make angle bracket matching work better in a text editor).

    internal const char RAngle = '>';

    //////////////////////////////////////////////////////////////////////////
    // Private Fields
    //

    
SourceFile.s_whiteSpaceRegex Field

Matches one or more white space characters.

    readonly static Regex s_whiteSpaceRegex = new Regex(@"\s+");

    
SourceFile.m_warnings Field

Holds the value of the Warnings property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    List<ParsingException> m_warnings = new List<ParsingException>();

    
SourceFile.m_assemblyName Field

Holds the value of the AssemblyName property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    string m_assemblyName;

    
SourceFile.m_exceptionOnInvalidXmlComment Field

Holds the value of the ExceptionOnInvalidXmlComment property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    bool m_exceptionOnInvalidXmlComment = true;

    //////////////////////////////////////////////////////////////////////////
    // Internal Fields
    //

    
SourceFile.m_docSet Field

Holds the value of the DocumentationSet property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    internal DocumentationSet m_docSet;

    
SourceFile.m_sourceFileAbsolutePath Field

Holds the value of the SourceFileAbsolutePath property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    internal string m_sourceFileAbsolutePath;

    
SourceFile.m_sourceFileRelativePath Field

Holds the value of the SourceFileRelativePath property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    internal string m_sourceFileRelativePath;

    
SourceFile.m_topics Field

Holds the value of the Topics property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    internal List<Topic> m_topics = new List<Topic>(100);

    
SourceFile.m_sourceFileTopicId Field

Holds the value of the SourceFileTopicId property.

    [DebuggerBrowsable(DebuggerBrowsableState.Never)]
    int m_sourceFileTopicId;

    //////////////////////////////////////////////////////////////////////////
    // Public Properties
    //

    
SourceFile.DocumentationSet Property

Returns the documentation set that contains this source file.

    public DocumentationSet DocumentationSet
    {
        get
        {
            return m_docSet;
        }
    }

    
SourceFile.SourceFileAbsolutePath Property

Gets the full path to the source file.

Remarks

If the source file is provided as a stream rather than as a file in the file system, SourceFileAbsolutePath is an arbitrary label used to identify the file in error messages.

    public string SourceFileAbsolutePath
    {
        [DebuggerStepThrough]
        get
        {
            return m_sourceFileAbsolutePath;
        }
    }

    
SourceFile.SourceFileRelativePath Property

If the source file is specified by the application using a path to the file, this property gets the base name of the source file; for example, "Ghi.cs". If the application provided a directory tree containing this file (among others), then this property gets the path to this file relative to that directory tree; for example, "Abc\Def\Ghi.cs" (in the case where the application specified a directory tree containing sudirectory "Abc", which in turn contains subdirectory "Def", which in turn contains file "Ghi.cs").

Remarks

If the source file is provided as a stream rather than as a file in the file system, SourceFileRelativePath is null.

    public string SourceFileRelativePath
    {
        [DebuggerStepThrough]
        get
        {
            return m_sourceFileRelativePath;
        }
    }

    
SourceFile.CodeHtmlFileName Property

Returns the name of the HTML file that contains, or will contain, the formatted version of this source file.

Remarks

CodeHtmlFileName is based on SourceFileRelativePath with path separator characters changed to "!", and "!" characters changed to "!!". For example, if SourceFileRelativePath is "Foo\Bar.cs", CodeHtmlFileName is "Foo!Bar.cs.htm".

    public string CodeHtmlFileName
    {
        get
        {
            return SourceFileRelativePath.Replace("!", "!!")
                .Replace(@"\", "!").Replace("/", "!") + ".htm";
        }
    }

    
SourceFile.Topics Property

Gets the topics in this source file. Each topic corresponds to a valid XML comment.

    public ICollection<Topic> Topics
    {
        [DebuggerStepThrough]
        get
        {
            return new ReadOnlyCollection<Topic>(m_topics);
        }
    }

    
SourceFile.TopicsList Property

Gets Topics as a writable list.

    internal List<Topic> TopicsList
    {
        [DebuggerStepThrough]
        get
        {
            return m_topics;
        }
    }

    
SourceFile.SourceFileTopicId Property

Gets the integer identifier of this topic which represents the entire source file when viewed as formatted source code.

    public int SourceFileTopicId
    {
        [DebuggerStepThrough]
        get
        {
            return m_sourceFileTopicId;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_sourceFileTopicId = value;
        }
    }

    
SourceFile.Warnings Property

Gets the warnings encountered during the loading and parsing of this source file.

    public ICollection<ParsingException> Warnings
    {
        [DebuggerStepThrough]
        get
        {
            return new ReadOnlyCollection<ParsingException>(m_warnings);
        }
    }

    
SourceFile.AssemblyName Property

Gets the name of the assembly that contains the code compiled from this source files, or null if none is this information is not available.

    public string AssemblyName
    {
        [DebuggerStepThrough]
        get
        {
            return m_assemblyName;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_assemblyName = value;
        }
    }

    
SourceFile.ExceptionOnInvalidXmlComment Property

Gets or sets a value indicating whether an exception is thrown when an invalid XML comment is detected. The default value is true.

    public bool ExceptionOnInvalidXmlComment
    {
        [DebuggerStepThrough]
        get
        {
            return m_exceptionOnInvalidXmlComment;
        }
        [DebuggerStepThrough]
        internal set
        {
            m_exceptionOnInvalidXmlComment = value;
        }
    }

    //////////////////////////////////////////////////////////////////////////
    // Public Events
    //

    
SourceFile.InvalidXmlComment Event

Fired to indicate that an invalid XML comment was discovered.

    public event InvalidXmlCommentEventDelegate InvalidXmlComment;

#if false
    //////////////////////////////////////////////////////////////////////////
    // Public Methods
    //

    /// <summary>
    /// Generates code HTML corresponding to this source file.
    /// </summary>
    ///
    /// <param name="htmlPath">The path of the HTML output file to
    ///     generate.  This file is overwritten if it exists.</param>
    ///
    public abstract void GenerateCodeHtml(string htmlPath);
#endif

    //////////////////////////////////////////////////////////////////////////
    // Protected Methods
    //

    
SourceFile.AddXmlComment Method

Appends a TokenType.XmlComment token to the end of the linked list of tokens.

Parameters

token

The token to add.

Remarks

Any white space tokens that would precede the XML comment token are deleted, and their blanks are incorporated into the XML comment token.

    protected void AddXmlComment(Token token)
    {
        Debug.Assert(token.TokenType == TokenType.XmlComment);

        // delete all trailing whitespace tokens
        string space = null;
        while (true)
        {
            Token previousToken = TailToken.Previous;
            if (previousToken.TokenType == TokenType.WhiteSpace)
            {
                if (space == null)
                    space = previousToken.Text;
                else
                    space += previousToken.Text;
                previousToken.RemoveFromList();
            }
            else
                break;
        }

        // add the deleted white space (if any) to <token>
        if (space != null)
            token.Text = space + token.Text;

        // insert <token> into the linked list
        Append(token);
    }

    
SourceFile.Warning Method

Appends to m_warnings a warning message referring to the current source file and the line number of a given token.

Parameters

token

The token to get the line number of (to include in the warning message).

format

A formatting string for the message; for example, "unknown declaration". Do not include the word "warning" in this text.

args

Formatting arguments.

    internal void Warning(Token token, string format, params object[] args)
    {
        m_warnings.Add(new ParsingException(m_sourceFileAbsolutePath,
            token.GetLineNumber(), format, args));
    }

    
SourceFile.Expected Method

Constructs and returns a new ParsingException referring to the current source file and the line number of a given token. The exception indicates that something was expected but not found.

Parameters

token

The token to get the line number of (to include in the exception text).

format

A formatting string for the string indicating the thing that was expected; for example "class name".

args

Formatting arguments.

    protected ParsingException Expected(Token token, string format,
        params object[] args)
    {
        throw NewParsingException(token, Resources.Expected,
            String.Format(format, args));
    }

    
SourceFile.Unexpected Method

Constructs and returns a new ParsingException referring to the current source file and the line number of a given token. The exception indicates that something was unexpected.

Parameters

token

The token to get the line number of (to include in the exception text).

format

A formatting string for the string indicating the thing that was unexpected; for example "semicolon (;)".

args

Formatting arguments.

    protected ParsingException Unexpected(Token token, string format,
        params object[] args)
    {
        throw NewParsingException(token, Resources.Unexpected,
            String.Format(format, args));
    }

    
SourceFile.NewParsingException Method

Constructs and returns a new ParsingException referring to the current source file and the line number of a given token.

Parameters

token

The token to get the line number of (to include in the exception text).

format

A formatting string for an error message to include with the exception.

args

Formatting arguments for the error message.

    protected ParsingException NewParsingException(Token token,
        string format, params object[] args)
    {
        return new ParsingException(m_sourceFileAbsolutePath,
            token.GetLineNumber(), format, args);
    }

    
SourceFile.Join Method

If s1 is null, return s2. If s2 is null, return s1. If both are null, return null. If neither are null, return s1 concatenated with s2 with delimiter in between.

Parameters

s1

The first string.

delimiter

The delimiter to use if neither s1 nor s2 are null.

s2

The second string.

    protected static string Join(string s1, string delimiter,
        string s2)
    {
        if (s1 == null)
        {
            if (s2 == null)
                return null;
            else
                return s2;
        }
        else
        {
            if (s2 == null)
                return s1;
            else
                return s1 + delimiter + s2;
        }
    }

    
SourceFile.FindCommonPrefix Method

Returns common prefix string that's in common between two strings.

Parameters

s1

The first string.

s2

The second string.

Return Value

The longest string that's a prefix for both s1 and s2.

    protected static string FindCommonPrefix(string s1, string s2)
    {
        int cch = Math.Min(s1.Length, s2.Length);
        for (int ich = 0; ich < cch; ich++)
        {
            if (s1[ich] != s2[ich])
                return s1.Substring(0, ich);
        }
        return s1.Substring(0, cch);
    }

    
SourceFile.FireInvalidXmlComment Method

Fires an InvalidXmlComment event.

Parameters

exception

Information about the error.

    protected void FireInvalidXmlComment(ParsingException exception)
    {
        if (InvalidXmlComment != null)
            InvalidXmlComment(exception);
    }

    //////////////////////////////////////////////////////////////////////////
    // Internal Methods
    //

    
SourceFile.Load Method

Loads and parses the source file.

Parameters

initialSymbols

The initial set of defined conditional compilation symbols; for example, "DEBUG". Additional symbols may be defined using #define directives within the source file.

    internal abstract void Load(ICollection<string> initialSymbols);

    
SourceFile.Ellipsis Method

Truncates a string and adds "..." if the string exceeds a given length.

Parameters

value

The input string.

maxLength

The maximum length of value (after processing described in Remarks is performed) before it is truncated and an ellipsis "..." added.

Remarks

Also, newlines and tabs are replaced with spaces, adjacent spaces are collapsed into a single space, and leading and trailing white space is removed from value.

    static internal string Ellipsis(string value, int maxLength)
    {
        // perform processing described in Remarks
        value = s_whiteSpaceRegex.Replace(value, " ").Trim();
        if (value.Length > maxLength)
            return value.Substring(0, maxLength) + "...";
        else
            return value;
    }
}

InvalidXmlCommentEventDelegate Delegate

The type of an event handler for an event which is fired to indicate that an XML comment is is invalid.

Parameters

exception

Information about the error.

Remarks
public delegate void InvalidXmlCommentEventDelegate(ParsingException exception);

}