// *
// * Copyright (C) 2008 Roger Alsing : http://www.RogerAlsing.com
// *
// * This library is free software; you can redistribute it and/or modify it
// * under the terms of the GNU Lesser General Public License 2.1 or later, as
// * published by the Free Software Foundation. See the included license.txt
// * or http://www.gnu.org/copyleft/lesser.html for details.
// *
// *
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
namespace Alsing.SourceCode
{
///
/// spanDefinition class
///
///
/// The spanDefinition class represents a specific code/text element
/// such as a string , comment or the code itself.
///
/// a spanDefinition can contain keywords , operators , scopes and child spans.
///
///
/// For example , if we where to describe the syntax C#
/// we would have the following span:
///
/// Code span - the spanDefinition containing all the keywords and operators.
/// Singleline comment span - a spanDefinition that starts on // terminates at the end of a line.
/// Multiline comment span - a spanDefinition that starts on /* can span multiple rows and terminates on */.
/// String span - a spanDefinition that starts on " terminates on " or at the end of a line.
/// Char span - a spanDefinition that starts on ' terminates on ' or at the end of a line.
///
/// CHILD SPANS:
/// The code span would have all the other spans as childspans , since they can only appear inside the
/// code span . A string can for example never exist inside a comment in C#.
/// a spanDefinition can also have itself as a child span.
/// For example , the C# Code span can have itself as a childspan and use the scope patterns "{" and "}"
/// this way we can accomplish FOLDING since the parser will know where a new scope starts and ends.
///
/// SCOPES:
/// Scopes describe what patterns starts and what patterns end a specific spanDefinition.
/// For example , the C# Multiline Comment have the scope patterns /* and */
///
/// KEYWORDS:
/// A Keyword is a pattern that can only exist between separator chars.
/// For example the keyword "for" in c# is valid if it is contained in this string " for ("
/// but it is not valid if the containing string is " MyFormat "
///
/// OPERATORS:
/// Operators is the same thing as keywords but are valid even if there are no separator chars around it.
/// In most cases operators are only one or two chars such as ":" or "->"
/// operators in this context should not be mixed up with code operators such as "and" or "xor" in VB6
/// in this context they are keywords.
///
///
///
public class SpanDefinition
{
private readonly List tmpSimplePatterns = new List();
///
/// The background color of a span.
///
public Color BackColor = Color.Transparent;
///
/// A list containing which spanDefinitions are valid child spans in a specific span.
/// eg. strings and comments are child spans for a code span
///
public SpanDefinitionList childSpanDefinitions = new SpanDefinitionList();
public PatternCollection ComplexPatterns = new PatternCollection();
///
/// A list of keyword groups.
/// For example , one keyword group could be "keywords" and another could be "datatypes"
/// theese groups could have different color shemes assigned to them.
///
public PatternListList KeywordsList; //new PatternListList (this);
public Hashtable LookupTable = new Hashtable();
///
/// Gets or Sets if the spanDefinition can span multiple lines or if it should terminate at the end of a line.
///
public bool MultiLine;
///
/// The name of this span.
/// names are not required for span but can be a good help when interacting with the parser.
///
public string Name = "";
///
/// A list of operator groups.
/// Each operator group can contain its own operator patterns and its own color shemes.
///
public PatternListList OperatorsList; //new PatternListList (this);
///
/// A list of scopes , most span only contain one scope , eg a scope with start and end patterns "/*" and "*/"
/// for multiline comments, but in some cases you will need more scopes , eg. PHP uses both "<?" , "?>" and "<?PHP" , "PHP?>"
///
public ScopeList ScopePatterns;
///
/// The style to use when colorizing the content of a span,
/// meaning everything in this span except keywords , operators and childspans.
///
public TextStyle Style;
///
/// Gets or Sets if the parser should terminate any child span when it finds an end scope pattern for this span.
/// for example %> in asp terminates any asp span even if it appears inside an asp string.
///
public bool TerminateChildren;
///
/// Default spanDefinition constructor
///
public SpanDefinition(SyntaxDefinition parent) : this()
{
Parent = parent;
Parent.ChangeVersion();
}
public SpanDefinition()
{
KeywordsList = new PatternListList(this);
OperatorsList = new PatternListList(this);
Style = new TextStyle();
KeywordsList.Parent = this;
KeywordsList.IsKeyword = true;
OperatorsList.Parent = this;
OperatorsList.IsOperator = true;
ScopePatterns = new ScopeList(this);
}
#region PUBLIC PROPERTY PARENT
public SyntaxDefinition Parent { get; set; }
#endregion
///
/// Returns false if any color has been assigned to the backcolor property
///
public bool Transparent
{
get { return (BackColor.A == 0); }
}
public void ResetLookupTable()
{
LookupTable.Clear();
tmpSimplePatterns.Clear();
ComplexPatterns.Clear();
}
public void AddToLookupTable(Pattern pattern)
{
if (pattern.IsComplex)
{
ComplexPatterns.Add(pattern);
return;
}
tmpSimplePatterns.Add(pattern);
}
public void BuildLookupTable()
{
tmpSimplePatterns.Sort(new PatternComparer());
foreach (Pattern p in tmpSimplePatterns)
{
if (p.StringPattern.Length <= 2)
{
char c = p.StringPattern[0];
if (!p.Parent.CaseSensitive)
{
char c1 = char.ToLowerInvariant(c);
if (LookupTable[c1] == null)
LookupTable[c1] = new PatternCollection();
var patterns = LookupTable[c1] as PatternCollection;
if (patterns != null)
if (!patterns.Contains(p))
patterns.Add(p);
char c2 = char.ToUpper(c);
if (LookupTable[c2] == null)
LookupTable[c2] = new PatternCollection();
patterns = LookupTable[c2] as PatternCollection;
if (patterns != null)
if (!patterns.Contains(p))
patterns.Add(p);
}
else
{
if (LookupTable[c] == null)
LookupTable[c] = new PatternCollection();
var patterns = LookupTable[c] as PatternCollection;
if (patterns != null)
if (!patterns.Contains(p))
patterns.Add(p);
}
}
else
{
string c = p.StringPattern.Substring(0, 3).ToLowerInvariant();
if (LookupTable[c] == null)
LookupTable[c] = new PatternCollection();
var patterns = LookupTable[c] as PatternCollection;
if (patterns != null)
if (!patterns.Contains(p))
patterns.Add(p);
}
}
}
}
public class PatternComparer : IComparer
{
public int Compare(Pattern x, Pattern y)
{
return y.StringPattern.Length.CompareTo(x.StringPattern.Length);
}
}
}