<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="72630" data-post-id="72630">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<blockquote>
<p>start with the smaller language you currently handle</p>
</blockquote>
<p><em>Smallest</em> language? Currently I only handle HTML5 (without CSS and Javascript, those are in the making) and Elixir. The smallest language would be HTML, which has the “benefit” of using a context-sensitive approach. That’s a good idea.</p>
<p>(EDIT:  have other lexers “almost ready” but still not good enough for publication)</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="72630" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nimbleparsec-a-simple-and-fast-parser-combinator-for-elixir/12860/32">Post #31</a>
	                </div>
	            </div>
              <div id="likers-container-72630" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="72630"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #31"></div>
  </section>
</div>
    <div class="postbit" id="72631" data-post-id="72631">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I still have to study NimbleParsex a little better, because it’s quite a mental shift from ExSpirit to NimbleParsec (which operates inside the constraints of the BEAM)</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="72631" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nimbleparsec-a-simple-and-fast-parser-combinator-for-elixir/12860/33">Post #32</a>
	                </div>
	            </div>
              <div id="likers-container-72631" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="72631"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #32"></div>
  </section>
</div>
    <div class="postbit" id="72642" data-post-id="72642">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="josevalim" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/120/1787_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  josevalim
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Elixir</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Oops, yes, <em>smallest</em>. <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>HTML5 sounds like a great start. Although Nimble compiles and runs faster than ExSpirit for things like datetime, there is no guarantee it is also faster when handling languages like HTML5. So we being able to validate that would be useful.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="72642" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nimbleparsec-a-simple-and-fast-parser-combinator-for-elixir/12860/34">Post #33</a>
	                </div>
	            </div>
              <div id="likers-container-72642" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="72642"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #33"></div>
  </section>
</div>
    <div class="postbit" id="72648" data-post-id="72648">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Eiji" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Eiji/120/36743_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Eiji
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote group-livebook_core_team" data-username="josevalim" data-post="34" data-topic="12860">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/48/1787_2.png" class="avatar"> josevalim:</div>
<blockquote>
<p>HTML5 sounds like a great start. Although Nimble compiles and runs faster than ExSpirit for things like datetime, there is no guarantee it is also faster when handling languages like HTML5. So we being able to validate that would be useful.</p>
</blockquote>
</aside>
<p>For all interested in creating <strong>valid</strong> HTML5 parser: it’s not as easy as it looks. Let me share here some useful links:</p>
<ol>
<li><a href="https://webkit.org/blog/68/understanding-html-xml-and-xhtml/" rel="noopener nofollow ugc">Understanding HTML, XML and XHTML</a> article</li>
<li><a href="https://html.spec.whatwg.org/multipage/parsing.html" rel="noopener nofollow ugc">Parsing HTML documents</a> - it’s part of specification (chapter <code>12.2</code>) about parsing HTML documents from <code>WHATWG</code> community</li>
</ol>
<p><a class="mention" href="/u/josevalim" rel="nofollow">@josevalim</a>: I think that 2nd link could be helpful for you (if you have time to read it), because you can look at parsing HTML documents (i.e. it’s much more complicated than simple datetime parsers) step by step, so you can check if making such advanced parser is doable using your library. Hope it’s helpful resource.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="72648" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nimbleparsec-a-simple-and-fast-parser-combinator-for-elixir/12860/35">Post #34</a>
	                </div>
	            </div>
              <div id="likers-container-72648" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="72648"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #34"></div>
  </section>
</div>
    <div class="postbit" id="72652" data-post-id="72652">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="josevalim" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/josevalim/120/1787_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  josevalim
                    <span class="op-star" title="Thread Starter">
                      <img alt="OP" class="op-star-icon" src="/assets/thread-icons/thread-icon-thread-starter-df91e872.png" />
                    </span>
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>Creator of Elixir</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thanks <a class="mention" href="/u/eiji" rel="nofollow">@Eiji</a>, I will take a look at it.</p>
<p>Although I think <a class="mention" href="/u/tmbb" rel="nofollow">@tmbb</a> will find out the limitations of nimble faster than me. <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<p>Btw, if someone is looking for fun things to do with NimbleParsec, we have a simple markdown parser in Elixir that converts markdown to ANSI code: <a href="https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/io/ansi/docs.ex" class="inline-onebox" rel="nofollow">elixir/lib/elixir/lib/io/ansi/docs.ex at main · elixir-lang/elixir · GitHub</a></p>
<p>I think we can have a nicer approach with NimbleParsec if we first parse the markdown into tokens <em>and only then</em> format it to ansi. Unfortunately Elixir cannot depend on NimbleParsec but since NimbleParsec emits code without a runtime dependency in itself, it means we can emit the parser code and just embed it in Elixir. <img src="https://forum.elixirforum.com/images/emoji/apple/smiley.png?v=15" title=":smiley:" class="emoji" alt=":smiley:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="72652" data-batch-url="/posts/batch_likers">
                        5
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nimbleparsec-a-simple-and-fast-parser-combinator-for-elixir/12860/36">Post #35</a>
	                </div>
	            </div>
              <div id="likers-container-72652" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="72652"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #35"></div>
  </section>
