<turbo-stream action="append" target="posts_list"><template>    <div class="postbit" id="107773" data-post-id="107773">
  <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="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>If you have some time, can you please expand on what I am missing? If you could provide a reference, even better!</p>
</blockquote>
</aside>
<p>The thing to watch out for, is that formally, a parser is just something which can <em>recognise</em> a grammar with particular properties. A PEG (Parsing Expression Grammar) is simply a language grammar which can be written as a combination of the operators on the Wikipedia page. Any practical Context-Free Grammar will likely be also expressible as a PEG (though this is technically an open academic question).</p>
<p>The key thing to remember is that for the parser to be “complete”, it just needs to be able to take in a grammar (i.e. the definition the user writes for the parser) and the input, and either say “yes, this input follows the grammar” or “no, this input does not follow the grammar”. Hence, my statement was “now NimbleParsec can <em>recognise</em> any PEG grammar”, which of course is a prerequisite for “NimbleParsec can use a PEG grammar to turn binary input into some useful datastrucure”, which <a class="mention" href="/u/overminddl1" rel="nofollow">@OvermindDL1</a> is referring to. Unfortunately, this problem is far less interesting to researchers, and so “what features are missing” is probably better answered by reference to other popular PEG-style parsers rather than a paper or reference page <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 group-livebook_core_team" 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>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>
</blockquote>
</aside>
<p>This is indeed how I was planning to handle XML tag closing/opening. I can see that right now <a class="mention" href="/u/overminddl1" rel="nofollow">@OvermindDL1</a> is writing an answer, but my guess is that the answer will again involve the fact that these are not really composable with the rest of the parsing definitions, but rather require a specific external function to be called (if they were composable, you could make a version of every single base combinator which also depends on or modifies some state). There’s also the local/global state thing which ExSpirit has, (I actually have no idea how that works or why it is useful though).</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107773" 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/83">Post #82</a>
	                </div>
	            </div>
              <div id="likers-container-107773" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107773"
                     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 #82"></div>
  </section>
</div>
    <div class="postbit" id="107776" data-post-id="107776">
  <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 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>The academic PEG description is essentially the root math of it, but adhering to it strictly is a recipe for inefficiency and lack of abilities.  What’s been learned by the industry over the past 20 years has come up with a few patterns that have become necessities.  <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 group-livebook_core_team" 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>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>
