This is a test Markdown file
It has some emphasis and some strong stuff to talk about
SomeCodeIsEvenDisplayed ()
{
	public void IntoSomething ()
	{
		Console.WriteLine ("That looks like code");
	}
}You can even embed cool url like my website.
| %{ | |
| using System; | |
| using System.IO; | |
| using System.Linq; | |
| using System.Collections.Generic; | |
| namespace MarkdownParser | |
| { | |
| class Counter | |
| { | |
| public Counter (int count = 0) | |
| { | |
| Count = count; | |
| } | |
| public int Count { | |
| get; | |
| set; | |
| } | |
| } | |
| public class Parser | |
| { | |
| int yacc_verbose_flag = 0; | |
| public IEnumerable<IBlock> Parse (string input) | |
| { | |
| return Parse (new StringReader (input)); | |
| } | |
| public IEnumerable<IBlock> Parse (TextReader reader) | |
| { | |
| var lexer = new Tokenizer (reader); | |
| return (IEnumerable<IBlock>)this.yyparse (lexer); | |
| } | |
| %} | |
| %token ERROR | |
| %token TEXT /* A string of character until the next newline/span */ | |
| %token EMPTY_LINE | |
| %token NEWLINE | |
| %token TRIPLE_QUOTE | |
| %token HASH | |
| %token HEADING_LINE | |
| %token HEADING_LINE_DASH | |
| %token EMPH_MARKER | |
| %token STRONG_MARKER | |
| %token BULLET_MARKER | |
| %token INLINE_CODE_MARKER | |
| %token URL_MARKER | |
| %start document | |
| %% | |
| document: opt_block_list { $$ = $1; ((List<IBlock>)$$).Reverse (); } | |
| opt_block_list | |
| : /* empty */ { $$ = new List<IBlock> (); } | |
| | block opt_block_list { ((List<IBlock>)$2).Add ((IBlock)$1); $$ = $2; } | |
| block | |
| : block_inner EMPTY_LINE { $$ = $1; } | |
| block_inner | |
| : paragraph { $$ = $1; } | |
| | heading { $$ = $1; } | |
| | code { $$ = $1; } | |
| | bullet_list { $$ = $1; } | |
| paragraph: span_list NEWLINE { $$ = new Paragraph ((IList<ISpan>)$1); } | |
| heading | |
| : atx_heading { $$ = $1; } | |
| /* | setex_heading { $$ = $1; }*/ | |
| code | |
| : TRIPLE_QUOTE TEXT NEWLINE opt_text_list TRIPLE_QUOTE NEWLINE { $$ = new Code (language: ((string)$2).Trim (), content: string.Join (Environment.NewLine, (IEnumerable<string>)$4)); } | |
| opt_text_list: opt_text_list_inner { $$ = $1; ((List<string>)$1).Reverse (); } | |
| opt_text_list_inner | |
| : /* empty */ { $$ = new List<string> (); } | |
| | text opt_text_list_inner { ((List<string>)$2).Add ((string)$1); $$ = $2; } | |
| bullet_list | |
| : BULLET_MARKER | |
| span_list: span_list_inner { $$ = $1; ((List<ISpan>)$$).Reverse (); } | |
| span_list_inner | |
| : span { $$ = new List<ISpan> { (ISpan)$1 }; } | |
| | span span_list_inner { ((List<ISpan>)$2).Add ((ISpan)$1); $$ = $2; } | |
| span | |
| : TEXT { $$ = new FormatedSpan (SpanFormating.None, (string)$1); } | |
| | url { $$ = $1; } | |
| | emphasis { $$ = $1; } | |
| | strong { $$ = $1; } | |
| | inline_code { $$ = $1; } | |
| url: URL_MARKER TEXT URL_MARKER URL_MARKER TEXT URL_MARKER { $$ = new UrlSpan (href: (string)$5, content: (string)$2); } | |
| inline_code: INLINE_CODE_MARKER TEXT INLINE_CODE_MARKER { $$ = new FormatedSpan (SpanFormating.Code, (string)$1); } | |
| emphasis: EMPH_MARKER TEXT EMPH_MARKER { $$ = new FormatedSpan (SpanFormating.Emphasis, (string)$2); } | |
| strong: STRONG_MARKER TEXT STRONG_MARKER { $$ = new FormatedSpan (SpanFormating.Strong, (string)$2); } | |
| text: TEXT NEWLINE { $$ = $1; } | |
| atx_heading | |
| : hash_list text { $$ = new Heading (HeadingStyle.Atx, depth: ((Counter)$1).Count, content: ((string)$2).Trim ()); } | |
| hash_list | |
| : HASH { $$ = new Counter (1); } | |
| | HASH hash_list { ((Counter)$2).Count++; $$ = $2; } | |
| /*setex_heading: TEXT NEWLINE setex_heading_line NEWLINE { ((Heading)$3).Content = (string)$1; $$ = $3; } | |
| setex_heading_line | |
| : HEADING_LINE { $$ = new Heading (HeadingStyle.Setex, depth: 0); } | |
| | HEADING_LINE_DASH { $$ = new Heading (HeadingStyle.Setex, depth: 1); }*/ | |
| %% | |
| } | 
| using System; | |
| using System.IO; | |
| using System.Linq; | |
| using System.Collections.Generic; | |
| using NUnit.Framework; | |
| using MarkdownParser; | |
| namespace MarkdownParserTests | |
| { | |
| [TestFixture] | |
| public class Test | |
| { | |
| [Test] | |
| public void TestMarkdownAstTest () | |
| { | |
| var ast = new IBlock[] { | |
| new Heading (HeadingStyle.Atx, 1, "My Test Markdown file"), | |
| new Heading (HeadingStyle.Atx, 2, "Introduction"), | |
| new Paragraph (new ISpan[] { new FormatedSpan ("This is a test Markdown file") }), | |
| new Paragraph (new ISpan[] { | |
| new FormatedSpan ("It has some "), | |
| new FormatedSpan (SpanFormating.Emphasis, "emphasis"), | |
| new FormatedSpan (" and some "), | |
| new FormatedSpan (SpanFormating.Strong, "strong"), | |
| new FormatedSpan (" stuff to talk about"), | |
| }), | |
| new Code (language: "csharp", content: @"SomeCodeIsEvenDisplayed () | |
| { | |
| public void IntoSomething () | |
| { | |
| Console.WriteLine (""That looks like code""); | |
| } | |
| }"), | |
| new Paragraph (new ISpan[] { | |
| new FormatedSpan ("You can even embed cool url like "), | |
| new UrlSpan (href: "http://neteril.org", content: "my website"), | |
| new FormatedSpan (".") | |
| }) | |
| }; | |
| AssertAst (ast, "MarkdownParserTests.MarkdownSnippets.test_markdown.md"); | |
| } | |
| void AssertAst (IEnumerable<IBlock> expectedAst, string markdownRes) | |
| { | |
| var reader = new StreamReader (GetType ().Assembly.GetManifestResourceStream (markdownRes)); | |
| var parser = new Parser (); | |
| IEnumerable<IBlock> ast = null; | |
| try { | |
| ast = parser.Parse (reader); | |
| } catch (Exception e) { | |
| Assert.Fail ("Parser failed: {0}", e.ToString ()); | |
| } | |
| CollectionAssert.AreEqual (expectedAst, ast); | |
| } | |
| } | |
| } | 
This is a test Markdown file
It has some emphasis and some strong stuff to talk about
SomeCodeIsEvenDisplayed ()
{
	public void IntoSomething ()
	{
		Console.WriteLine ("That looks like code");
	}
}You can even embed cool url like my website.