<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="107653" data-post-id="107653">
  <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">
								<aside class="quote group-livebook_core_team" data-username="josevalim" data-post="64" 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>I mean this is in the nicest way possible but don’t start this gate keeping non sense.</p>
</blockquote>
</aside>
<p>This isn’t “gate-keeping nonsense”. I’m just saying that you or anyone else is not qualified to write parsers. In fact, on several occasions, I have praised the design of NimbleParsec and its composability, which is in many ways superior to ExSpirit, which is a good example of a fully general parser. NimbleParsec is also better than anything I would ever write, and also very fast, because of the way it compiles into binary pattern matches. This owes a lot to your insights on performance on the BEAM.</p>
<p>Tha said, I’d like to highlight a quote from post in thist opic:</p>
<aside class="quote group-livebook_core_team" data-username="josevalim" data-post="54" 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>NimbleParsec was never meant to be a complete parsec but it doesn’t mean it can’t be one as long as it fits within its goals.</p>
</blockquote>
</aside>
<p>This seems to have been lost in translation somwhere. I was under the impression that NimbleParsec was supposed to support (at least) the same as a PEG parser. I was under the impression that it already supported such grammars, or at least it had been designed with that goal in mind.</p>
<p>I mever got the impression that it was supposed to be a limited parser. Otherwise I’d never have suggested the context-sensitive features. Adding context-sensitivity on top of a parser that isn’t wven equivalent to a PEG parser was not one of my brightest ideas.</p>
<p>The main problem here is that parsers with different capabilities need different architectures.</p>
<p>For example, you can’t reliably parse HTML with regular expressions. Which means that if you qant to parse HTML your parser can’t be based on a regular expressions engine.</p>
<p>That’s why I think it’s important to decide which capabilities you want in your parser before commiting to an architecture.</p>
<p>From what I understand, the main goal is to compile into fast binary pattern matches. That is a perfectly valid design goal, and in no way i want to criticise that goal as invalid.</p>
<p>But, i is possible that this design will make it imposible to recognize certain patterns. And again, this is perfectly valid.</p>
<p>I just wanted to illustrate the tradeoff we’re dealing with… Was it clear?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107653" 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/73">Post #72</a>
	                </div>
	            </div>
              <div id="likers-container-107653" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107653"
                     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 #72"></div>
  </section>
</div>
    <div class="postbit" id="107673" data-post-id="107673">
  <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">
								<aside class="quote no-group" data-username="mjadczak" data-post="72" 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/mjadczak/48/3537_2.png" class="avatar"> mjadczak:</div>
<blockquote>
<p>Once you have a unified way in which all parsers either succeed or fail, you can then e.g. express <code>repeat_until</code> like I said: <code>repeat(lookahead_not(until) |&gt; to_repeat())</code> .</p>
</blockquote>
</aside>
<p>Love this! I have just verified this is actually the case and therefore removed <code>repeat_until</code> from master.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107673" 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/74">Post #73</a>
	                </div>
	            </div>
              <div id="likers-container-107673" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107673"
                     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 #73"></div>
  </section>
</div>
    <div class="postbit" id="107676" data-post-id="107676">
  <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>One last update: I have optimized bound lookaheads, so looking ahead patterns where the size is known upfront now generates only one clause, which is super efficient. This makes things like <code>repeat_until</code> more efficient than it was before using a more composable construct! v0.5 should be out in the next minutes.</p>
<aside class="quote no-group" data-username="tmbb" data-post="73" 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>In fact, on several occasions, I have praised the design of NimbleParsec and its composability</p>
</blockquote>
</aside>
<p>Indeed, thanks! <img src="https://forum.elixirforum.com/images/emoji/apple/heart.png?v=15" title=":heart:" class="emoji" alt=":heart:" loading="lazy" width="20" height="20"></p>
<aside class="quote no-group" data-username="tmbb" data-post="73" 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>This seems to have been lost in translation somwhere. I was under the impression that NimbleParsec was supposed to support (at least) the same as a PEG parser. I was under the impression that it already supported such grammars, or at least it had been designed with that goal in mind.</p>
</blockquote>
</aside>
<p>All I can say is that I never said any of this. <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>In any case, according to <a class="mention" href="/u/mjadczak" rel="nofollow">@mjadczak</a>, we should be equivalent to a PEG parser now, so hurray. If somebody is confident about this topic and want to send a PR that amends the README accordingly, please do it!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107676" data-batch-url="/posts/batch_likers">
                        4
                      </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/75">Post #74</a>
	                </div>
	            </div>
              <div id="likers-container-107676" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107676"
                     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 #74"></div>
  </section>
