<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="107596" data-post-id="107596">
  <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="mjadczak" data-post="52" 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>Even if it’s not an exact implementation of PEG, it would be reasonable to expect that NimbleParsec should be equal in “parsing power”, if you will, to a PEG parser—that is, admit any languages which a PEG parser does.</p>
</blockquote>
</aside>
<p>I agree, and although NimbleParsec has replaced a little bit of my <a href="https://hex.pm/packages/ex_spirit" rel="nofollow">ExSpirit</a> library usages, but I still use ExSpirit on occasion just because NimbleParsec can’t handle some things as well (especially around state information).</p>
<p>The issues in your post are for NimbleParsec supposed to be done by a secondary pass, it’s not a single-pass parsing library (which loses a lot of it’s capabilities).</p>
<p>I’m sure Jose would be up for accepting PR’s to integrate the features that my ExSpirit library has, the state handling capabilities would be a <em>HUGE</em> boon for me and I could drop ExSpirit if it’s features were ported over.  <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>For note, that same example in ExSpirit (give or take, should actually be parsing out whatever comes after <code>if</code>/<code>while</code>):</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">iex(1)&gt; defmodule Testing do
...(1)&gt;   use ExSpirit.Parser, text: true
...(1)&gt; 
...(1)&gt;   defrule identifier(tag(:id, chars([?a..?z, ?A..?Z, ?0..?9], 1)))
...(1)&gt;   
...(1)&gt;   defrule keywords(context) do
...(1)&gt;     symbols_ =
...(1)&gt;       ExSpirit.TreeMap.new()
...(1)&gt;       |&gt; ExSpirit.TreeMap.add_text("if", :if) # Value can be a function to return a parser
...(1)&gt;       |&gt; ExSpirit.TreeMap.add_text("while", :while) # Value can be a function to return a parser
...(1)&gt;     context |&gt; symbols(symbols_) |&gt; lookahead_not(identifier()) # Should actually parse the if/while instead...
...(1)&gt;   end
...(1)&gt;   
...(1)&gt;   defrule expr(alt([
...(1)&gt;     keywords(),
...(1)&gt;     identifier(),
...(1)&gt;   ]))
...(1)&gt; end
{:module, Testing,
 &lt;&lt;70, 79, 82, 49, 0, 0, 127, 188, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 3, 7,
   0, 0, 0, 84, 14, 69, 108, 105, 120, 105, 114, 46, 84, 101, 115, 116, 105,                                                          
   110, 103, 8, 95, 95, 105, 110, 102, 111, 95, ...&gt;&gt;, {:expr, 1}}
iex(2)&gt; import ExSpirit.Parser
ExSpirit.Parser
iex(3)&gt; parse("if", Testing.identifier)
%ExSpirit.Parser.Context{
  column: 3,
  error: nil,
  filename: "&lt;unknown&gt;",
  line: 1,
  position: 2,
  rest: "",
  result: {:id, "if"},
  rulestack: [],
  skipper: nil,
  state: %{},
  userdata: nil
}
iex(4)&gt; parse("if", Testing.identifier).result
{:id, "if"}
iex(5)&gt; parse("iffy", Testing.identifier).result
{:id, "iffy"}
iex(6)&gt; parse("if", Testing.expr).result
:if
iex(7)&gt; parse("iffy", Testing.expr).result
{:id, "iffy"}
</code></pre>
<p>I should probably just finish my <code>ExSpirit.Parserx</code> rewrite (which started just before NimbleParsec came out) as it is faster.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107596" 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/53">Post #52</a>
	                </div>
	            </div>
              <div id="likers-container-107596" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107596"
                     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 #52"></div>
  </section>
</div>
    <div class="postbit" id="107600" data-post-id="107600">
  <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/mjadczak" rel="nofollow">@mjadczak</a>. This was a very interesting and entertaining read!</p>
<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>
<p>You are correct that today lookahead can only “error” and I would probably keep the error semantics. It is also worth saying that lookahead is implemented on top of <code>traverse</code>. Maybe we can introduce <code>{:deny, ...}</code> to traverse, at least as a starting point, and that should make certain designs possible.</p>
<p>Here is a diff that allows just that:</p>
<pre data-code-wrap="diff"><code class="lang-diff">diff --git a/lib/nimble_parsec/compiler.ex b/lib/nimble_parsec/compiler.ex
index 842ab6f..c0c0233 100644
--- a/lib/nimble_parsec/compiler.ex
+++ b/lib/nimble_parsec/compiler.ex
@@ -277,12 +277,24 @@ defmodule NimbleParsec.Compiler do
     quote(do: unquote(next)(rest, acc, stack, context, line, offset))
   end