</blockquote>
</aside>
<p>State context handling is like think of parsing out an integer at one node, passing it ‘into’ potentially many nodes deep, where that gets added to another parsed integer, that then gets returned ‘up’ a multitude of nodes, where this is important is think about parsing a programming language where the syntax changes depending on a ‘type’ of something that got parsed or defined earlier, like think of this:</p>
<pre><code class="lang-plaintext">s = something()
s.blah
</code></pre>
<p>To determine what the <code>s.blah</code> should be doing, say a map lookup, a module function invocation, etc… depends on the type of <code>s</code>, which depends on the type of what <code>something()</code> is, which requires <code>something()</code> to have been typed prior (this is similar to how some ML languages work, not OCaml as it uses unique operators for everything though).  Now imagine it is not just a simple <code>.</code> call but some entirely different branching structure, so you have to dispatch to different parsers based on some runtime type information of the system.  In a modern PEG parser that is able to be figured out during parsing without ever needing to re-dispatch in to the parser.  Like take the TreeMap in ExSpirit, it is designed as it is because it can be stored in state, so it could start empty, but then someone defines something in the language called <code>my int</code> and whatever comes after it should be parsed as an integer and passed in to it, all you have to do is add it to that and it ‘just works’.  The Treemap (my implementation is very much a direct translation of the ones I’ve written in C++, I could write it more efficiently in a more Elixir’y way in Elixir) is also a common pattern in modern peg libraries.</p>
<p>A great example of a modern PEG library is C++'s <a href="https://www.boost.org/doc/libs/1_69_0/libs/spirit/doc/html/index.html" rel="noopener nofollow ugc">Spirit2</a>, a rewrite of Spirit1 based on everything learned prior (which made it the fastest PEG library anywhere, because it can quite literally optimize it’s constructs in very interesting ways).  If you want to see a PEG library that is in heavy use and crazy efficient then that is the one to look at (Antlr is not bad though it focuses more on streaming so is not as efficient and thus different design considerations).  An extra library of <a href="https://www.boost.org/doc/libs/1_69_0/libs/spirit/repository/doc/html/index.html" rel="noopener nofollow ugc">spirit-components</a> is available as well that contains some less generic and more specialized pre-built elements like keyword handling (as I spoke above), confix (basically for handling things like beginning/ending tags more succinctly), distinct (like parsing <code>if</code> but not matching <code>iffy</code> based on a non-matching tail, among others, but all are built on the base Spirit library.</p>
<p>Spirit handles state far more cleanly than I do in ExSpirit (which I could emulate with more macro work), essentially given something like <code>little_dword[_a = _1] &gt;&gt; advance(_a) &gt;&gt; little_dword</code> it parses a little-endian dword (Spirit works on generic binaries, not just text, think Elixir/Erlang binary parsing with a lot more), then takes the first element of the result of it (most things only have one output, it fails to compile if you access an element that doesn’t exist for the given parser, it’s type safe), designated by the <code>_1</code> and assigns it to a rule-specific ‘state value’ here names <code>_a</code>, which is then passed ‘into’ the <code>advance</code> component, which then skips that number of bytes, I.E. this parses a dword-sized ‘size’ header like <code>00 00 00 04</code> and then skips that many bytes to skip over this record, then it parses another little-endian dword (this you can do in Elixir binary matching, hence why I’m using this example to make it easy to reason about how Elixir/Erlang binary matching/parsing has similar features to modern PEG state handling).</p>
<p>The <code>advance(_a)</code> is passing the data ‘into’ the rulestack, it could be your own rule that takes the argument and uses it inside it as it wishes as well, and it returns data by packing them into result elements, this is why ExSpirit allows you to store rule specific named state that doesn’t exist in inner rules and isn’t passed up, but you can return data via <code>result</code> and you can pass data ‘into’ via arguments, modeling the same as C++'s Spirit.</p>
<p><a href="https://www.boost.org/doc/libs/1_69_0/libs/spirit/doc/html/spirit/abstracts/parsing_expression_grammar.html" rel="noopener nofollow ugc">This</a> page on Spirit’s docs talks about the basic PEG setup, which is basically just:</p>
<ul>
<li>Sequences: Parse the first then the second</li>
<li>Alternatives: Parse the first, if it fails then parse the second</li>
<li>Loops: Parse a number of times until the parser fails then concat all successful parses up to then</li>
<li>Difference: Parse something that does not match something else (this is the basic of the lookahead).</li>
</ul>
<p>Now these are not always the most efficient, especially Difference’s performance is pretty abysmal, hence why specialized things like <code>lookahead</code> and made.</p>
<p>Spirit splits up the ‘types’ of it’s components into a few kinds:</p>
<ul>
<li>Primitives: A simple thing like <code>int_</code> that parses and returns data, it can potentially take arguments (like <code>int_</code> accepts things like size, range, radix, etc… etc…) but it does not accept any components as arguments.</li>
<li>Compound: Like primitives but they also accept other components, so this would be like a repeat operator (<code>repeat</code> in ExSpirit, <code>*</code> or <code>+</code> in C++ Spirit) or even the basic sequence (which takes multiple ordered components by default, <code>seq</code> or <code>|&gt;</code> in ExSpirit and <code>&gt;&gt;</code> in C++).</li>
<li>Rule: A collection of components scoped, this is like ‘naming’ a set of of components, essentially it corresponds to a function in C++ except it’s defined in the type system instead of as a runnable function (<code>defrule</code> in ExSpirit, <code>rule&lt;Iterator, return_type(rule, args, here)&gt;</code> in C++).  This also provides a point to separate the code so the compiler can choose whether to inline it or not where used (where all compound and primitive components are force inlined for efficiency).  Say you made a rule like <code>rule&lt;Iterator, vector&lt;int&gt;()&gt; ints = int_ % ','</code> in C++ Spirit that parses a comma separated list of integers and returns them in an array named <code>ints</code> then you could use it elsewhere like any other component like <code>"list: " &gt;&gt; ints &gt;&gt; eol</code> or so.  If the compiler doesn’t optimize it then there is a slight cost of runtime speed, however it does reduce compilation times by using more rules.</li>
<li>Grammar: This is a collection of rules, it adds a full synchronization point, grammars are not eligible for being inlined across other grammars.  Generally you only have one grammar but if you have a <em>huge</em> language to parse then you can split up multiple grammars to add points where the compiler is not allowed to optimize across, which can <em>SIGNIFICANTLY</em> improve compilation time in complex parsers at the cost of a bit of runtime speed.</li>
</ul>
<p>So the basic syntax of a component is <code>component_name</code> or <code>component_name()</code> (either works, though if it has arguments to pass in then you must use the <code>component_name(args...)</code> form).</p>
<p>Every component can have an associated semantic action delinated by <code>[</code>/<code>]</code>, so something like <code>int_[&amp;blah]</code> will call the function <code>blah</code> with the result of the parsed integer if the <code>blah</code> is typed as <code>int blah(int)</code>, if blah is otherwise typed as <code>int blah(context&amp;, int)</code> (maybe the other order, I forget…) then it gets the full context data passed in so it can access locally defined state variables, parse location (column/line/etc..) and a <em>lot</em> more information.  The above <code>[_a = _1]</code> is essentially just defining an inline lambda function of <code>[[](auto context, auto val) {context.putState&lt;_a&gt;(val)} ]</code> or something like that (that’s not a spirit feature, rather a phoenix library feature, which is very often used with spirit due to the succinctness of it’s lambdas). A semantic action can be any ‘callable’ type that fits any of the proper signatures (or it fails to compile).</p>
<p>The basic set of components included with Spirit directly (either to significantly reduce repeated code or for efficiency reasons because the basic PEG constructs are way too inefficient) are mostly defined <a href="https://www.boost.org/doc/libs/1_69_0/libs/spirit/doc/html/spirit/qi/quick_reference/qi_parsers.html" rel="noopener nofollow ugc">here</a>.  The usual ‘efficient’ ones like character and string and number parsers are of course included, among others, but the especially interesting ones are the <a href="https://www.boost.org/doc/libs/1_69_0/libs/spirit/doc/html/spirit/qi/quick_reference/qi_parsers/directive.html" rel="noopener nofollow ugc">parser directives</a>, this includes things like:</p>
<ul>
<li>lexeme:  disables the skip parser but pre-skips</li>
<li>no_skip: disables the skip parser with no pre-skip</li>
<li>raw: Parses however but returns the entire range of source text instead, regardless of the returned values.  Without this then parsing twice is necessary.</li>
<li>expect: Throws an exception with the currently set error if there is an error, otherwise no-op.  Without this then errors will not be accurate in many cases.</li>
<li>repeat: Min-max specific repeating call.  Without this input can be repeatedly parsed when it was not necessary.</li>
<li>Among many others.</li>
</ul>
<p>Spirit also defines the concept of a <code>skip_parser</code>, this is a parser passed into the <code>parse</code> call to act as an omitted skipper that is auto-placed between every terminal component (a component that parses a base thing like ‘int_’, but something like <code>repeat</code> would run the skip parser between each iteration and before the first).  This is often used with spaces for example, so given <code>parse(input.begin(), input.end(), int_ % ',', blank)</code> would parse <code>1    ,  2  ,      3, 4,5,6  ,   7</code> the same as <code>1,2,3,4,5,6,7</code>, but without the <code>blank</code> skip parser then only <code>1,2,3,4,5,6,7</code> would parse and any spaces would fail.  This is generically useful for a lot of things and implementing it on the user-code otherwise means adding in a whole <em>LOT</em> of needless noise among every-single-parser that is created.  The skip parser can be prevented from working via <code>lexeme</code>/<code>no_skip</code> in C++ Spirit for a given component.</p>
<p>So yes in general the PEG ‘spec’ is simple and doesn’t have much, but it is also crazy inefficient, modern PEG libraries have found patterns that work around it to get a more useful base set of components.</p>
<p>Another thing Spirit can do is also let you define a ‘parser’ that runs the other way, you feed it the data structure of whatever internal format you have and it sends out a binary stream.  That is not a feature I added in yet in ExSpirit but it was open to it.</p>
<aside class="quote no-group" data-username="tmbb" data-post="81" 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><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>
</blockquote>
</aside>
<p>Basically yeah, there is a difference between <code>PEG</code> the Spec and <code>PEG</code> as is implemented in modern libraries, I tend to use what is done in modern libraries as that is the part that is actually useful considering how dreadfully inefficient the base Spec is.</p>
<aside class="quote no-group" data-username="tmbb" data-post="81" 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 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>
</blockquote>
</aside>
<p>Correct, but it is such a universal ‘convenience’ that it is often baked into about every library as it can both <em>substantially</em> improve error messages while also improving performance.</p>
<aside class="quote no-group" data-username="tmbb" data-post="81" 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>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>
</blockquote>
</aside>
<p>Eh, the first (state handling) is not so much a convenience, it is what allows PEG’s to go from Context Free parsers to Context Sensitive.  There are many ways to handle state, some more efficient then others of course.</p>
<aside class="quote group-livebook_core_team" data-username="josevalim" data-post="82" 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>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>
</blockquote>
</aside>
<p>Efficient XML parsing is the traditionally ‘simple’ use-case, it is context sensitive to match the closing tag with the opening tag, otherwise you need a second pass over the complete data.  Now the second pass (like using a semantic action in C++ Spirit) can of course be used to enforce this specific case, but in actual programming languages it is often common for the parser to ‘change’ based on state, and thus the XML example is a simplified form of that where the parser changes (what the ending tag matches to) based on prior state (what the opening tag was parsed as), so being able to do that without the ending pass, I.E. being able to change the actual parser functionality based on runtime state is highly important for parsing most languages efficiently (otherwise you tend to have to go to a multi-stage parser where you first tokanize, then fixup the tokens, then generate the AST, then convert the AST to the internal format, where modern PEG libraries can generate the internal format directly without needing to generate the huge amount of intermediate data).</p>
<aside class="quote no-group" data-username="mjadczak" data-post="83" 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>but rather require a specific external function to be called</p>
</blockquote>
</aside>
<p>Correct, you’ll have to verify the end tag via a function after the parsing of the (anything) end tag is complete, simple in the XML case, but not so in more complex cases like parsing branches differently based on the types of parsed data.</p>
<aside class="quote no-group" data-username="mjadczak" data-post="83" 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>There’s also the local/global state thing which ExSpirit has, (I actually have no idea how that works or why it is useful though).</p>
</blockquote>
</aside>
<p>Super popular with interpreters, like implementing a mini language that calculates the values as it is parsed, so the returned parsed value is the result of the calculation, regardless of any variables set, scopes, etc…  Local is being able to hold data within a specific rule, like what the value of the parsed opening tag was in XML so you can reuse it to adjust the parser for the closing tag.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107776" 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/84">Post #83</a>
	                </div>
	            </div>
              <div id="likers-container-107776" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107776"
                     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 #83"></div>
  </section>
