#region Copyright 2001-2003 Jean-Claude Manoli [jc@manoli.net]
/*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the author(s) be held liable for any damages arising from
* the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not
* be misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
#endregion
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace CodeFormatter{
/// <summary>
/// Provides a base class for formatting most programming languages.
/// </summary>
public abstract class CodeFormat : SourceFormat
{
/// <summary>
/// Must be overridden to provide a list of keywords defined in
/// each language.
/// </summary>
/// <remarks>
/// Keywords must be separated with spaces.
/// </remarks>
protected abstract string Keywords
{
get;
}
/// <summary>
/// Can be overridden to provide a list of preprocessors defined in
/// each language.
/// </summary>
/// <remarks>
/// Preprocessors must be separated with spaces.
/// </remarks>
protected virtual string Preprocessors
{
get { return ""; }
}
/// <summary>
/// Must be overridden to provide a regular expression string
/// to match strings literals.
/// </summary>
protected abstract string StringRegEx
{
get;
}
/// <summary>
/// Must be overridden to provide a regular expression string
/// to match comments.
/// </summary>
protected abstract string CommentRegEx
{
get;
}
/// <summary>
/// Determines if the language is case sensitive.
/// </summary>
/// <value><b>true</b> if the language is case sensitive, <b>false</b>
/// otherwise. The default is true.</value>
/// <remarks>
/// A case-insensitive language formatter must override this
/// property to return false.
/// </remarks>
public virtual bool CaseSensitive
{
get { return true; }
}
/// <summary/>
protected CodeFormat()
{
//generate the keyword and preprocessor regexes from the keyword lists
Regex r;
r = new Regex(@"\w+|-\w+|#\w+|@@\w+|#(?:\\(?:s|w)(?:\*|\+)?\w+)+|@\\w\*+");
string regKeyword = r.Replace(Keywords, @"(?<=^|\W)$0(?=\W)");
string regPreproc = r.Replace(Preprocessors, @"(?<=^|\s)$0(?=\s|$)");
r = new Regex(@" +");
regKeyword = r.Replace(regKeyword, @"|");
regPreproc = r.Replace(regPreproc, @"|");
if (regPreproc.Length == 0)
{
regPreproc = "(?!.*)_{37}(?<!.*)"; //use something quite impossible...
}
//build a master regex with capturing groups
StringBuilder regAll = new StringBuilder();
regAll.Append("(");
regAll.Append(CommentRegEx);
regAll.Append(")|(");
regAll.Append(StringRegEx);
if (regPreproc.Length > 0)
{
regAll.Append(")|(");
regAll.Append(regPreproc);
}
regAll.Append(")|(");
regAll.Append(regKeyword);
regAll.Append(")");
RegexOptions caseInsensitive = CaseSensitive ? 0 : RegexOptions.IgnoreCase;
CodeRegex = new Regex(regAll.ToString(), RegexOptions.Singleline | caseInsensitive);
}
/// <summary>
/// Called to evaluate the HTML fragment corresponding to each
/// matching token in the code.
/// </summary>
/// <param name="match">The <see cref="Match"/> resulting from a
/// single regular expression match.</param>
/// <returns>A string containing the HTML code fragment.</returns>
protected override string MatchEval(Match match)
{
if(match.Groups[1].Success) //comment
{
StringReader reader = new StringReader(match.ToString());
string line;
StringBuilder sb = new StringBuilder();
while ((line = reader.ReadLine()) != null)
{
if(sb.Length > 0)
{
sb.Append("\n");
}
sb.Append("<span class=\"rem\">");
sb.Append(line);
sb.Append("</span>");
}
return sb.ToString();
}
if(match.Groups[2].Success) //string literal
{
return "<span class=\"str\">" + match.ToString() + "</span>";
}
if(match.Groups[3].Success) //preprocessor keyword
{
return "<span class=\"preproc\">" + match.ToString() + "</span>";
}
if(match.Groups[4].Success) //keyword
{
return "<span class=\"kwrd\">" + match.ToString() + "</span>";
}
System.Diagnostics.Debug.Assert(false, "None of the above!");
return ""; //none of the above
}
}
}
|