-  defp traverse(traversal, next, rest, user_acc, context, line, offset, _) do
+  defp traverse(traversal, next, rest, user_acc, context, line, offset, config) do
     case apply_traverse(traversal, rest, user_acc, context, line, offset) do
-      {user_acc, ^context} when user_acc != :error -&gt;
+      {user_acc, ^context} when not is_atom(user_acc) -&gt;
         quote(do: unquote(next)(rest, unquote(user_acc) ++ acc, stack, context, line, offset))

       quoted -&gt;
+        deny =
+          case config do
+            %{catch_all: nil} -&gt;
+              quote do: {:error, reason, rest, context, line, offset}
+
+            %{catch_all: next, acc_depth: n} -&gt;
+              {_, _, _, body} = build_proxy_to(:unused, next, n)
+              body
+          end
+
         quote do
           case unquote(quoted) do
             {user_acc, context} when is_list(user_acc) -&gt;
@@ -290,6 +302,9 @@ defmodule NimbleParsec.Compiler do

             {:error, reason} -&gt;
               {:error, reason, rest, context, line, offset}
+
+            {:deny, reason} -&gt;
+              unquote(deny)
           end
         end
     end
@@ -299,7 +314,8 @@ defmodule NimbleParsec.Compiler do
     apply_traverse(Enum.reverse(mfargs), rest, {acc, context}, line, offset)
   end

-  defp apply_traverse([mfargs | tail], rest, {acc, context}, line, offset) when acc != :error do
+  defp apply_traverse([mfargs | tail], rest, {acc, context}, line, offset)
+       when not is_atom(acc) do
     acc_context = apply_mfa(mfargs, [rest, acc, context, line, offset])
     apply_traverse(tail, rest, acc_context, line, offset)
   end
@@ -674,7 +690,7 @@ defmodule NimbleParsec.Compiler do
         {traverse_line, traverse_offset} = pre_post_traverse(kind, pre_metadata, post_metadata)

         case apply_traverse(mfargs, rest, outputs, context, traverse_line, traverse_offset) do
-          {outputs, ^context} when outputs != :error -&gt;
+          {outputs, ^context} when not is_atom(outputs) -&gt;
             {:ok, inputs, guards, outputs, post_metadata}

           _ -&gt;
</code></pre>
<p>The diff above will allow you to return <code>{:deny, "not an identifier"}</code> from lookahead/traverse. The <code>reason</code> is only used fi you call deny outside of something you cannot escape. Once I do it, this works as expected:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule NPL.Helpers do
  import NimbleParsec

  def keyword(c \\ empty()),
    do:
      c
      |&gt; choice([
        string("if") |&gt; replace(:if),
        string("while") |&gt; replace(:while)
      ])
      |&gt; lookahead(:fail_on_identifier)
      |&gt; tag(:kw)

  def identifier(c \\ empty()),
    do:
      c
      |&gt; utf8_string([?a..?z, ?A..?Z, ?0..?9], min: 1)
      |&gt; tag(:id)

  def fail_on_identifier(&lt;&lt;a, _::binary&gt;&gt;, _, _, _) when a in ?a..?z, do: {:deny, "identifier"}
  def fail_on_identifier(_, ctx, _, _), do: {[], ctx}

  def expr_(),
    do:
      choice([
        keyword(),
        identifier()
      ])
      |&gt; optional(string(" ") |&gt; ignore() |&gt; expr())

  def expr(c \\ empty()), do: c |&gt; parsec(:expr)
end

defmodule NPL do
  import NimbleParsec
  import NPL.Helpers

  defparsec(
    :expr,
    expr_()
  )
end

IO.inspect NPL.expr "iffy"  
</code></pre>
<p>I agree there are still “logistics” issues. Having to write lookahead for everything is not nice but it should provide a starting point so we can generalize it into a proper combinator.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107600" data-batch-url="/posts/batch_likers">
                        3
                      </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/54">Post #53</a>
	                </div>
	            </div>
              <div id="likers-container-107600" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107600"
                     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 #53"></div>
  </section>
</div>
    <div class="postbit" id="107604" data-post-id="107604">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="mjadczak" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/mjadczak/120/3537_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  mjadczak
                  </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="53" 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>The issues in your post are for NimbleParsec supposed to be done by a secondary pass, it’s not a single-pass parsing library (which loses a lot of it’s capabilities).</p>