</div>
    <div class="postbit" id="107777" data-post-id="107777">
  <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 quote-modified" data-username="OvermindDL1" data-post="84" 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>Every component can have an associated semantic action delinated by <code>[</code> / <code>]</code> , so something like <code>int_[&amp;blah]</code> will call the function <code>blah</code> with the result of the parsed integer if the <code>blah</code> is typed as <code>int blah(int)</code> , if blah is otherwise typed as <code>int blah(context&amp;, int)</code> (maybe the other order, I forget…) then it gets the full context data passed in so it can access locally defined state variables, parse location (column/line/etc…) and a <em>lot</em> more information. The above <code>[_a = _1]</code> is essentially just defining an inline lambda function of <code>[[](auto context, auto val) {context.putState&lt;_a&gt;(val)} ]</code> or something like that (that’s not a spirit feature, rather a phoenix library feature, which is very often used with spirit due to the succinctness of it’s lambdas). A semantic action can be any ‘callable’ type that fits any of the proper signatures (or it fails to compile).</p>
</blockquote>
</aside>
<p>To expand on this, say a parser for the Elixir language was made in C++ Spirit or ExSpirit, you can create a new ‘tag’ function or component that wraps the result in a 3-tuple like Elixir’s AST is, with the middle context metadata including the line and column parsing information, perhaps the byte location in the input stream, etc…  This is something not currently possible in NimbleParsec as it doesn’t have such context information.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107777" 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/85">Post #84</a>
	                </div>
	            </div>
              <div id="likers-container-107777" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107777"
                     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 #84"></div>
  </section>