</div>
    <div class="postbit" id="72994" data-post-id="72994">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="OvermindDL1" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/OvermindDL1/120/2677_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  OvermindDL1
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Yep, parsing HTML5 ‘properly’ is <em>hell</em> itself.  ^.^;</p>
<p>However, doing lax SGML-style parsing along with the optional header element will grab 99%+ of all constructs.  <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="72994" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nimbleparsec-a-simple-and-fast-parser-combinator-for-elixir/12860/37">Post #36</a>
	                </div>
	            </div>
              <div id="likers-container-72994" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="72994"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #36"></div>
  </section>
</div>
    <div class="postbit" id="76296" data-post-id="76296">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="tmbb" src="/assets/icons/user-9f439610.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  tmbb
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’m the author of Makeup (a library for syntax highlighting of source code) and ExDocMakeup (a markdown processor that can be used with ExDoc that uses Makeup for syntax highlighting of code examples in the docs). It was a discussion around Makeup that initially prompted the development of NimbleParsec. Up until the most recent version, Makeup used to depend on the ExSpirit library by <a class="mention" href="/u/overminddl1" rel="nofollow">@OvermindDL1</a>, which is much more flexible than NimbleParsec (as the discussion above shows), but much, much slower.</p>
<p>Using Benchee, I’ve prepared some benchmarks pitting the current version of Makeup (0.4.0) against the old version. I’ve gotten aproximately 10x speedups in both compilation time and runtime.</p>
<p>Here’s how to interpret the benchmarks below:</p>
<ul>
<li>Formatter performance: the part that takes up a list of tokens and converts it into an HTML fragment</li>
<li>Lexer: the part that reads the raw source code and produces a list of tokens</li>
<li>Lexer compilation time: this was done by invoking the Elixir compiler at runtime on the relevant file. This is a good proxy measure of the “real” compilation process (it’s pretty cool that’s so easy to compile code at runtime in Elixir - never us this in production, though!)</li>
</ul>
<p>The most important number is the “Lexer + Formatter”, because that’s what the user will do most of the time. The benchmarks use a fake elixir file with about 250 lines written by the authors of the python library Pygments (which is similar to makeup) to demonstrate most of the syntax rules.</p>
<p>ExSpirit (old version):</p>
<pre><code class="lang-plaintext">Name                                                              ips        average  deviation         median         99th %
Formatter performance                                          124.40        8.04 ms    ±97.25%          15 ms          16 ms
Reading file from disk + Lexer + Formatter (end to end)          7.29      137.24 ms     ±7.99%         140 ms         172 ms
Lexer performance                                                7.18      139.33 ms     ±9.72%         140 ms         157 ms
Lexer + Formatter                                                6.83      146.43 ms    ±10.56%         141 ms         187 ms
Lexer compilation time                                         0.0355       28156 ms     ±0.00%       28156 ms       28156 ms
</code></pre>
<p>NimbleParsec (new version):</p>
<pre><code class="lang-plaintext">Name                                                              ips        average  deviation         median         99th %
Formatter performance                                          620.02        1.61 ms    ±32.96%        1.60 ms        3.20 ms
Lexer performance                                              108.31        9.23 ms     ±4.86%        9.40 ms        9.40 ms
Lexer + Formatter                                               94.72       10.56 ms    ±69.37%          15 ms          16 ms
Reading file from disk + Lexer + Formatter (end to end)         92.32       10.83 ms    ±66.61%          15 ms          16 ms
Lexer compilation time                                           0.26     3812.50 ms     ±0.01%     3812.50 ms        3813 ms
</code></pre>
<p>The secret to the Formatter’s performance improvements was to use iolists whenever possible instead of binaries after a suggestion by <a class="mention" href="/u/josevalim" rel="nofollow">@josevalim</a> I’d never have thought that the difference would be so great. It turns out that concatenating strings on the BEAM is very slow and requires lots of copying. <a class="mention" href="/u/josevalim" rel="nofollow">@josevalim</a> has been extremely helpful in suggesting improvements to the lexer, answering questions about NimbleParsec and giving useful tips on how to increase performance of my library.</p>
<p>Performance improvements in the lexer were mainly due to the use of NimbleParsec (and to an obsessive amount of microbenchmaking). The performance of my lexer is now pretty much the same as the performance of the Elixir formatter, which means there are probably very little gains to be had. Makeup is quite similar to the Elixir formatter in that it parses files and prints a beautified version of the output. It was also written by people which are probably smarter than me and which have some actual knowledge of the internals of the BEAM.</p>
<p>This newest version of Makeup itself is not yet ready for prime time. You can help by running it on examples of real elixir code, inspecting the output and submitting an issue with examples tha look wrong. Such examples can be included in the test suite, which sadly doesn’t cover all syntax rules yet (and may never cover all rule combinations, that’s why it’s important to run it on real code to spot issues).</p>
<p>All of this will be easier after I’ve updated the docs with more useful information.</p>
<p>From my experience in the last few days, NimbleParsec seems to be ready to be used for real projects. It’s the ideal option for those who need to parse context-free languages, and with some postprocessing steps it can be used to help parse some context-sensitive ones. I don’t believe I’ve found any bug while using it for Makeup.</p>
<p>Thanks to <a class="mention" href="/u/josevalim" rel="nofollow">@josevalim</a> for writing this great library and for all the help and to <a class="mention" href="/u/overminddl1" rel="nofollow">@OvermindDL1</a> who’s written ExSpirit, without which Makeup would have never been written. Although quite slow, ExSpirit is way faster than almost anything out there and is still the only Elixir parser library that supports parsing context-sensitive languages.</p>
<p>If you’ll only take away one thing from this post, take this: string concatenation is slow. Iolists are the secret sauce that will make your programs go fast. Don’t replace your code without benchmarking it, though. Performance on the BEAM is weird, don’t trust your instincts from other languages.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="76296" data-batch-url="/posts/batch_likers">
                        12
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nimbleparsec-a-simple-and-fast-parser-combinator-for-elixir/12860/39">Post #38</a>
	                </div>
	            </div>
              <div id="likers-container-76296" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="76296"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #38"></div>
  </section>
