mirror of
https://github.com/xoofx/markdig.git
synced 2026-10-08 14:48:32 +00:00
Add better infrastructure for the parsers
This commit is contained in:
@@ -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)
|
||||
|
||||
7
src/Textamina.Markdig/Parsers/BlockParserList.cs
Normal file
7
src/Textamina.Markdig/Parsers/BlockParserList.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Textamina.Markdig.Parsers
|
||||
{
|
||||
public class BlockParserList : ParserList<BlockParser>
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace Textamina.Markdig.Parsers
|
||||
public interface ICharacterParser
|
||||
{
|
||||
char[] OpeningCharacters { get; }
|
||||
|
||||
int Index { get; }
|
||||
}
|
||||
|
||||
public interface IBlockParser : ICharacterParser
|
||||
|
||||
@@ -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; }
|
||||
|
||||
29
src/Textamina.Markdig/Parsers/InlineParserList.cs
Normal file
29
src/Textamina.Markdig/Parsers/InlineParserList.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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" />
|
||||
|
||||
Reference in New Issue
Block a user