</div>
    <div class="postbit" id="107684" data-post-id="107684">
  <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">
								<aside class="quote group-livebook_core_team" data-username="josevalim" data-post="75" 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>All I can say is that I never said any of this. <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>
</blockquote>
</aside>
<p>No, you didn’t, but because you presented it as a (not as featureful) alternative to ExSpirit, I thought it was at least as powerful as a PEG parser. But that was not your fault.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107684" 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/76">Post #75</a>
	                </div>
	            </div>
              <div id="likers-container-107684" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107684"
                     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 #75"></div>
  </section>
</div>
    <div class="postbit" id="107688" data-post-id="107688">
  <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><a class="mention" href="/u/tmbb" rel="nofollow">@tmbb</a> Oops, apparently NimbleParsec 0.5.0 broke makeup (and ex_doc). I have written a PR here: <a href="https://github.com/tmbb/makeup/pull/18" class="inline-onebox" rel="nofollow">Depend on NimbleParsec v0.4.0 by josevalim · Pull Request #18 · elixir-makeup/makeup · GitHub</a> - can you please ship a new version?</p>
<p>It should also be relatively straight-forward to migrate to v0.5.0, you likely only need to rewrite <code>replace_until(foo, bar)</code> as <code>replace(lookahead_not(bar) |&gt; foo)</code> but I can’t look into it right now, sorry.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107688" 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/77">Post #76</a>
	                </div>
	            </div>
              <div id="likers-container-107688" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107688"
                     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 #76"></div>
  </section>
</div>
    <div class="postbit" id="107690" data-post-id="107690">
  <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">
								<aside class="quote no-group" data-username="tmbb" data-post="73" 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>I’m just saying that you or anyone else is not qualified to write parsers.</p>
</blockquote>
</aside>
<p>This sentence should have been “I’m NOT saying that you or anyone else is not qualified to write parsers”. Proofreading on mobile is hard <img src="https://forum.elixirforum.com/images/emoji/apple/stuck_out_tongue.png?v=15" title=":stuck_out_tongue:" class="emoji" alt=":stuck_out_tongue:" loading="lazy" width="20" height="20"></p>
<aside class="quote group-livebook_core_team" data-username="josevalim" data-post="77" 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>can you please ship a new version?</p>
</blockquote>
</aside>
<p>Yes, as soon as I get home.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107690" 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/78">Post #77</a>
	                </div>
	            </div>
              <div id="likers-container-107690" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107690"
                     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 #77"></div>
  </section>
</div>
    <div class="postbit" id="107748" data-post-id="107748">
  <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 group-livebook_core_team" data-username="josevalim" data-post="71" 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>Perfect. NimbleParsec is behaving the same way now. <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"> Thanks a lot!</p>