</div>
    <div class="postbit" id="76577" data-post-id="76577">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="OvermindDL1" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/OvermindDL1/120/2677_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  OvermindDL1
                  </h3>
		          </div>
						
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<aside class="quote no-group" data-username="tmbb" data-post="39" data-topic="12860">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/t/77aa72/48.png" class="avatar"> tmbb:</div>
<blockquote>
<p>It turns out that concatenating strings on the BEAM is very slow and requires lots of copying.</p>
</blockquote>
</aside>
<p>+++</p>
<p>Yeah definitely should be outputting IOlists, even with ExSpirit.  ^.^;</p>
<aside class="quote no-group" data-username="tmbb" data-post="39" data-topic="12860">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/t/77aa72/48.png" class="avatar"> tmbb:</div>
<blockquote>
<p>From my experience in the last few days, NimbleParsec seems to be ready to be used for real projects. It’s the ideal option for those who need to parse context-free languages, and with some postprocessing steps it can be used to help parse some context-sensitive ones. I don’t believe I’ve found any bug while using it for Makeup.</p>
</blockquote>
</aside>
<p>I’m really curious about when it will be able to parse context-sensitive languages, then it can fully replace ExSpirit and I can deprecate it (less stuff for me to manage/update, the better!).  <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p>
<aside class="quote no-group" data-username="tmbb" data-post="39" data-topic="12860">
<div class="title">
<div class="quote-controls"></div>
<img alt="" width="24" height="24" src="https://forum.elixirforum.com/letter_avatar_proxy/v4/letter/t/77aa72/48.png" class="avatar"> tmbb:</div>
<blockquote>
<p>Thanks to <a class="mention" href="/u/josevalim" rel="nofollow">@josevalim</a> for writing this great library and for all the help and to <a class="mention" href="/u/overminddl1" rel="nofollow">@OvermindDL1</a> who’s written ExSpirit, without which Makeup would have never been written. Although quite slow, ExSpirit is way faster than almost anything out there and is still the only Elixir parser library that supports parsing context-sensitive languages.</p>
</blockquote>
</aside>
<p>Heh thanks, it was birthed because I needed it and nothing else out supported the features I needed.  ^.^</p>
<p>I <em>really</em> want NimbleParsec to replace it, needs a few more features to be able to do that though.  <img src="https://forum.elixirforum.com/images/emoji/apple/slight_smile.png?v=15" title=":slight_smile:" class="emoji" alt=":slight_smile:" loading="lazy" width="20" height="20"></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="76577" data-batch-url="/posts/batch_likers">
                        6
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nimbleparsec-a-simple-and-fast-parser-combinator-for-elixir/12860/40">Post #39</a>
	                </div>
	            </div>
              <div id="likers-container-76577" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="76577"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #39"></div>
  </section>
