Add better infrastructure for the parsers

This commit is contained in:
Alexandre Mutel
2016-02-28 21:05:40 +09:00
parent 305901e9ff
commit 72cdb18fc4
10 changed files with 71 additions and 19 deletions

View File

@@ -2,14 +2,12 @@ using Textamina.Markdig.Syntax;
namespace Textamina.Markdig.Parsers
{
public abstract class BlockParser : IBlockParser
public abstract class BlockParser : ParserBase, IBlockParser
{
protected BlockParser()
{
}
public char[] OpeningCharacters { get; protected set; }
public bool HasOpeningCharacter(char c)
{
if (OpeningCharacters != null)

View File

@@ -0,0 +1,7 @@
namespace Textamina.Markdig.Parsers
{
public class BlockParserList : ParserList<BlockParser>
{
}
}

View File

@@ -8,10 +8,9 @@ namespace Textamina.Markdig.Parsers
{
public class BlockParserState
{
private readonly ParserList<BlockParser> blockParsers;
private int currentStackIndex;
public BlockParserState(StringBuilderCache stringBuilders, Document root, ParserList<BlockParser> parsers)
public BlockParserState(StringBuilderCache stringBuilders, Document root, BlockParserList parsers)
{
if (stringBuilders == null) throw new ArgumentNullException(nameof(stringBuilders));
if (root == null) throw new ArgumentNullException(nameof(root));
@@ -21,13 +20,15 @@ namespace Textamina.Markdig.Parsers
NewBlocks = new Stack<Block>();
root.IsOpen = true;
Stack = new List<Block> {root};
blockParsers = parsers;
Parsers = parsers;
}
public List<Block> Stack { get; }
public Stack<Block> NewBlocks { get; }
public BlockParserList Parsers { get; }
public ContainerBlock CurrentContainer { get; private set; }
public Block LastBlock { get; private set; }
@@ -412,8 +413,8 @@ namespace Textamina.Markdig.Parsers
// Eat indent spaces before checking the character
ParseIndent();
var parsers = blockParsers.GetParsersForOpeningCharacter(CurrentChar);
var globalParsers = blockParsers.GlobalParsers;
var parsers = Parsers.GetParsersForOpeningCharacter(CurrentChar);
var globalParsers = Parsers.GlobalParsers;
if (parsers != null)
{

View File

@@ -5,6 +5,8 @@ namespace Textamina.Markdig.Parsers
public interface ICharacterParser
{
char[] OpeningCharacters { get; }
int Index { get; }
}
public interface IBlockParser : ICharacterParser

View File

@@ -2,12 +2,18 @@ using Textamina.Markdig.Syntax;
namespace Textamina.Markdig.Parsers
{
public abstract class InlineParser : ICharacterParser
public class ParserBase : ICharacterParser
{
public char[] OpeningCharacters { get; protected set; }
public int Index { get; internal set; }
}
public abstract class InlineParser : ParserBase
{
public delegate void CloseBlockDelegate(InlineParserState state);
public char[] OpeningCharacters { get; protected set; }
public abstract bool Match(InlineParserState state, ref StringSlice slice);
public CloseBlockDelegate OnCloseBlock { get; set; }

View File

@@ -0,0 +1,29 @@
using System.Collections.Generic;
namespace Textamina.Markdig.Parsers
{
public class InlineParserList : ParserList<InlineParser>
{
public InlineParserList()
{
}
public InlineParser[] ClosingParsers { get; private set; }
public override void Initialize()
{
base.Initialize();
var closingParsers = new InlineParserList();
foreach (var parser in this)
{
if (parser.OnCloseBlock != null)
{
closingParsers.Add(parser);
}
}
ClosingParsers = closingParsers.ToArray();
}
}
}

View File

@@ -10,7 +10,7 @@ namespace Textamina.Markdig.Parsers
{
public class InlineParserState
{
public InlineParserState(StringBuilderCache stringBuilders, Document document, ParserList<InlineParser> parsers)
public InlineParserState(StringBuilderCache stringBuilders, Document document, InlineParserList parsers)
{
if (stringBuilders == null) throw new ArgumentNullException(nameof(stringBuilders));
if (document == null) throw new ArgumentNullException(nameof(document));
@@ -30,7 +30,7 @@ namespace Textamina.Markdig.Parsers
public readonly List<Inline> InlinesToClose;
public readonly ParserList<InlineParser> Parsers;
public readonly InlineParserList Parsers;
public readonly Document Document;

View File

@@ -15,7 +15,7 @@ namespace Textamina.Markdig.Parsers
private readonly BlockParserState blockParserState;
private readonly StringBuilderCache stringBuilderCache;
private readonly InlineParserState inlineState;
private readonly ParserList<InlineParser> inlineParsers;
private readonly InlineParserList inlineParsers;
public MarkdownParser(TextReader reader)
{
@@ -24,7 +24,7 @@ namespace Textamina.Markdig.Parsers
stringBuilderCache = new StringBuilderCache();
// TODO: Make this configurable outside here
var blockParsers = new ParserList<BlockParser>()
var blockParsers = new BlockParserList()
{
new ThematicBreakParser(),
new HeadingBlockParser(),
@@ -38,7 +38,7 @@ namespace Textamina.Markdig.Parsers
};
blockParsers.Initialize();
inlineParsers = new ParserList<InlineParser>()
inlineParsers = new InlineParserList()
{
new HtmlEntityParser(),
new LinkInlineParser(),

View File

@@ -6,7 +6,7 @@ using Textamina.Markdig.Helpers;
namespace Textamina.Markdig.Parsers
{
public class ParserList<T> : List<T> where T : class, ICharacterParser
public abstract class ParserList<T> : List<T> where T : ParserBase
{
private T[][] parsersWithOpeningCharacters;
private T[] globalParsers;
@@ -36,17 +36,24 @@ namespace Textamina.Markdig.Parsers
return -1;
}
public void Initialize()
public virtual void Initialize()
{
var charCounter = new Dictionary<char, int>();
int globalCounter = 0;
int maxChar = 0;
foreach (var parser in this)
for (int i = 0; i < this.Count; i++)
{
var parser = this[i];
parser.Index = i;
if (parser.OpeningCharacters != null && parser.OpeningCharacters.Length != 0)
{
foreach (var openingChar in parser.OpeningCharacters)
{
if (openingChar >= 127)
{
throw new InvalidOperationException($"Invalid non-ascii character `{openingChar}` used by the parser [{parser.GetType().Name}]. Only ASCII < 127 are allowed");
}
if (!charCounter.ContainsKey(openingChar))
{
charCounter[openingChar] = 0;

View File

@@ -41,8 +41,10 @@
<Compile Include="Formatters\HtmlTextWriter.cs" />
<Compile Include="Helpers\LinkHelper.cs" />
<Compile Include="Helpers\StringBuilderCache.cs" />
<Compile Include="Parsers\BlockParserList.cs" />
<Compile Include="Parsers\IBlockParser.cs" />
<Compile Include="Parsers\InlineParser.cs" />
<Compile Include="Parsers\InlineParserList.cs" />
<Compile Include="Parsers\InlineParserState.cs" />
<Compile Include="Parsers\BlockParserState.cs" />
<Compile Include="Parsers\Inlines\HtmlEntityParser.cs" />