</blockquote>
</aside>
<p>I’m not certain that you could do this at all with the (as of writing) NimbleParsec, even with multiple passes. Do you have a quick example of how you could do it in two passes? It seems to me that things like supporting state (which are really just “what kind of side computation can we attach to the parsing logic”) are different from lookahead (which is a fundamental block of the parser). ExSpirit may have both, but the fundamental difference here is that you have <code>lookahead_not</code> IMO.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107604" 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/55">Post #54</a>
	                </div>
	            </div>
              <div id="likers-container-107604" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107604"
                     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 #54"></div>
  </section>
</div>
    <div class="postbit" id="107605" data-post-id="107605">
  <section>
    <div class="post-wrap">


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

	        <div class="thread-main">
	            <div class="post-body" data-turbo="false">
								<p>Thanks! I’m going to play around based off that diff, but good to see it can fit somewhat nicely in the existing infrastucture.</p>
<p>I do feel quite strongly that lookahead should be a fundamental combinator rather than a “call to user code” function. It seems like even with your patch, in order to use a pre-existing parser (and I mean just a value or a function, not a <code>parsec</code>/<code>combinator</code> you would have to wrap that parser into a <code>defparsec</code> so that you could call it from the auxiliary <code>traverse</code> function.</p>
<p>I also think that having this <code>:deny</code> form be a special case just for this lookahead usecase also hurts composability, which I understood was a core goal of the library—it would be nice if I could take any parser at all, which returned an <code>:error</code> when run by itself, and stick it into <code>:deny</code>, turning it into a success. Once again I’ll reiterate that from a CS theory point of view, this is a fundamental combinator in a strict sense of “there are grammars you cannot parse without it”, which is not the case even for things like <code>repeat</code>!</p>
<p>Thanks again though, I’m looking forward to playing around some more with this idea and seeing if I can come up with a nice way to integrate it into the existing structure.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107605" 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/56">Post #55</a>
	                </div>
	            </div>
              <div id="likers-container-107605" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107605"
                     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 #55"></div>
  </section>
</div>
    <div class="postbit" id="107606" data-post-id="107606">
  <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="mjadczak" data-post="55" 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’m not certain that you could do this at all with the (as of writing) NimbleParsec, even with multiple passes.</p>
</blockquote>
</aside>
<p>You could be treating it basically as a tokanizer, which does relegate it’s functionality a bit but that’s mostly how it’s been built to be…</p>
<aside class="quote no-group" data-username="mjadczak" data-post="55" 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>It seems to me that things like supporting state (which are really just “what kind of side computation can we attach to the parsing logic”) are different from lookahead (which is a fundamental block of the parser).</p>
</blockquote>
</aside>
<p>Yep, that is just the biggest feature that I routinely use from ExSpirit that NimbleParsec doesn’t have, I can mostly work around the rest, mostly (mine contains a <em>lot</em> more result information that I use quite a bit that NimbleParsec just doesn’t have).</p>
<aside class="quote no-group" data-username="mjadczak" data-post="55" 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>ExSpirit may have both, but the fundamental difference here is that you have <code>lookahead_not</code> IMO.</p>
</blockquote>
</aside>
<p>Actually everything mine has is built it from a base set of things, and <code>lookahead</code>/<code>lookahead_not</code> you can implement entirely in user-code in ExSpirit.  NimbleParsec generates code in comparison so what it can do is limited to what it’s code generators know about.  Perhaps with some good injection points then people could write their own generators…?</p>
<aside class="quote no-group" data-username="mjadczak" data-post="56" 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 also think that having this <code>:deny</code> form be a special case just for this lookahead usecase also hurts composability, which I understood was a core goal of the library—it would be nice if I could take any parser at all, which returned an <code>:error</code> when run by itself, and stick it into <code>:deny</code> , turning it into a success. Once again I’ll reiterate that from a CS theory point of view, this is a fundamental combinator in a strict sense of “there are grammars you cannot parse without it”, which is not the case even for things like <code>repeat</code> !</p>
</blockquote>
</aside>
<p>That all comes back to how NimbleParsec generates it’s fast code.  PR’s can extend it 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="107606" 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/57">Post #56</a>
	                </div>
	            </div>
              <div id="likers-container-107606" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107606"
                     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 #56"></div>
  </section>
</div>
    <div class="postbit" id="107608" data-post-id="107608">
  <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="mjadczak" data-post="52" 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>Right off the bat, we see one immediate issue with <code>lookahead/2</code> : it’s not a composable combinator, but rather some sort of halfway measure, where we need to define a separate function for each little thing we want to check.</p>
</blockquote>
</aside>
<p>Despite being the instigator of the <code>lookadhead/2</code> combinator, I have to say I was unaware of how it had been implemented. Like you, I don’t like the fact that this combinator doesn’t take a parser as argument. This is very important information for my future uses of NimbleParsec.</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>I think that NimbleParsec should be very clear on what it supports and what it doesn’t support. That is important for users to decide whether the library fits their needs. Maybe someone with experience with grammars could spell out how powerful NimbleParsec is exactly? As we’ve seen, it’s not a PEG parser, but it might be something slightly weaker but still very powerful.</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>Having to write lookahead for everything is not nice but it should provide a starting point so we can generalize it into a proper combinator.</p>
</blockquote>
</aside>
<p>I very disagree very strongly with this idea. For a parser, it’s very important to decide ahead of time what it’s capabilities are. Adding features by accretion doesn’t seem like a good way to do this. (IMO) You shouldn’t add features one by one. You should pick a parsing style (Regex, PEG, Context-sensitive [spirit-like]) and then implement it. In stages, if necessary, but with the model picked ahead of time.</p>
<p>It’s totally OK if NimbleParsec doesn’t become any more powerful than it is because that would compromise the main design goal (which is to be crazy fast), but the capabilities of a possible new version should be decided as soon as possible.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107608" 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/58">Post #57</a>
	                </div>
	            </div>
              <div id="likers-container-107608" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107608"
                     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 #57"></div>
  </section>
</div>
    <div class="postbit" id="107609" data-post-id="107609">
  <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="mjadczak" data-post="55" 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’m not certain that you could do this at all with the (as of writing) NimbleParsec, even with multiple passes. Do you have a quick example of how you could do it in two passes?</p>
</blockquote>
</aside>
<p>Look at the elixir lexer in my makeup project. I parse everything as a keyword and then in a second pass highlight some keywords in a different way. But the initial step treats “if” and “while” just like “a” and “b”. On my phone so no links, 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="107609" 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/59">Post #58</a>
	                </div>
	            </div>
              <div id="likers-container-107609" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107609"
                     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 #58"></div>
  </section>
</div>
    <div class="postbit" id="107612" data-post-id="107612">
  <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="58" 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>Despite being the instigator of the <code>lookadhead/2</code> combinator, I have to say I was unaware of how it had been implemented. Like you, I don’t like the fact that this combinator doesn’t take a parser as argument. This is very important information for my future uses of NimbleParsec.</p>
</blockquote>
</aside>
<p>Wait what?  I’ve not seen it yet in NimbleParsec, how does it work without a combinator to give it a success/fail result?!  o.O</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107612" 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/60">Post #59</a>
	                </div>
	            </div>
              <div id="likers-container-107612" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107612"
                     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 #59"></div>
  </section>
</div>
    <div class="postbit" id="107613" data-post-id="107613">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="mjadczak" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/mjadczak/120/3537_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  mjadczak
                  </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="60" 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>how does it work without a combinator to give it a success/fail result?</p>
</blockquote>
</aside>
<p>You have to supply a user-defined function (which needs to be a real <code>def </code>in the module) which takes the binary and has to return a success or error.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107613" 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/61">Post #60</a>
	                </div>
	            </div>
              <div id="likers-container-107613" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107613"
                     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 #60"></div>
  </section>
</div>
    <div class="postbit" id="107614" data-post-id="107614">
  <section>
    <div class="post-wrap">


					<div class="post-header">
		        <div class="user-avatar">
		          <img alt="mjadczak" src="https://forum.elixirforum.com/user_avatar/forum.elixirforum.com/mjadczak/120/3537_2.png" width="120" height="120" />
		        </div>
					
						<div class="user-details">
		          <div class="user-name">
		            <h3>
                  mjadczak
                  </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="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>Here is a diff that allows just that:</p>
</blockquote>
</aside>
<p>For what it’s worth, it’s simple enough to recreate by hand, but I could not get this diff to parse properly (kept getting “malformed patch”). Maybe forum formatting broke it somehow?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107614" 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/62">Post #61</a>
	                </div>
	            </div>
              <div id="likers-container-107614" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107614"
                     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 #61"></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=7">Load more posts (81 remaining)</a>
</div></template></turbo-stream>