</blockquote>
</aside>
<p>Woot!</p>
<aside class="quote no-group" data-username="mjadczak" data-post="72" 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/mjadczak/48/3537_2.png" class="avatar"> mjadczak:</div>
<blockquote>
<p>I think something to keep in mind, which may be useful in working out how something “should” behave, is a standard model of whether a parser “fails” or “succeeds”. Once every single parser can be said to either “fail” or “succeed” given some input, potentially consuming some input if it succeeds, then it becomes clear— <code>repeat(p)</code> tries to let <code>p</code> consume as much input as possible, while it succeeds, and once it fails (necessarily not consuming any input), it goes to the next thing in the sequence. <code>choice([a, b, c])</code> tries to apply <code>a</code> to the input, and if it succeeds, proceeds to the next parser in the sequence. If <code>a</code> fails (not consuming input), then <code>b</code> is tried instead (and then <code>c</code> , and if all choices fail, the whole <code>choice</code> combinator fails).</p>
</blockquote>
</aside>
<p>Precisely.</p>
<p>Traditional PEG parsers are little composable functions that operate on a ‘state’ structure, that state structure holds things like the unparsed input, positioning information, returned result, metadata, etc…  ExSpirit is almost a direct translation of the ‘traditional’ PEG library, which though crazy efficient on efficient languages like C++/Rust/OCaml is less efficient on Elixir (hence why I really need to finish my Parserx version).  But each ‘function’ just takes the state and returns state, the first thing every function should do is test if the state is in a good state (no error condition) and if not then immediately return it directly (passing the existing error back) else it does whatever it needs to do and transforms the state and returns it.</p>
<p>Functions that take other functions, like <code>repeat</code> or <code>lookahead_not</code> can do things like call the input and test it’s returns state until it fails, then take all the successful <code>result</code>s and put them in a list and return them, or for <code>lookahead_not</code> it runs the function and it just returns a flipped error state from the originally passed in state (ignoring everything else of the state returned from the function).</p>
<aside class="quote no-group" data-username="mjadczak" data-post="72" 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/mjadczak/48/3537_2.png" class="avatar"> mjadczak:</div>
<blockquote>
<p>Once you have a unified way in which all parsers either succeed or fail, you can then e.g. express <code>repeat_until</code> like I said: <code>repeat(lookahead_not(until) |&gt; to_repeat())</code> . The inner parser <code>p</code> in this case is <code>lookahead_not(until) |&gt; to_repeat()</code> (where we’ve assumed that <code>to_repeat()</code> will consume some input, like a string or whatever). The outer <code>repeat</code> passes its current input to this <code>p</code> . The <code>lookahead_not</code> checks whether the immediate input (i.e. whatever’s at the start of the current binary) matches <code>until</code> . Let’s say at first it doesn’t. So <code>lookahead_not</code> succeeds, but does not consume any input—it lets <code>to_repeat()</code> consume it instead. Now the binary has moved along, and <code>repeat</code> gives it to <code>p</code> again. <code>lookahead_not</code> passes this input to <code>until</code> , and it matches! <code>lookahead_not</code> discards the results (accumulator) and also pretends the input was never consumed, but fails. Now <code>repeat</code> knows to succeed (it always succeeds, because it’s a 0 or more repetition) instead of to keep repeating.</p>
</blockquote>
</aside>
<p>Close enough yeah, it’s more like the transforming ‘piped data’ flow I described above internally in most implementations.  <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="mjadczak" data-post="72" 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/mjadczak/48/3537_2.png" class="avatar"> mjadczak:</div>
<blockquote>
<p>Now, obviously if you actually implemented it like this, you would no longer have a super-efficient pattern-matching parser, but just yet-another-PEG parser which needs to interpret all of this information at runtime. Hence, I’m not necessarily saying that each parser/combinator should actually explicitly return an <code>:ok</code> or <code>:error</code> which is matched on. Rather, I’m saying that this is a good mental model of what is happening, and should help to answer questions like “how should this combination of parsers behave”?</p>
</blockquote>
</aside>
<p>It’s possible to make a pattern matching version of it though with a lot more code generation, I started working on such a thing in the Parserx version but never continued it since NimbleParsec came out that mostly completed the same thing (though with significantly fewer features), so I figured I could use NimbleParsec where it is good and mine where it was necessary (I’ve even used them together, NimbleParsec is very usable from within ExSpirit ^.^).</p>
<aside class="quote no-group" data-username="mjadczak" data-post="72" 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/mjadczak/48/3537_2.png" class="avatar"> mjadczak:</div>
<blockquote>
<p>Regardless, the commit looks good, especially now you’ve got the behaviour with <code>repeat</code> worked out. I’m looking forward to trying it out! I’m currently tinkering with trying to implement a full-featured (spec-compliant) XML parser using NimbleParsec <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>
</blockquote>
</aside>
<p>Yeesh, you’ll need multiple passes for that.  You cannot represent a proper XML parser in PEG without state handling, thus meaning you have to use multiple passes.  Like I made a mini-xml parser (no attributes) in ExSpirit as an example at <a href="https://github.com/OvermindDL1/ex_spirit/blob/master/examples/simple_xml.exs" class="inline-onebox" rel="noopener nofollow ugc">ex_spirit/examples/simple_xml.exs at master · OvermindDL1/ex_spirit · GitHub</a> and you can see the required state work for accurate parsing in it:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">
defmodule SimpleXML do
  use ExSpirit.Parser, text: true

  defrule text( chars(-?&lt;) )

  defrule tag_name( chars([?a..?z, ?A..?Z, ?0..?9, ?_, ?-]) )

  defrule tag(
    lit(?&lt;) |&gt; tag_name() |&gt; put_state(:tagname, :result) |&gt; lit(?&gt;) |&gt; expect(seq([
      get_state_into(:tagname, tag(&amp;1, repeat(node_()))),
      lit("&lt;/"), get_state_into(:tagname, lit(&amp;1)), lit(?&gt;)
    ]))
  )

  defrule node_(
    alt([
      tag(),
      text(),
    ])
  )

  def from_string(input) do
    parse(input, node_())
  end