</div>
    <div class="postbit" id="107778" data-post-id="107778">
  <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="85" 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>you can create a new ‘tag’ function or component that wraps the result in a 3-tuple like Elixir’s AST is, with the middle context metadata including the line and column parsing information, perhaps the byte location in the input stream, etc… This is something not currently possible in NimbleParsec as it doesn’t have such context information.</p>
</blockquote>
</aside>
<p>This is posible in NimbleParsec! You can add line and column metadata with no problems since about the second version came out. Are you sure you’ve looked at the most recent docs? You can also add information from the context if you wish. Tagging the generated AST with NimbleParsec, although not as convenient as with ExSpirit (IMO), is perfectly 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="107778" 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/86">Post #85</a>
	                </div>
	            </div>
              <div id="likers-container-107778" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107778"
                     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 #85"></div>
  </section>
</div>
    <div class="postbit" id="107779" data-post-id="107779">
  <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="tmbb" data-post="86" 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 is posible in NimbleParsec! You can add line and column metadata with no problems since about the second version came out. Are you sure you’ve looked at the most recent docs? You can also add information from the context if you wish.</p>
</blockquote>
</aside>
<p>Here is an example: <a href="https://github.com/plataformatec/nimble_parsec/blob/master/examples/simple_xml.exs" class="inline-onebox" rel="nofollow">nimble_parsec/examples/simple_xml.exs at master · dashbitco/nimble_parsec · GitHub</a></p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107779" 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/87">Post #86</a>
	                </div>
	            </div>
              <div id="likers-container-107779" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107779"
                     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 #86"></div>
  </section>