</div>
    <div class="postbit" id="95849" data-post-id="95849">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="kip" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/kip/120/1440_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  kip
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>ex_cldr Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>I’m rewriting (for the 3rd time!) the language tag parser in <a href="https://github.com/kipcole9/cldr" rel="nofollow">ex_cldr</a> using <code>nimble_parsec</code>.  One challenge I have is that the ABNF grammar has a couple of irregularities.  For example:</p>
<p><code>zh-yue-HK</code> means Chinese, Cantonese variant, as spoken in Hong Kong.  Notice that the “language extensions” <code>yue</code> is three alpha characters.</p>
<p><code>zh-Hant-HK</code> means Chinese, using the traditional Chinese script.  Note that the <code>script</code> is four alpha characters.</p>
<p>The grammar for this part of the language tag is:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">   langtag       = language
                   ["-" script]

   language      = 2*3ALPHA            ; shortest ISO 639 code
                   ["-" extlang]       ; sometimes followed by
                                       ; extended language subtags

   extlang       = 3ALPHA              ; selected ISO 639 codes
                   *2("-" 3ALPHA)      ; permanently reserved

   script        = 4ALPHA              ; ISO 15924 code
</code></pre>
<p>The issue I’m facing is that if there is a <code>script</code> but no <code>extlang</code> the <code>extlang</code> parser will consume the first three characters of the <code>script</code> and then fail with a parse error. For example <code>zh-Hant-HK</code> will be parsed as language <code>zh</code>, language extension <code>Han</code> and then fail in parsing <code>t-HK</code>.</p>
<p>I thought the <code>lookahead</code> macro would help here - I can look ahead in the stream and if the next character isn’t a <code>-</code> then I can fail the <code>extlang</code> parser.  But … I can only <code>{:error, _}</code> the whole parse tree - not fail this one parser.</p>
<p>Is there another alternative approach I can use to <code>{:fail, _}</code> a parser without terminating the full parse?</p>
<p>The <a href="https://github.com/kipcole9/cldr/blob/master/lib/cldr/language_tag/rfc5646.ex#L67-L90" rel="nofollow">relevant code is here</a>.  Any and all comments welcome.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="95849" data-batch-url="/posts/batch_likers">
                        1
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nimbleparsec-a-simple-and-fast-parser-combinator-for-elixir/12860/41">Post #40</a>
	                </div>
	            </div>
              <div id="likers-container-95849" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="95849"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #40"></div>
  </section>
</div>
    <div class="postbit" id="95851" data-post-id="95851">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="Qqwy" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/Qqwy/120/1349_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  Qqwy
                  </h3>
		          </div>
						
			          <div class="user-title">
									<span>TypeCheck Core Team</span>
			          </div>
						</div>
					
					</div>

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>It might be worthwhile to attempt to switch the order of the parsers, such that <code>extlang</code> will only be used when there really are only three characters.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="95851" data-batch-url="/posts/batch_likers">
                        0
                      </span>
                      <!-- <span class="thread-count js-solved-indicator" title="Marked as solution"></span> -->
	                </div>
	                <div class="go-to-post">
	                  <a title="Go to post" alt="Go to post" href="https://forum.elixirforum.com/t/nimbleparsec-a-simple-and-fast-parser-combinator-for-elixir/12860/42">Post #41</a>
	                </div>
	            </div>
              <div id="likers-container-95851" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="95851"
                     data-batch-url="/posts/batch_likers">
                  <div class="post-likers"></div>
                </div>
              </div>
	        </div>
			

    </div>

    <div class="triangle-top-right type-standard-post cat-standard-post" title="Post #41"></div>
  </section>
</div>
</template></turbo-stream><turbo-stream action="replace" target="load-more-container"><template><div id="load-more-container" class="load-more-container">
    <a class="load-more-button" data-turbo-stream="true" href="/topics/12860/load_more?page=5">Load more posts (101 remaining)</a>
</div></template></turbo-stream>