end
</code></pre>
<p>You can see that when it parses the tag_name then it puts it into the state on that current rulestack of the name <code>:tagname</code>, then it pulls the <code>:tagname</code> state into two different places, first is into a <code>tag</code>, which just wraps the children so an XML node of <code>&lt;blah&gt;children&lt;/blah&gt;</code> becomes <code>{"blah", children}</code>, and also into the closing tag, so an opening <code>&lt;blah&gt;</code> <em>has</em> to match a closing <code>&lt;/blah&gt;</code> or compilation fails.  As per the example run of it:</p>
<pre><code class="lang-plaintext">$ mix run examples/simple_xml.exs
Input a single line of xml-like syntax:
&lt;test1&gt;Some text&lt;test2&gt;Hi&lt;/test2&gt; and more&lt;/test1&gt;
Result: {"test1", ["Some text", {"test2", ["Hi"]}, " and more"]}

$ mix run examples/simple_xml.exs
Input a single line of xml-like syntax:
&lt;a-tag&gt;How about an improperly terminated tag&lt;/b-tag&gt;
&lt;unknown&gt;:1:48: Expectation Failure: literal `a-tag` did not match the input
        RuleStack: [tag, node_]
        Input: b-tag&gt;

$ mix run examples/simple_xml.exs
Input a single line of xml-like syntax:
&lt;
&lt;unknown&gt;:1:1: Parse error: Repeating over a parser failed due to not reaching the minimum amount of 1 with only a repeat count of 0
        RuleStack: [text, node_]
        Input: &lt;
</code></pre>
<p>And it can easily be decorated to transform error messages into something more domain-specific like <code>closing tag does not match opening tag</code> or something as well by decorating the PEG commands with another.  All single pass.  This is why I say that state handling is so extremely important in PEG parsers and why all of them have some form of state handling.  I can trivially make a calculator in ExSpirit that let’s you define variables, calculate, etc… all in a single pass.  I’ve <em>already</em> made a single pass Lisp (with macro’s and read-macro!) and Forth parsers in ExSpirit and all.  <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="73" 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 what I understand, the main goal is to compile into fast binary pattern matches. That is a perfectly valid design goal</p>
</blockquote>
</aside>
<p>ExSpirit’s goal was supposed to be a Traditional PEG Parser, I tried to make it fast (and it was faster than all others in Elixir until NimbleParsec came along) but accuracy was my first goal (and there are still a couple of niggles I’m not happy with that Parserx was supposed to fix as well).</p>
<aside class="quote group-livebook_core_team" data-username="josevalim" data-post="74" 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>Love this! I have just verified this is actually the case and therefore removed <code>repeat_until</code> from master.</p>
</blockquote>
</aside>
<p>Make sure to bump the major version!  ^.^</p>
<aside class="quote group-livebook_core_team" data-username="josevalim" data-post="75" 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>One last update: I have optimized bound lookaheads, so looking ahead patterns where the size is known upfront now generates only one clause, which is super efficient. This makes things like <code>repeat_until</code> more efficient than it was before using a more composable construct! v0.5 should be out in the next minutes.</p>
</blockquote>
</aside>
<p>Ooo, very cool!  I really should flesh out the Parserx branch sometime…  ^.^;</p>
<aside class="quote group-livebook_core_team" data-username="josevalim" data-post="75" 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>In any case, according to <a class="mention" href="/u/mjadczak" rel="nofollow">@mjadczak</a>, we should be equivalent to a PEG parser now, so hurray. If somebody is confident about this topic and want to send a PR that amends the README accordingly, please do it!</p>
</blockquote>
</aside>
<p>Eh, almost, it’s missing a couple of features still, like <code>expect</code> is absolutely necessary to have proper errors at the correct locations in many cases and state handling is extremely important in many types of parsers or you can’t get context-sensitive parsers to work without multiple passes (which often makes errors significantly more inaccurate as well as overall slower).  Maybe a couple other things but those are the biggies.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107748" 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/79">Post #78</a>
	                </div>
	            </div>
              <div id="likers-container-107748" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107748"
                     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 #78"></div>
  </section>
