# Copyright (C) 2008, The Perl Foundation.
# $Id: /mirror/trunk/languages/markdown/src/parser/grammar.pg 31852 2008-10-09T06:52:03.272406Z fperrad  $

=begin overview

This is the grammar for Markdown written as a sequence of Perl 6 rules.

=end overview

=cut

grammar Markdown::Grammar is PCT::Grammar;

token TOP {
    ^ <Block>*
    {*}
}

token Block {
    <.BlankLine>* [
        | <BlockQuote> {*}      #= BlockQuote
        | <HorizontalRule> {*}  #= HorizontalRule
        | <Heading> {*}         #= Heading
        | <OrderedList> {*}     #= OrderedList
        | <BulletList> {*}      #= BulletList
        | <Para> {*}            #= Para
    ]
}

token Para {
    <.NonindentSpace> <Inlines> <.BlankLine>+
    {*}
}

token AtxInline {
    <!Newline> <!_AtxEnd> <Inline> {*}
}

token _AtxEnd {
    <.Sp> '#'* <.Sp> <.Newline>
}

token AtxStart { '######' | '#####' | '####' | '###' | '##' | '#' }

token AtxHeading {
    <AtxStart> <.Sp> <AtxInline>+ <._AtxEnd>
    {*}
}

token SetextHeading {
    | <SetextHeading1> {*}      #= SetextHeading1
    | <SetextHeading2> {*}      #= SetextHeading2
}

token SetextHeading1 {
    <!Endline> <Inline>+ <.Newline> '===' '='* <.Newline>
    {*}
}

token SetextHeading2 {
    <!Endline> <Inline>+ <.Newline> '---' '-'* <.Newline>
    {*}
}

token Heading {
    | <AtxHeading> {*}          #= AtxHeading
    | <SetextHeading> {*}       #= SetextHeading
}

token BlockQuote {
    <BlockQuoteRaw>
    {*}
}

token BlockQuoteRaw {
    [
        <._Chevron> ' '? <Line>
        [ <!_Chevron> <!BlankLine> <Line> ]*
        <.BlankLine>*
    ]+
    {*}
}

token _Chevron { '>' }

token HorizontalRule {
    <.NonindentSpace> [
        | '*' <.Sp> '*' <.Sp> '*' [ <.Sp> '*' ]*
        | '-' <.Sp> '-' <.Sp> '-' [ <.Sp> '-' ]*
        | '_' <.Sp> '_' <.Sp> '_' [ <.Sp> '_' ]*
    ]
    <.Sp> <.Newline> <.BlankLine>+
    {*}
}

token Bullet {
    <.NonindentSpace> [ '+' | '*' | '-' ] <.Spacechar>+
}

token BulletList {
    | <BulletListTight> {*}     #= BulletListTight
    | <BulletListLoose> {*}     #= BulletListLoose
}

token BulletListTight {
    <BulletListItem>+ <.BlankLine>* <!BulletListLoose>
    {*}
}

token BulletListLoose {
    [
        <BulletListItem> <.BlankLine>*
    ]+
    {*}
}

token BulletListItem {
    <!HorizontalRule> <?Bullet> <ListItem>
    {*}
}

token ListItem {
    [ <.Bullet> | <.Enumerator> ] <ListBlock> <ListContinuationBlock>*
    {*}
}

token ListBlock {
    <Line> <ListBlockLine>*
    {*}
}

token ListContinuationBlock {
    <BlankLine>* [ <.Indent> <ListBlock> ]+
    {*}
}

token Enumerator {
    <.NonindentSpace> \d+ '.' <.Spacechar>+
}

token OrderedList {
    | <OrderedListTight> {*}    #= OrderedListTight
    | <OrderedListLoose> {*}    #= OrderedListLoose
}

token OrderedListTight {
    <OrderedListItem>+ <.BlankLine>* <!OrderedListLoose>
    {*}
}

token OrderedListLoose {
    [
        <OrderedListItem> <.BlankLine>*
    ]+
    {*}
}

token OrderedListItem {
    <!HorizontalRule> <?Enumerator> <ListItem>
    {*}
}

token ListBlockLine {
    <!_ListItem> <!BlankLine> <OptionallyIndentedLine>
}

token _ListItem {
    <.Indent>? [ <BulletListItem> | <OrderedListItem> ]
}

token Inlines {
    <_Inline>+
    <.Endline>?
}

token _Inline {
    | <!Endline> <Inline> {*}   #= Inline
    | <Endline> <?Inline> {*}   #= Endline
}

token Inline {
    | <Str> {*}                 #= Str
#    | <Endline> {*}             #= Endline
    | <Space> {*}               #= Space
    | <Strong> {*}              #= Strong
    | <Emph> {*}                #= Emph
    | <Code> {*}                #= Code
    | <Entity> {*}              #= Entity
    | <EscapedChar> {*}         #= EscapedChar
    | <Symbol> {*}              #= Symbol
}

token Space {
    <Spacechar>+ {*}
}

token Str {
    <NormalChar>+ {*}
}

token EscapedChar {
    '\\' <!Newline> (.)
    {*}
}

token Entity {
    | <HexEntity> {*}
    | <DecEntity> {*}
    | <CharEntity> {*}
}

token Endline {
    <TerminalEndline> | <NormalEndline>
    {*}
}

token NormalEndline {
    <.Sp> <.Newline> <!BlankLine> <!BlockQuote> <!AtxStart> <!_Setext>
}