</div>
    <div class="postbit" id="107786" data-post-id="107786">
  <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="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>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>
</blockquote>
</aside>
<p>The eaisest way to explain what’s missing is to look at the spec of the <code>post_traverse</code> function (the new name for the old <code>traverse</code> function): <code>post_traverse(combinator \\ empty(), to_post_traverse, call)</code> the <code>call</code> argument is a function, which takes the parser state as an argument (including the context, of course) and it must return a 2-tuple of the form <code>{acc, context}</code>, where the context is the new context and <code>acc</code> is the result you append to the list of results. This does not allow you to consume any input. You can do things to the result depending on the input that has already been consumed and on the input you haven’t yet consumed, but you can’t consume nay new input.</p>
<p>This means you can’t change the input you’re consuming based on the <code>contexts</code>. For NimbleParsec to allow context-sensitive combinators, the <code>call</code> function would have to build a new combinator at runtime and apply it to the rest of the input. Let’s say you want to parse a grammar of the form <code>&lt;n&gt;:&lt;n integers separated by commas&gt;</code>. An example is this: <code>5:1,4,55,6,7</code>. To parse this, you have to consume the character <code>?5</code>, and then build a new parser that recognizes exactly 5 integers (it could fetch the number 5 dynamically from the context). This is an example of a context-sensitive language, and one which I think NimbleParsec can’t handle currently.</p>
<p>Now, implementing a state system like this sounds like a lot of work, because you’d have to have “dynamic” versions of the combinators (besides the “static” ones you already have). This complicats the design a lot, and stateful combinators are much harder to optimize into the kinds of pattern matches that NimbleParsec is using now.</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107786" data-batch-url="/posts/batch_likers">
                        2
                      </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/88">Post #87</a>
	                </div>
	            </div>
              <div id="likers-container-107786" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107786"
                     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 #87"></div>
  </section>
</div>
    <div class="postbit" id="107792" data-post-id="107792">
  <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>Yeaaaaaaaaah… doing this would be really tricky.</p>
<p>We could have a dynamic choice, where you could choose at runtime which combinator to dispatch to:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">dynamic([
  foo: combinator1,
  bar: combinator2,
], mfa)
</code></pre>
<p>And the <code>mfa</code> returns either <code>:foo</code> or <code>:bar</code> but it is still limited because the combinators pointed out by <code>:foo</code> and <code>:bar</code> still aren’t dynamic, so you can’t say something should happen exactly 5 times. You would still have to write a code in a way that parses n entries and then check afterwards (using post_traverse) that you had exactly 5 entries. I have no idea if this is good enough though.</p>
<p>Thanks <a class="mention" href="/u/tmbb" rel="nofollow">@tmbb</a>!</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107792" 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/89">Post #88</a>
	                </div>
	            </div>
              <div id="likers-container-107792" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107792"
                     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 #88"></div>
  </section>
</div>
    <div class="postbit" id="107800" data-post-id="107800">
  <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="89" 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>We could have a dynamic choice, where you could choose at runtime which combinator to dispatch to:</p>
</blockquote>
</aside>
<p>Exactly, only it needs to be a little more general:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">dynamic(fn context -&gt; my_dynamic_combinator(context) end)
</code></pre>
<p>And somehow the returned combinator must be interpreted at runtime by the parser (instead of compiled into something much more efficient). With a slight change to <code>post_traverse</code> (or with the addition of a new “primitive” combinator) I believe I could implement context-sensitive parsers as “user-level” code.</p>
<p>I might work on it if I get some free time</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107800" 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/90">Post #89</a>
	                </div>
	            </div>
              <div id="likers-container-107800" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107800"
                     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 #89"></div>
  </section>
</div>
    <div class="postbit" id="107804" data-post-id="107804">
  <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="86" 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 is posible in NimbleParsec! You can add line and column metadata with no problems since about the second version came out. Are you sure you’ve looked at the most recent docs?</p>
