title: Opening and closing elements in LPEG for Pandoc Reader
body: <p>I am working on a simple Pandoc reader that can process some of the basic html-like syntax used in forums (such as <code>[b]bold[/b]</code> and <code>[h1]Header[/h1]</code>).</p>
  <p>I managed to get a basic reader working with LPEG (as described in the pandoc documentation), but the solution I landed on feels clunky. Is there better way to define the grammar around start and end tags (using things like priorities or negative lookahead, or LPEG groupings)?</p>
  <p>Here was what I was able to get working:</p>
  <pre class="lang-lua prettyprint-override"><code>local P, S, R, Cf, Cc, Ct, V, Cs, Cg, Cb, B, C, Cmt =
    lpeg.P, lpeg.S, lpeg.R, lpeg.Cf, lpeg.Cc, lpeg.Ct, lpeg.V,
    lpeg.Cs, lpeg.Cg, lpeg.Cb, lpeg.B, lpeg.C, lpeg.Cmt
  
  local whitespacechar = S(&quot; \t\r\n&quot;)
  local wordchar = (1 - whitespacechar)
  local spacechar = S(&quot; \t&quot;)
  local newline = P&quot;\r&quot;^-1 * P&quot;\n&quot;
  local blanklines = newline * (spacechar^0 * newline)^1
  local endline = newline - blanklines
  local emph_start = P&quot;[i]&quot;
  local emph_end = P&quot;[/i]&quot;
  local strong_start = P&quot;[b]&quot;
  local strong_end = P&quot;[/b]&quot;
  local header_start = P&quot;[h&quot; * (R&quot;17&quot; / tonumber) * &quot;]&quot; 
  local header_end = P&quot;[/h&quot; * R&quot;17&quot; * &quot;]&quot;
  local tag_start = emph_start + strong_start + header_start
  local tag_end = emph_end + strong_end + header_end
  
  -- Grammar
  G = P{ &quot;Pandoc&quot;,
    Pandoc = Ct(V&quot;Block&quot;^0) / pandoc.Pandoc;
    Block = blanklines^0 * (V&quot;Header&quot; + V&quot;Para&quot;) ;
    Para = Ct(V&quot;Inline&quot;^1) / pandoc.Para;
    Inline = V&quot;Emph&quot; + V&quot;Strong&quot; + V&quot;Str&quot; + V&quot;Space&quot; + V&quot;SoftBreak&quot; ;
    Str = (1 - (whitespacechar + tag_end + tag_start))^1 / pandoc.Str;
    Space = spacechar^1 / pandoc.Space;
    SoftBreak = endline / pandoc.SoftBreak;
    Emph = emph_start * Ct(V&quot;Inline&quot;^1) * emph_end / pandoc.Emph;
    Strong = strong_start * Ct(V&quot;Inline&quot;^1) * strong_end / pandoc.Strong;
    Header = header_start * Ct(V&quot;Inline&quot;^1) * header_end / pandoc.Header;
  }
  
  function Reader(input)
    return lpeg.match(G, input)
  end
  </code></pre>
  <p>And here's the kind of text I'd like to transfrom:</p>
  <pre><code>[h1]A Test[/h1]
  The [i]quick[/i] dog jumped over the lazy stream!
  Tags should be able to be applied [b]mid[/b]word.
  </code></pre>