%% name = NoraMark::Parser %% ast-location = ::NoraMark %% text = ast Text(content) %% paragraph = ast Paragraph(ids, classes, parameters, content) %% paragraph_group = ast ParagraphGroup(ids, classes, parameters, content) %% br = ast Breakline() %% line_command = ast LineCommand(name, ids, classes, parameters, content) %% block = ast Block(name, ids, classes, parameters, content) %% newpage = ast Newpage(ids, classes, parameters, content) %% inline = ast Inline(name, ids, classes, parameters, content) %% ul_item = ast UlItem(ids, classes, parameters, content) %% unordered_list = ast UnorderedList(ids, classes, parameters, content) %% ol_item = ast OlItem(ids, classes, parameters, content) %% ordered_list = ast OrderedList(ids, classes, parameters, content) %% dl_item = ast DLItem(ids, classes, parameters, content) %% definition_list = ast DefinitionList(ids, classes, parameters, content) %% preformatted_block = ast PreformattedBlock(name, ids, classes, parameters, codelanguage, content) %% frontmatter = ast Frontmatter(content) %% h_section = ast HeadedSection(level, heading, content) %% page = ast Page(content) # literals Eof = !. Space = ' ' | '\t' EofComment = Space* "#" (!Eof .)* Comment = Space* "#" (!Nl .)* Nl EmptyLine* - = ( Space )* EmptyLine = /^/ - (Nl | Comment | EofComment) Nl = /\r?\n/ Le = Nl | Eof Word = < /[\w0-9]/ ( '-' | /[\w0-9]/ )* > { text } Num = < [0-9]+ > { text.to_i } #common syntax ClassName = '.' Word:classname { classname } ClassNames = (ClassName)*:classnames { classnames } IdName = '#' Word:idname { idname } IdNames = (IdName)*:idnames { idnames } CommandName = Word:name IdNames?:idnames ClassNames?:classes { {name: name, ids: idnames, classes: classes} } ParameterNormal = < /[^,)]/* > { text } ParameterQuoted = '"' < /[^"]/* > '"' - &/[,)]/ { text } ParameterSingleQuoted = "'" < /[^']/* > "'" - &/[,)]/ { text } Parameter = (ParameterQuoted | ParameterSingleQuoted | ParameterNormal ):value { value } Parameters = Parameter:parameter ',' - Parameters:parameters { [ parameter ] + parameters } | Parameter:parameter { [ parameter ] } Command = CommandName:cn ('(' - Parameters:args - ')')? { args ||= []; cn.merge({ args: args }) } # paragraph ImplicitParagraph = - !ParagraphDelimiter Comment* DocumentLine:content Comment* EofComment? ~paragraph([],[], [], content) # explicit paragraph ExplicitParagraphCommand = Command:c &{ c[:name] == 'p' } ExplicitParagraph = - ExplicitParagraphCommand:c ':' - DocumentContent?:content Le EmptyLine* ~paragraph(c[:ids], c[:classes], c[:args], content) Paragraph = ExplicitParagraph | ImplicitParagraph # paragraph_group ParagraphGroup = Paragraph+:p EmptyLine* ~paragraph_group([],[],[],p) # explicit block BlockHead = - Command:command - '{' - Nl EmptyLine* { command } BlockEnd = - '}' - Le EmptyLine* BlockBody = (!BlockEnd Block)+:body { body } ExplicitBlock = BlockHead:c - BlockBody:content - BlockEnd ~block(c[:name], c[:ids], c[:classes], c[:args], content) # preformatted block PreformattedCommand = Command:command &{ ['pre', 'code'].include? command[:name] } PreformattedCommandHeadSimple = - PreformattedCommand:command - '{' - Nl { command } PreformattedCommandHeadComplex = - PreformattedCommand:command - '{//' Word?:codelanguage - Nl { command.merge({codelanguage: codelanguage}) } PreformattedCommandHead = PreformattedCommandHeadComplex | PreformattedCommandHeadSimple PreformatEndSimple = - '}' - Le EmptyLine* PreformatEndComplex = - '//}' - Le EmptyLine* PreformattedBlockSimple = PreformattedCommandHeadSimple:c (!PreformatEndSimple (CharString Nl))+:content PreformatEndSimple ~preformatted_block(c[:name], c[:ids], c[:classes], c[:args], c[:codelanguage], content) PreformattedBlockComplex = PreformattedCommandHeadComplex:c (!PreformatEndComplex (CharString Nl))+:content PreformatEndComplex ~preformatted_block(c[:name], c[:ids], c[:classes], c[:args], c[:codelanguage], content) PreformattedBlock = PreformattedBlockComplex | PreformattedBlockSimple # inline command Inline = ImgInline | CommonInline CommonInline = '[' Command:c '{' - DocumentContentExcept('}'):content '}' ']' ~inline(c[:name], c[:ids], c[:classes], c[:args], content) ImgCommand = Command:c &{ c[:name] == 'img' && c[:args].size == 2} ImgInline = '[' ImgCommand:c ']' ~inline(c[:name], c[:ids], c[:classes], c[:args], nil) # special line commands CommandNameForSpecialLineCommand = NewpageCommand | ExplicitParagraphCommand # newpage NewpageCommand = Command:command &{ command[:name] == 'newpage' } Newpage = - NewpageCommand:c ':' - DocumentContent?:content - Nl ~newpage(c[:ids],c[:classes],c[:args], content) # unordered list UnorderedList = UnorderedItem+:items ~unordered_list([],[],[], items) UnorderedItem = '*:' - DocumentContent:content Le ~ul_item([], [], [], content) # ordered list OrderedList = OrderedItem+:items ~ordered_list([],[],[], items) OrderedItem = Num ':' - DocumentContent:content Le ~ol_item([], [], [], content) # definition list DefinitionList = DefinitionItem+:items ~definition_list([], [], [], items) DefinitionItem = - ';:' - DocumentContentExcept(':'):term ':' - DocumentContent:definition Le ~dl_item([], [], [term], definition) # long definition list LongDefinitionList = LongDefinitionItem+:items ~definition_list([], [], [], items) LongDefinitionItem = - ';:' - DocumentContentExcept('{'):term '{' - Nl - BlockBody:definition - BlockEnd ~dl_item([], [], [term], definition) ItemsList = UnorderedList | OrderedList | DefinitionList | LongDefinitionList # generic line command LineCommand = - !CommandNameForSpecialLineCommand Command:c ':' - DocumentContent?:content - Le EmptyLine* ~line_command(c[:name], c[:ids], c[:classes], c[:args], content) # blocks LineBlock = ItemsList | LineCommand Block = EmptyLine* (PreformattedBlock | HeadedSection | LineBlock | ExplicitBlock | ParagraphGroup ):block EmptyLine* {block} BlockDelimiter = BlockHead | BlockEnd ParagraphDelimiter = BlockDelimiter | PreformattedCommandHead | LineBlock | Newpage | HeadedStart # markdown-style headings HStartMark(n) = < '='+ ':' > &{ text.length - 1 == n } HMarkupTerminator(n) = - < '='+ ':' > &{ text.length - 1 <= n } HStart(n) = - HStartMark(n) - DocumentContent:s Le { { level: n, heading: s } } HSection(n) = HStart(n):h (!HMarkupTerminator(n) !Eof Block)*:content ~h_section(h[:level], h[:heading], content) HeadedStart = HStart(1) | HStart(2) | HStart(3) | HStart(4) | HStart(5) | HStart(6) HeadedSection = HSection(1) | HSection(2) | HSection(3) | HSection(4) | HSection(5) | HSection(6) # frontmatter FrontmatterSeparator = - '---' - Nl Frontmatter = FrontmatterSeparator (!FrontmatterSeparator ( CharString Nl))+:yaml FrontmatterSeparator EmptyLine* ~frontmatter(yaml) # texts Char = < /[[:print:]]/ > { text } CharString = < Char* > { text } CharExcept(e) = Char:c &{ c != e } DocumentTextExcept(e) = < (!Inline CharExcept(e))+ > ~text(text) DocumentContentExcept(e) = (Inline | DocumentTextExcept(e))+:content { content } DocumentText = < (!Inline Char)+ > ~text(text) DocumentContent = (Inline | DocumentText)+:content { content } DocumentLine = DocumentContent:content Le { content } #page Page = Frontmatter?:frontmatter - (!Newpage Block)*:blocks ~page(([frontmatter] + blocks).select{ |x| !x.nil?}) Pages = Page:page Newpage:newpage Pages:pages { [ page, newpage ] + pages } | Page:page { [ page ] } #root root = Pages:pages - EofComment? Eof { pages }