diff --git a/CHANGELOG.md b/CHANGELOG.md index 72df146..f09acb7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,14 @@ # MultiMarkdown Change Log # +## [5.3.0] - 2016-06-08 ## + +* CHANGED: Update test suite +* FIXED: Don't allow math spans inside strong/emph +* FIXED: Fix additional edge case in emph/strong parser +* FIXED: Fix slow parsing of complex strong/emph (Fixes #18) +* FIXED: Improve accuracy and performance of strong/emph +* FIXED: Improve performance + ## [5.2.0] - 2016-03-16 ## @@ -96,3 +105,4 @@ [5.0.1]: https://github.com/fletcher/MultiMarkdown-5/releases/tag/5.0.1 [5.1.0]: https://github.com/fletcher/MultiMarkdown-5/releases/tag/5.1.0 [5.2.0]: https://github.com/fletcher/MultiMarkdown-5/releases/tag/5.2.0 +[5.3.0]: https://github.com/fletcher/MultiMarkdown-5/releases/tag/5.3.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 8fbd90a..1547de8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,9 +8,9 @@ cmake_minimum_required (VERSION 2.6) set (My_Project_Title "MultiMarkdown") set (My_Project_Description "MultiMarkdown - lightweight markup processor") set (My_Project_Author "Fletcher T. Penney") -set (My_Project_Revised_Date "2016-03-16") +set (My_Project_Revised_Date "2016-06-08") set (My_Project_Version_Major 5) -set (My_Project_Version_Minor 2) +set (My_Project_Version_Minor 3) set (My_Project_Version_Patch 0) set (My_Project_Version "${My_Project_Version_Major}.${My_Project_Version_Minor}.${My_Project_Version_Patch}") diff --git a/src/parser.leg b/src/parser.leg index af2d88c..3c2acf8 100644 --- a/src/parser.leg +++ b/src/parser.leg @@ -102,7 +102,7 @@ YAMLStop = ("---"|"...") BlankLine DocForMetaDataOnly = BOM? a:StartList ( &( YAMLStart? MetaDataKey Sp ':' Sp (!Newline)) MetaData { a = cons($$, a); } )? - ( SkipBlock )* + ( . )* BlankLine* { ((parser_data *)G->data)->result = reverse_list(a); @@ -251,8 +251,7 @@ SpecialChar = '*' | '_' | '`' | '&' | '[' | ']' | '(' | ')' | '<' | '!' | '#' ExtendedSpecialChar = &{ ext(EXT_SMART) } ('.' | '-' | '\'' | '"') | &{ ext(EXT_NOTES) } ( '^' ) | &{ ext(EXT_CRITIC) } ( '{' ) - | &{ !ext(EXT_COMPATIBILITY) } ( '~' ) - | &{ !ext(EXT_COMPATIBILITY) } ( '|' ) + | &{ !ext(EXT_COMPATIBILITY) } ( '~' | '|' ) Punctuation = '.' | ',' | '?' | '!' | ';' | ':' | '。' | '、' NonPunctuation = !(Punctuation | SpecialChar | Spacechar | Newline) . @@ -315,22 +314,27 @@ Inlines = a:StartList ( !Endline Inline { a = cons($$, a); } Inline = #&{ check_timeout((parser_data *)G->data) } # TODO: the check_timeout function still slows us down -- do we still need it?? &{ ext(EXT_CRITIC) } CriticMarkup - | &{ !ext(EXT_COMPATIBILITY) } DollarMath + | &'$' &{ !ext(EXT_COMPATIBILITY) } DollarMath | Str - | &{ !ext(EXT_COMPATIBILITY) } MathSpan + | &'\\\\' &{ !ext(EXT_COMPATIBILITY) } MathSpan | Endline | UlOrStarLine | Space | Strong | Emph - | &{ !ext(EXT_COMPATIBILITY) } CitationReference - | &{ !ext(EXT_COMPATIBILITY) } Variable - | Image - | Link - | NoteReference + | &'[' ( + &{ !ext(EXT_COMPATIBILITY) } CitationReference + | &{ !ext(EXT_COMPATIBILITY) } Variable + | NoteReference + | Link + ) + | &'![' Image | Code - | MarkdownHtmlTagOpen - | RawHtml + | &'<' ( + Link + | MarkdownHtmlTagOpen + | RawHtml + ) | Entity | EscapedChar | Smart @@ -407,18 +411,28 @@ SingleDollarMathStart = '$' !(Spacechar | Newline | '$' ) SingleDollarMathEnd = (!'\\' !'$' Nonspacechar) '$' !NonPunctuation -SingleDollarMath = < SingleDollarMathStart (!SingleDollarMathEnd !(BlankLine BlankLine) .)* SingleDollarMathEnd > +SingleDollarMath = < SingleDollarMathText > { $$ = str(yytext); $$->key = MATHSPAN; } DoubleDollarMathStart = '$' '$' !(Spacechar | Newline) DoubleDollarMathEnd = (!'\\' Nonspacechar) '$' '$' !NonPunctuation -DoubleDollarMath = < DoubleDollarMathStart (!DoubleDollarMathEnd !(BlankLine BlankLine) .)* DoubleDollarMathEnd > +DoubleDollarMath = < DoubleDollarMathText > { $$ = str(yytext); $$->key = MATHSPAN; } DollarMath = SingleDollarMath | DoubleDollarMath + +MathText = &{ !ext(EXT_COMPATIBILITY) } + (MathSpanText | SingleDollarMathText | DoubleDollarMathText) + +MathSpanText = '\\' ( ('\\[' (!'\\\\]' .)* '\\\\]') | ('\\(' (!'\\\\)' .)* '\\\\)') ) + +SingleDollarMathText = SingleDollarMathStart (!SingleDollarMathEnd !(BlankLine BlankLine) .)* SingleDollarMathEnd + +DoubleDollarMathText = DoubleDollarMathStart (!DoubleDollarMathEnd !(BlankLine BlankLine) .)* DoubleDollarMathEnd + # This keeps the parser from getting bogged down on long strings of '*' or '_', # or strings of '*' or '_' with space on each side: UlOrStarLine = (UlLine | StarLine) { $$ = str(yytext); } @@ -439,17 +453,54 @@ Emph = < EmphMatch > EmphMatch = (EmphStar | EmphUl) -EmphStar = '*' !Whitespace - (StrongMatch | BracketedText | (!'*' !(BlankLine BlankLine) .) ) - ((Whitespace? StrongMatch) | (Whitespace? EmphMatch) | (Whitespace? BracketedText) | - (!'*' !(BlankLine BlankLine) !Whitespace .) | (!'*' !(BlankLine BlankLine) !(Whitespace '*') .) - )* - '*' +EmphStarOpen = '*' !Whitespace + +EmphStarClose = '*' + +OneStar = '*' !'*' + +TwoStar = '**' !'*' + +OneTwoStar = '*' '*'? !'*' + +ThreeStar = '***' !'*' -EmphUl = '_' !Whitespace - (StrongMatch | BracketedText | (!'_' !(BlankLine BlankLine) .) ) - (StrongMatch | EmphMatch | BracketedText | (!'_' !(BlankLine BlankLine) .) )* - '_' &('_'* (SpecialChar | Whitespace)) +EmphStar = EmphStarOpen + (StrongMatch | BracketedText | MathText | (!'*' .) ) + ( + &(Whitespace) ( + Whitespace + (StrongMatch | EmphMatch) + ) | + &TwoStar ( + StrongStar + ) | + BracketedText | + MathText | + (!'*' !Whitespace .) | + (!'*' !(BlankLine BlankLine) !(Whitespace '*') .) + )* + EmphStarClose + +EmphUlOpen = '_' !Whitespace + +EmphUlClose = '_' &('__'? !'_' ( Whitespace | Punctuation | SpecialChar | Eof)) + +EmphUl = EmphUlOpen + (StrongMatch | BracketedText | MathText | (!'_' .) ) + ( + &(Whitespace) ( + Whitespace + (StrongMatch | EmphMatch) + ) | + &OneTwoStar ( + StrongStar | EmphStar + ) | + BracketedText | + MathText | + (!'_' !(BlankLine BlankLine) .) + )* + EmphUlClose Strong = < StrongMatch > { @@ -463,17 +514,46 @@ Strong = < StrongMatch > StrongMatch = (StrongStar | StrongUl) -StrongStar = "**" !Whitespace - (EmphMatch | BracketedText | (!'*' !(BlankLine BlankLine) .) ) - ((Whitespace? StrongMatch) | (Whitespace? EmphMatch) | (Whitespace? BracketedText) | - (!'*' !(BlankLine BlankLine) !Whitespace .) | (!'*' !(BlankLine BlankLine) !(Whitespace '*') .) +StrongStarOpen = '**' !Whitespace + +StrongStarClose = '**' + +StrongStar = StrongStarOpen + (EmphMatch | BracketedText | MathText | (!'*' .) ) + ( + &(Whitespace) ( + Whitespace + (StrongMatch | EmphMatch) + ) | + &OneStar ( + EmphStar + ) | + BracketedText | + MathText | + (!'*' !Whitespace .) | + (!'*' !(BlankLine BlankLine) !(Whitespace '*') .) )* - "**" - -StrongUl = "__" !Whitespace - (EmphMatch | BracketedText | (!'_' !(BlankLine BlankLine) .) ) - (StrongMatch | EmphMatch | BracketedText | (!'_' !(BlankLine BlankLine) .) )* - "__" &('_'* (SpecialChar | Whitespace)) + StrongStarClose + +StrongUlOpen = '__' !Whitespace + +StrongUlClose = '__' &('_'? !'_' ( Whitespace | Punctuation | SpecialChar | Eof)) + +StrongUl = StrongUlOpen + (EmphMatch | BracketedText | MathText | (!'_' .) ) + ( + &(Whitespace) ( + Whitespace + (StrongMatch | EmphMatch) + ) | + &OneTwoStar ( + StrongStar | EmphStar + ) | + BracketedText | + MathText | + (!'_' !(BlankLine BlankLine) .) + )* + StrongUlClose Link = ExplicitLink | ReferenceLink | AutoLink @@ -497,7 +577,7 @@ ReferenceLinkSingle = ( a:Label < (Spnl "[]")? > ) CitationReference = CitationReferenceDouble | CitationReferenceSingle -CitationReferenceDouble = !"[]" a:Label < Spnl > !"[]" b:RawCitationReference +CitationReferenceDouble = !"[]" !"[#" a:Label < Spnl > !"[]" b:RawCitationReference { char *label; label = label_from_node_tree(a); @@ -662,8 +742,19 @@ Image = '!' ( !AutoLink Link ) $$->key = IMAGE; } +Label = &( '[' ) + < BracketedText > + { + yytext[strlen(yytext) - 1] = '\0'; + $$ = markdown_chunk_to_node(&yytext[1], ((parser_data *)G->data)->extensions); + if ($$ == NULL) { + $$ = str(""); + } else { + $$->key = LIST; + } + } -Label = < "[" (&"[%" | !'[' ( !'^' !'#' &{ ext(EXT_NOTES) } | &. &{ !ext(EXT_NOTES) } )) +Label2 = < "[" (&"[%" | !'[' ( !'^' !'#' &{ ext(EXT_NOTES) } | &. &{ !ext(EXT_NOTES) } )) a:StartList ( !']' Inline { a = cons($$, a); } )* ']'> @@ -1382,7 +1473,11 @@ RightAlign = ('-'+ | '='+)':' &(!'-' !'=' !':') CellDivider = '|' -BracketedText = '[' ((!'[' !']' .) | BracketedText )* ']' # Matches text within [...], but allows for recursive brackets +BracketedTextz = &('[' (!(Endline Endline) !']' .)* ']') BracketedText2 + +BracketedText = &('[' (!(BlankLine BlankLine) !']' .)* ']') BracketedText2 + +BracketedText2 = '[' ( ('\\' .) | (!'[' !']' .) | BracketedText2 )* ']' # Matches text within [...], but allows for recursive brackets TableCaption = b:StartList a:StartList (< BracketedText > { @@ -1485,9 +1580,9 @@ TOCPlain = ( (y:Fenced { free_node_tree(y); } ) | (!BlankLine !Heading z:Line { # Critic Markup -CriticMarkup = CriticAddition | CriticDeletion | CriticSubstitution | CriticHighlight | CriticComment +CriticMarkup = &'{' (CriticAddition | CriticDeletion | CriticSubstitution | CriticHighlight | CriticComment) -CriticClean = CleanAddition | CleanDeletion | CleanSubstitution | CleanHighlight | CleanComment +CriticClean = &'{' (CleanAddition | CleanDeletion | CleanSubstitution | CleanHighlight | CleanComment) AddStart = '{++' diff --git a/submodules/MarkdownTest b/submodules/MarkdownTest index 45d54df..8d5ad66 160000 --- a/submodules/MarkdownTest +++ b/submodules/MarkdownTest @@ -1 +1 @@ -Subproject commit 45d54dfaae4c3715366faf161118ecb2422201ee +Subproject commit 8d5ad66e3bbaeb0de8646783bfe964261ddb39c7 diff --git a/submodules/greg b/submodules/greg index 98ecf13..265003c 160000 --- a/submodules/greg +++ b/submodules/greg @@ -1 +1 @@ -Subproject commit 98ecf13c3502b47e342b09fb7b0cad453e1bb797 +Subproject commit 265003c8cb3022183f48df3e2684336b788af39d