</blockquote>
</aside>
<p>I have not apparently, when I wrote my benchmark where NimbleParsec bested ExSpirit handedly it did not exist at the time!  Woot!</p>
<aside class="quote group-livebook_core_team" data-username="josevalim" data-post="87" 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 an example: <a href="https://github.com/plataformatec/nimble_parsec/blob/master/examples/simple_xml.exs" rel="noopener nofollow ugc">https://github.com/plataformatec/nimble_parsec/blob/master/examples/simple_xml.exs </a></p>
</blockquote>
</aside>
<p>To be honest I find that file pretty long and unreadable, I’m not sure that’ s a good example.  Lots of seemingly random functions doing things that the parser should do and so forth.  I’m pretty sure I could write a set of matcher heads to parse the same in significantly shorter space?  Hmm, let me write a parser how I usually did in erlang:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule SimpleXML do
  def parse(inp) do
    {rest, [xml]} = xml({inp, 1, 1, 0})
    {:ok, xml, rest}
  catch s when is_binary(s) -&gt; {:error, s}
  end

  def xml({"&lt;" &lt;&gt; inp, l, c, o}) do
    {inp, name} = tag({inp, l, c+1, o+1})
    xml_head(inp, name)
  end
  def xml(inp), do: {inp, []}

  def xml_head({"&gt;" &lt;&gt; inp, l, c, o}, name), do: xml_rest({inp, l, c+1, o+1}, name)

  def xml_rest(inp, name, children \\ [])
  def xml_rest({"&lt;/" &lt;&gt; inp, l, c, o}=ct, name, children) do
    {inp, ^name} = tag({inp, l, c+2, o+2})
    xml_done(inp, name, children)
  rescue MatchError -&gt; err(ct, "Invalid closing tag does not match start tag of #{name}")
  end
  def xml_rest({"&lt;" &lt;&gt; _inp, _l, _c, _o} = ct, name, children) do
    {ct, xml} = xml(ct)
    xml_rest(ct, name, xml ++ children)
  end
  def xml_rest({&lt;&lt;_::integer-size(8), _::binary&gt;&gt;, _l, _c, _o} = ct, name, children) do
    {ct, txt} = text(ct)
    xml_rest(ct, name, txt ++ children)
  end
  def xml_rest(ct, name, _children), do: err(ct, "XML Parsing failure at #{name}")
  
  def xml_done({"&gt;" &lt;&gt; inp, l, c, o}, name, children) do
    {{inp, l, c+1, o+1}, [{name, [line: l, column: c, offset: o], :lists.reverse(children)}]}
  end
  
  def tag(inp, t \\ "")
  def tag({&lt;&lt;ch::integer-size(8), inp::binary&gt;&gt;, l, c, o}, t) when ch in ?a..?z or ch in ?A..?Z, do: tag({inp, l, c+1, o+1}, &lt;&lt;t::binary, ch::utf8&gt;&gt;)
  def tag(inp, t) when byte_size(t)&gt;0, do: {inp, String.to_atom(t)}
  def tag(ct, _t), do: err(ct, "Empty tag not allowed")
  
  def text({inp, l, c, o}), do: text(inp, inp, l, c, o)
  def text(orig, "\n" &lt;&gt; inp, l, _c, o), do: text(orig, inp, l+1, 1, o+1)
  def text(orig, "&lt;" &lt;&gt; _ = inp, l, c, o), do: text_done(orig, inp, l, c, o)
  def text(orig, "", l, c, o), do: text_done(orig, "", l, c, o)
  def text(orig, &lt;&lt;_::integer-size(8), inp::binary&gt;&gt;, l, c, o), do: text(orig, inp, l, c+1, o+1)
  
  def text_done(oinp, inp, l, c, o) do
    offset = byte_size(oinp) - byte_size(inp)
    &lt;&lt;result::binary-size(offset), _::binary&gt;&gt; = oinp
    {{inp, l, c, o}, [result]}
  end
  
  def err({inp, l, c, _o}, msg), do: throw "ERROR at #{l}:#{c}: #{msg}\nTrailing Data: `#{String.slice(inp, 0, 24)}`"
end
inputs = [
  "&lt;foo&gt;&lt;/foo&gt;",
  "&lt;foo&gt;&lt;bar&gt;&lt;/bar&gt;&lt;/foo&gt;",
  "&lt;foo&gt;bar&lt;/foo&gt;",
  "&lt;foo&gt;&lt;bar&gt;baz&lt;/bar&gt;&lt;/foo&gt;",
  "&lt;foo&gt;&lt;bar&gt;one&lt;/bar&gt;&lt;bar&gt;two&lt;/bar&gt;&lt;/foo&gt;",
  "&lt;&gt;bar&lt;/&gt;",
  "&lt;foo&gt;bar&lt;/baz&gt;",
  "&lt;foo&gt;bar&lt;/foo&gt;oops",
  "&lt;foo&gt;bar"
]
for input &lt;- inputs do
  IO.puts(input)
  IO.inspect(SimpleXML.parse(input))
  IO.puts("")