</div>
    <div class="postbit" id="107751" data-post-id="107751">
  <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">
								<aside class="quote no-group" data-username="OvermindDL1" data-post="79" 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/overminddl1/48/2677_2.png" class="avatar"> OvermindDL1:</div>
<blockquote>
<p>Eh, almost, it’s missing a couple of features still</p>
</blockquote>
</aside>
<p>I am going by the definition here: <a href="https://en.wikipedia.org/wiki/Parsing_expression_grammar#Syntax" class="inline-onebox" rel="nofollow">Parsing expression grammar - Wikipedia</a></p>
<p>If you have some time, can you please expand on what I am missing? If you could provide a reference, even better!</p>
<aside class="quote no-group" data-username="OvermindDL1" data-post="79" 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/overminddl1/48/2677_2.png" class="avatar"> OvermindDL1:</div>
<blockquote>
<p>state handling is extremely important in many types of parsers or you can’t get context-sensitive parsers to work without multiple passes</p>
</blockquote>
</aside>
<p>We state-handling via <code>traverse</code> and <code>repeat_while</code>. I.e. it is possible to pass a context around, with your own state, as nimble parsec operates. What am I missing here too?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107751" 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/80">Post #79</a>
	                </div>
	            </div>
              <div id="likers-container-107751" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107751"
                     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 #79"></div>
  </section>
</div>
    <div class="postbit" id="107757" data-post-id="107757">
  <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">
								<aside class="quote no-group" data-username="OvermindDL1" data-post="79" 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/overminddl1/48/2677_2.png" class="avatar"> OvermindDL1:</div>
<blockquote>
<p>Eh, almost, it’s missing a couple of features still, like <code>expect</code> is absolutely necessary to have proper errors at the correct locations in many cases and state handling is extremely important in many types of parsers</p>
</blockquote>
</aside>
<aside class="quote group-livebook_core_team quote-modified" data-username="josevalim" data-post="80" 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>I am going by the definition here: <a href="https://en.wikipedia.org/wiki/Parsing_expression_grammar#Syntax" class="inline-onebox" rel="noopener nofollow ugc">Parsing expression grammar - Wikipedia</a></p>
</blockquote>
</aside>
<p><a class="mention" href="/u/overminddl1" rel="nofollow">@OvermindDL1</a> is mixing a couple things that make his post confusing. A PEG parser is something that abides by the definition above. PEG parsers don’t need to keep state and they don’t need to recognize context-sensitive languages.</p>
<p>I believe they also don’t require the <code>expect</code> combinator to be considered PEG parsers. It’s just something that’s nice to have. Currently, NimbleParsec handles all errors as something that says that you should try the next parser. But sometimes, you might have an error in which you want to stop parsing altogether instead of keep trying. That saves you time (because you interrupt the parsing process) and gives better error messages. Basically, <code>expect</code> is a convenience combinator which raises an exception which halts parsing completely (and could even be implemented as such).</p>
<p>So, there are two things here:</p>
<ol>
<li>
<p>State handling, <em>à la</em> Spirit, to recognize things like indentation, matching XML tags, etc</p>
</li>
<li>
<p>The <code>expect</code> handler</p>
</li>
</ol>
<p>None of which are strictly required in a PEG parser. The first makes your parser more powerful than a PEG parser and the second one is just a convenience.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107757" 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/81">Post #80</a>
	                </div>
	            </div>
              <div id="likers-container-107757" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107757"
                     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 #80"></div>
  </section>
</div>
    <div class="postbit" id="107770" data-post-id="107770">
  <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>Thank you <a class="mention" href="/u/tmbb" rel="nofollow">@tmbb</a> for explaining! I think the <code>expect</code> handler should be straight-forward to implement. For the state stuff, I will wait for use cases as usual. <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="107770" 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/82">Post #81</a>
	                </div>
	            </div>
              <div id="likers-container-107770" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107770"
                     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 #81"></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=9">Load more posts (61 remaining)</a>
</div></template></turbo-stream>