private MarkdownParsingResult <INode> ParseFormatModificator(ITokenizer <IMdToken> tokenizer, Md modificatorAttribute) { var boundedTokenizer = tokenizer.UntilNotMatch(token => token.Has(Md.Close, modificatorAttribute)); var open = boundedTokenizer.Match(token => token.Has(Md.Open, modificatorAttribute)); var children = open.IfSuccess( childrenTokenizer => ParseNodesUntilMatch(childrenTokenizer, t => ParseTextWithEscaped(t) .IfFail(ParseFormatModificator) .IfFail(ParseAnyTokenAsText)) ); var close = children.IfSuccess(t => t.UnboundTokenizer() .Match(token => token.Has(Md.Close, modificatorAttribute)) ); if (close.Succeed && close.Parsed.Text == open.Parsed.Text) { var node = CreateModificatorNode(modificatorAttribute, children.Parsed); return(close.Remainder.SuccessWith(node)); } return(tokenizer.Fail <INode>()); }
private MarkdownParsingResult <INode> ParseCodeIndented(ITokenizer <IMdToken> tokenizer) { var codeLines = ParseNodesUntilMatch(tokenizer, t => { var start = t.Match(token => token.Has(Md.Indent)); var codeLine = start.IfSuccess(inner => { var bounded = inner.UntilNotMatch(token => token.Has(Md.NewLine)); return(ParseNodesUntilMatch(bounded, ParseAnyTokenAsEscaped)); }); if (codeLine.Succeed) { var codeNodes = codeLine.Parsed; var newLine = codeLine.Remainder.UnboundTokenizer().Match(token => token.Has(Md.NewLine)); if (newLine.Succeed) { codeNodes.Add(new EscapedTextNode(newLine.Parsed.Text)); } return(newLine.Remainder.SuccessWith(codeNodes)); } return(t.Fail <List <INode> >()); }); if (!codeLines.Parsed.Any()) { return(tokenizer.Fail <INode>()); } var unpackedText = codeLines.Parsed.SelectMany(node => node); return(codeLines.Remainder.SuccessWith <INode>(new CodeModificatorNode(unpackedText))); }
private MarkdownParsingResult <INode> ParseAnyTokenAsText(ITokenizer <IMdToken> tokenizer) { if (tokenizer.AtEnd) { return(tokenizer.Fail <INode>()); } return(tokenizer.Advance().SuccessWith <INode>(new TextNode(tokenizer.CurrentToken.Text))); }
public static MarkdownParsingResult <IMdToken> Match(this ITokenizer <IMdToken> tokenizer, Predicate <IMdToken> predicate) { if (tokenizer.AtEnd || !predicate(tokenizer.CurrentToken)) { return(tokenizer.Fail <IMdToken>()); } return(tokenizer.Advance().SuccessWith(tokenizer.CurrentToken)); }
public MarkdownParsingResult <INode> ParseParagraph(ITokenizer <IMdToken> tokenizer) { var children = ParseNodesUntilMatch(tokenizer, ParseFormattedText); if (children.Parsed.Any()) { return(children.Remainder.SuccessWith <INode>(new ParagraphNode(children.Parsed))); } return(tokenizer.Fail <INode>()); }
private MarkdownParsingResult <INode> ParseEscaped(ITokenizer <IMdToken> tokenizer) { var tokens = tokenizer.Match(token => token.Has(Md.Escaped)); if (tokens.Succeed) { return(tokens.Remainder.SuccessWith <INode>(new EscapedTextNode(tokens.Parsed.Text))); } return(tokenizer.Fail <INode>()); }
private MarkdownParsingResult <INode> ParseAnyTokenAsEscaped(ITokenizer <IMdToken> tokenizer) { if (tokenizer.AtEnd) { return(tokenizer.Fail <INode>()); } var underlyingText = tokenizer.CurrentToken.UnderlyingText; return(tokenizer.Advance().SuccessWith <INode>(new EscapedTextNode(underlyingText))); }
private MarkdownParsingResult <INode> ParsePlainText(ITokenizer <IMdToken> tokenizer) { var tokens = tokenizer.UntilMatch(token => token.Has(Md.PlainText)); var text = string.Join("", tokens.Parsed.Select(t => t.Text)); if (tokens.Parsed.Any()) { return(tokens.Remainder.SuccessWith <INode>(new TextNode(text))); } return(tokenizer.Fail <INode>()); }
private MarkdownParsingResult <INode> ParseTextWithEscaped(ITokenizer <IMdToken> tokenizer) { var parsingResult = ParseNodesUntilMatch(tokenizer, t => ParsePlainText(t).IfFail(ParseEscaped)); var nodes = parsingResult.Parsed; if (!nodes.Any()) { return(tokenizer.Fail <INode>()); } // No need to create extra nodes if we can INode result = nodes.Count == 1 ? nodes[0] : new GroupNode(nodes); return(parsingResult.Remainder.SuccessWith(result)); }
private MarkdownParsingResult <INode> ParseCodeInBackticks(ITokenizer <IMdToken> tokenizer) { var boundedTokenizer = tokenizer.UntilNotMatch(token => token.Has(Md.Close, Md.Code)); var open = boundedTokenizer.Match(token => token.Has(Md.Open, Md.Code)); var children = open.IfSuccess(childrenTokenizer => ParseNodesUntilMatch(childrenTokenizer, ParseAnyTokenAsEscaped)); var close = children.IfSuccess(t => t.UnboundTokenizer() .Match(token => token.Has(Md.Close, Md.Code))); if (close.Succeed) { return(close.Remainder.SuccessWith <INode>(new CodeModificatorNode(children.Parsed))); } return(tokenizer.Fail <INode>()); }
private MarkdownParsingResult <INode> ParseHeader(ITokenizer <IMdToken> tokenizer) { var header = tokenizer.Match(token => token.Has(Md.Header)); var boundedTokenizer = header.IfSuccess(t => { var bounded = t.UntilNotMatch(token => token.HasAny(Md.NewLine, Md.Break)); return(SkipWhiteSpaces(bounded)); }); var headerContent = boundedTokenizer.IfSuccess(t => ParseNodesUntilMatch(t, ParseFormattedText)); if (headerContent.Succeed) { return(headerContent.Remainder.UnboundTokenizer().SuccessWith <INode>( new HeaderNode(header.Parsed.Text.Length, headerContent.Parsed) )); } return(tokenizer.Fail <INode>()); }
private MarkdownParsingResult <INode> ParseLink(ITokenizer <IMdToken> tokenizer) { var openText = tokenizer.Match(token => token.Has(Md.LinkText, Md.Open)); var text = openText.IfSuccess(ParseTextWithEscaped); var closeText = text.IfSuccess(t => t.Match(token => token.Has(Md.LinkText, Md.Close))); var openLink = closeText .IfSuccess(SkipWhiteSpaces) .IfSuccess(t => t.Match(token => token.Has(Md.LinkReference, Md.Open))); var link = openLink.IfSuccess(ParsePlainText); var closeLink = link.IfSuccess(t => t.Match(token => token.Has(Md.LinkReference, Md.Close))); if (closeLink.Succeed) { var linkText = ((TextNode)link.Parsed).Text; return(closeLink.Remainder.SuccessWith <INode>(new LinkNode(linkText, text.Parsed))); } return(tokenizer.Fail <INode>()); }