end
</code></pre>
<p>Running it gives:</p>
<pre><code class="lang-plaintext">&lt;foo&gt;&lt;/foo&gt;
{:ok, {:foo, [line: 1, column: 11, offset: 10], []}, {"", 1, 12, 11}}

&lt;foo&gt;&lt;bar&gt;&lt;/bar&gt;&lt;/foo&gt;
{:ok,
 {:foo, [line: 1, column: 22, offset: 21],
  [{:bar, [line: 1, column: 16, offset: 15], []}]}, {"", 1, 23, 22}}

&lt;foo&gt;bar&lt;/foo&gt;
{:ok, {:foo, [line: 1, column: 14, offset: 13], ["bar"]}, {"", 1, 15, 14}}

&lt;foo&gt;&lt;bar&gt;baz&lt;/bar&gt;&lt;/foo&gt;
{:ok,
 {:foo, [line: 1, column: 25, offset: 24],
  [{:bar, [line: 1, column: 19, offset: 18], ["baz"]}]}, {"", 1, 26, 25}}

&lt;foo&gt;&lt;bar&gt;one&lt;/bar&gt;&lt;bar&gt;two&lt;/bar&gt;&lt;/foo&gt;
{:ok,
 {:foo, [line: 1, column: 39, offset: 38],
  [
    {:bar, [line: 1, column: 19, offset: 18], ["one"]},
    {:bar, [line: 1, column: 33, offset: 32], ["two"]}
  ]}, {"", 1, 40, 39}}

&lt;&gt;bar&lt;/&gt;
{:error, "ERROR at 1:2: Empty tag not allowed\nTrailing Data: `&gt;bar&lt;/&gt;`"}

&lt;foo&gt;bar&lt;/baz&gt;
{:error,
 "ERROR at 1:9: Invalid closing tag does not match start tag of foo\nTrailing Data: `&lt;/baz&gt;`"}

&lt;foo&gt;bar&lt;/foo&gt;oops
{:ok, {:foo, [line: 1, column: 14, offset: 13], ["bar"]}, {"oops", 1, 15, 14}}

&lt;foo&gt;bar
{:error, "ERROR at 1:9: XML Parsing failure at foo\nTrailing Data: ``"}
</code></pre>
<p>And I find it both a lot shorter and more readable, here is the ExSpirit version in comparison:</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>Which I find even shorter still and <em>significantly</em> more readable than both the prior.  If the parser doesn’t gain any code over doing it just manually via normal pattern matching, than why use the library?</p>
<aside class="quote no-group" data-username="tmbb" data-post="88" 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 means you can’t change the input you’re consuming based on the <code>contexts</code> . For NimbleParsec to allow context-sensitive combinators, the <code>call</code> function would have to build a new combinator at runtime and apply it to the rest of the input. Let’s say you want to parse a grammar of the form <code>&lt;n&gt;:&lt;n integers separated by commas&gt;</code> . An example is this: <code>5:1,4,55,6,7</code> . To parse this, you have to consume the character <code>?5</code> , and then build a new parser that recognizes exactly 5 integers (it could fetch the number 5 dynamically from the context). This is an example of a context-sensitive language, and one which I think NimbleParsec can’t handle currently.</p>
</blockquote>
</aside>
<p>Hmm…</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">defmodule Testering do
  use ExSpirit.Parser, text: true

  def parse(input) do
    parse(input,
      uint()
      |&gt; put_state(:count, :result)
      |&gt; lit(?:)
      |&gt; seq([uint(), get_state_into(:count, repeat(lit(?,) |&gt; uint(), &amp;1-1, &amp;1-1))])
    )
  end