token _Setext {
    <Line> [ '===' '='* | '---' '-'* ] <Newline>
}

token TerminalEndline {
    <.Sp> <.Newline> <.Eof>
}

token Symbol {
    <SpecialChar> {*}
}

# This keeps the parser from getting bogged down on long strings of '*' or '_',
# or strings of '*' or '_' with space on each side:
token StarLine {
    | '****' '*'*
    | <.Spacechar> '*'+ <?Spacechar>
}

token UILine {
    | '____' '_'*
    | <.Spacechar> '_'+ <?Spacechar>
}

token Emph {
    | <EmphStar> {*}            #= EmphStar
    | <EmphUI> {*}              #= EmphUI
}

token OneStarOpen { <!StarLine> '*' <!Spacechar> <!Newline> }

token OneStarClose { <!Spacechar> <!Newline> <Inline> <!StrongStar> '*' }

token EmphStar {
    <.OneStarOpen> [ <!OneStarClose> <Inline> ]* <OneStarClose>
    {*}
}

token OneUIOpen { <!UILine> '_' <!Spacechar> <!Newline> }

token OneUIClose { <!Spacechar> <!Newline> <Inline> <!StrongUI> '_' <!Alphanumeric> }

token EmphUI {
    <.OneUIOpen> [ <!OneUIClose> <Inline> ]* <OneUIClose>
    {*}
}

token Strong {
    | <StrongStar> {*}          #= StrongStar
    | <StrongUI> {*}            #= StrongUI
}

token TwoStarOpen { <!StarLine> '**' <!Spacechar> <!Newline> }

token TwoStarClose { <!Spacechar> <!Newline> <Inline> '**' }

token StrongStar {
    <.TwoStarOpen> [ <!TwoStarClose> <Inline> ]* <TwoStarClose>
    {*}
}

token TwoUIOpen { <!UILine> '__' <!Spacechar> <!Newline> }

token TwoUIClose { <!Spacechar> <!Newline> <Inline> '__' <!Alphanumeric> }

token StrongUI {
    <.TwoUIOpen> [ <!TwoUIClose> <Inline> ]* <TwoUIClose>
    {*}
}

token Ticks1 { '`' }
token Ticks2 { '``' }
token Ticks3 { '```' }
token Ticks4 { '````' }
token Ticks5 { '`````' }

token Code {
    | <.Ticks1> <.Sp> (<_Code1>) <.Sp> <.Ticks1> {*}
    | <.Ticks2> <.Sp> (<_Code2>) <.Sp> <.Ticks2> {*}
    | <.Ticks3> <.Sp> (<_Code3>) <.Sp> <.Ticks3> {*}
    | <.Ticks4> <.Sp> (<_Code4>) <.Sp> <.Ticks4> {*}
    | <.Ticks5> <.Sp> (<_Code5>) <.Sp> <.Ticks5> {*}
}

token _Sp_Ticks1 { <Sp> <Ticks1> }
token _Sp_Ticks2 { <Sp> <Ticks2> }
token _Sp_Ticks3 { <Sp> <Ticks3> }
token _Sp_Ticks4 { <Sp> <Ticks4> }
token _Sp_Ticks5 { <Sp> <Ticks5> }

token _Code1 {
    [
        | [ <!Ticks1> <Nonspacechar> ]+
        | <!Ticks1> '`'+
        | <!_Sp_Ticks1> [ <Spacechar> | <Newline> <!BlankLine> ]
    ]
}

token _Code2 {
    [
        [ <!Ticks2> <Nonspacechar> ]+
        | <!Ticks2> '`'+
        | <!_Sp_Ticks2> [ <Spacechar> | <Newline> <!BlankLine> ]
    ]+
}

token _Code3 {
    [
        [ <!Ticks3> <Nonspacechar> ]+
        | <!Ticks3> '`'+
        | <!_Sp_Ticks3> [ <Spacechar> | <Newline> <!BlankLine> ]
    ]+
}

token _Code4 {
    [
        [ <!Ticks4> <Nonspacechar> ]+
        | <!Ticks4> '`'+
        | <!_Sp_Ticks4> [ <Spacechar> | <Newline> <!BlankLine> ]
    ]+
}

token _Code5 {
    [
        [ <!Ticks5> <Nonspacechar> ]+
        | <!Ticks5> '`'+
        | <!_Sp_Ticks5> [ <Spacechar> | <Newline> <!BlankLine> ]
    ]+
}

token BlankLine { <.Sp> <.Newline> }

token Eof { $ }

token Spacechar { ' ' | \t }

token Nonspacechar { <!Spacechar> <!Newline> . }

token Newline { \n }

token Sp { <Spacechar>* }

token SpecialChar { '*' | '_' | '`' | '&' | '[' | ']' | '<' | '!' | '\\' }

token NormalChar { <!SpecialChar> <!Spacechar> <!Newline> . }

token Alphanumeric { \w }

token HexEntity { '&#' <[Xx]> <[0..9a..fA..F]>+ ';' }

token DecEntity { '&#' <[0..9]>+ ';'}

token CharEntity { '&' <[A..Za..z0..9]>+ ';' }

token NonindentSpace { '   ' | '  ' | ' ' | '' }

token Indent { \t | '    ' }

token IndentedLine { <.Indent> <Line> }

token OptionallyIndentedLine { <.Indent>? <Line> }

token Line { <RawLine> {*} }

token RawLine {
    [
    | (\N*) <.Newline>
    | (.+) <.Eof>
    ]
    {*}
}