end
Testering.parse("5:1,4,55,6,7")
Testering.parse("5:1,4,55,6,7,8,9")
</code></pre>
<p>Result being:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">iex(21)&gt; Testering.parse("5:1,4,55,6,7")
%ExSpirit.Parser.Context{
  column: 13,
  error: nil,
  filename: "&lt;unknown&gt;",
  line: 1,
  position: 12,
  rest: "",
  result: [1, 4, 55, 6, 7],
  rulestack: [],
  skipper: nil,
  state: %{count: 5},
  userdata: nil
}
iex(22)&gt; Testering.parse("5:1,4,55,6,7,8,9")
%ExSpirit.Parser.Context{
  column: 13,
  error: nil,
  filename: "&lt;unknown&gt;",
  line: 1,
  position: 12,
  rest: ",8,9",
  result: [1, 4, 55, 6, 7],
  rulestack: [],
  skipper: nil,
  state: %{count: 5},
  userdata: nil
}
</code></pre>
<p>As you can see in the <code>rest</code> it didn’t parse anything beyond the number, leaving it for later parsers.  And with a simple <code>alt</code> I can make it handle the 0 case as well (assuming that should even be a valid parse).</p>
<aside class="quote group-livebook_core_team" data-username="josevalim" data-post="89" 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>We could have a dynamic choice, where you could choose at runtime which combinator to dispatch to:</p>
</blockquote>
</aside>
<pre data-code-wrap="elixir"><code class="lang-elixir">  iex(1)&gt; import ExSpirit.Parser
  iex(2)&gt; import ExSpirit.Tests.Parser
  iex(3)&gt; alias ExSpirit.TreeMap, as: TreeMap
  iex(4)&gt; symbol_TreeMap = TreeMap.new() |&gt; TreeMap.add_text("int", &amp;uint(&amp;1)) |&gt; TreeMap.add_text("char", &amp;char(&amp;1))
  iex(5)&gt; context = parse("int42", symbols(symbol_TreeMap))
  iex(6)&gt; {context.error, context.result, context.rest}
  {nil, 42, ""}
  iex(7)&gt; context = parse("charT", symbols(symbol_TreeMap))
  iex(8)&gt; {context.error, context.result, context.rest}
  {nil, ?T, ""}
</code></pre>
<p>That’s the simple form of dynamic dispatch, you can even add and remove things from the treemap during parse time, including generating new parsers.</p>
<p>Although if you just want to generate a parser you can do that in a normal defrule anyway (I should add spirit’s <code>lazy</code> component to simplify that…).</p>
<aside class="quote no-group" data-username="tmbb" data-post="90" 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>Exactly, only it needs to be a little more general:</p>
</blockquote>
</aside>
<p>That specific function is called <code>lazy</code> in C++'s Spirit.  <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="90" 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>And somehow the returned combinator must be interpreted at runtime by the parser (instead of compiled into something much more efficient). With a slight change to <code>post_traverse</code> (or with the addition of a new “primitive” combinator) I believe I could implement context-sensitive parsers as “user-level” code.</p>
</blockquote>
</aside>
<p>Eh, it should just be an anonymous function call in terms of cost I’d think?</p> 
	            </div>

	            <div class="base-line">
	                <div class="thread-counters">
	                    <span class="thread-count count-likes js-likers-trigger" title="Likes" data-post-id="107804" 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/91">Post #90</a>
	                </div>
	            </div>
              <div id="likers-container-107804" 
                   class="likers-container"
                   data-first-post="false"
                   data-batch-url="/posts/batch_likers">
                   <div class="likers-placeholder" 
                     data-likers-post-id="107804"
                     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 #90"></div>
  </section>
</div>
    <div class="postbit" id="107811" data-post-id="107811">
  <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="91" 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>Hmm…</p>
</blockquote>
</aside>
<p>Yes, I’m perfectly aware of how trivial it is to do this in ExSpirit. After al, I’ve used the context-sensitive features of ExSpirit to write a pretty cool HTML lexer which was capable of highlighting matching opening and closing tags, something which seems impossible with NimbleParsec. The question is how to implement these features in NimbleParsec’s architecture.</p>
<aside class="quote no-group" data-username="OvermindDL1" data-post="91" 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, it should just be an anonymous function call in terms of cost I’d think?</p>
</blockquote>
</aside>
<p>I guess so. But the main problem is not performance. The way NimbleParsc works is by generating an AST for a parser and then compiling the whole thing. It makes use of the fact that some things are static and others are dynamic to optimize code generation (last time I looked, it might have changed). With something like this, you have to have an anonymous function than generates a combinator at runtime, which is something compeltely different from what NimbleParsec is doing.</p>
<p>It might require you to have two classes of componentes, some static and some dynamic. But then again, it might not. I could see something like:</p>
<pre data-code-wrap="elixir"><code class="lang-elixir">integer()
|&gt; convert_to_integer()
|&gt; put_state(:count, :result)
|&gt; ...
|&gt; get_state_into(:count, something)
</code></pre>
<p>where something is a combinator that (statically) returns an expression, which the <code>get_state_into</code> macro would compile into something different. Basically <code>get_state_into</code> would be an alterantive compiler for the same kind of expressions which are compiled by <code>defparsec</code>.</p>
<p>If you’re smart when coding <code>get_state_into</code>, you can optimize things so that most of the work is done at compile time instead of at runtime. I haven’t seen how ExSpirit does it though (I’ll look at it ASAP, the code seems very simple).</p> 
	            </div>

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