···1212 <language>en-us</language>
1313 <copyright>Creative Commons BY-NC-SA 4.0</copyright>
1414 <item>
1515+<title>Introducing Tablespoon</title>
1616+<description><p><a href="https://git.peppe.rs/languages/tbsp">tbsp</a> (tree-based
1717+source-processing language) is an awk-like language that operates on
1818+tree-sitter syntax trees. To motivate the need for such a program, we
1919+could begin by writing a markdown-to-html converter using
2020+<code>tbsp</code> and <a
2121+href="https://github.com/tree-sitter-grammars/tree-sitter-markdown">tree-sitter-md</a>.
2222+We need some markdown to begin with:</p>
2323+<pre><code># 1 heading
2424+2525+content of first paragraph
2626+2727+## 1.1 heading
2828+2929+content of nested paragraph</code></pre>
3030+<p>For future reference, this markdown is parsed like so by
3131+tree-sitter-md (visualization generated by <a
3232+href="https://git.peppe.rs/cli/tree-viz">tree-viz</a>):</p>
3333+<pre><code>document
3434+| section
3535+| | atx_heading
3636+| | | atx_h1_marker &quot;#&quot;
3737+| | | heading_content inline &quot;1 heading&quot;
3838+| | paragraph
3939+| | | inline &quot;content of first paragraph&quot;
4040+| | section
4141+| | | atx_heading
4242+| | | | atx_h2_marker &quot;##&quot;
4343+| | | | heading_content inline &quot;1.1 heading&quot;
4444+| | | paragraph
4545+| | | | inline &quot;content of nested paragraph&quot;</code></pre>
4646+<p>Onto the converter itself. Every <code>tbsp</code> program is written
4747+as a collection of stanzas. Typically, we start with a stanza like
4848+so:</p>
4949+<pre><code>BEGIN {
5050+ int depth = 0;
5151+5252+ print(&quot;&lt;html&gt;\n&quot;);
5353+ print(&quot;&lt;body&gt;\n&quot;);
5454+}</code></pre>
5555+<p>The stanza begins with a “pattern”, in this case, <code>BEGIN</code>,
5656+and is followed a block of code. This block specifically, is executed
5757+right at the beginning, before traversing the parse tree. In this
5858+stanza, we set a “depth” variable to keep track of nesting of markdown
5959+headers, and begin our html document by printing the
6060+<code>&lt;html&gt;</code> and <code>&lt;body&gt;</code> tags.</p>
6161+<p>We can follow this stanza with an <code>END</code> stanza, that is
6262+executed after the traversal:</p>
6363+<pre><code>END {
6464+ print(&quot;&lt;/body&gt;\n&quot;);
6565+ print(&quot;&lt;/html&gt;\n&quot;);
6666+}</code></pre>
6767+<p>In this stanza, we close off the tags we opened at the start of the
6868+document. We can move onto the interesting bits of the conversion
6969+now:</p>
7070+<pre><code>enter section {
7171+ depth += 1;
7272+}
7373+leave section {
7474+ depth -= 1;
7575+}</code></pre>
7676+<p>The above stanzas begin with <code>enter</code> and
7777+<code>leave</code> clauses, followed by the name of a tree-sitter node
7878+kind: <code>section</code>. The <code>section</code> identifier is
7979+visible in the tree-visualization above, it encompasses a
8080+markdown-section, and is created for every markdown header. To
8181+understand how <code>tbsp</code> executes above stanzas:</p>
8282+<pre><code>document ... depth = 0
8383+| section &lt;-------- enter section (1) ... depth = 1
8484+| | atx_heading
8585+| | | inline
8686+| | paragraph
8787+| | | inline
8888+| | section &lt;----- enter section (2) ... depth = 2
8989+| | | atx_heading
9090+| | | | inline
9191+| | | paragraph
9292+| | | | inline
9393+| | | &lt;----------- leave section (2) ... depth = 1
9494+| | &lt;-------------- leave section (1) ... depth = 0 </code></pre>
9595+<p>The following stanzas should be self-explanatory now:</p>
9696+<pre><code>enter atx_heading {
9797+ print(&quot;&lt;h&quot;);
9898+ print(depth);
9999+ print(&quot;&gt;&quot;);
100100+}
101101+leave atx_heading {
102102+ print(&quot;&lt;/h&quot;);
103103+ print(depth);
104104+ print(&quot;&gt;\n&quot;);
105105+}
106106+107107+enter inline {
108108+ print(text(node));
109109+}</code></pre>
110110+<p>But an explanation is included nonetheless:</p>
111111+<pre><code>document ... depth = 0
112112+| section &lt;-------- enter section (1) ... depth = 1
113113+| | atx_heading &lt;- enter atx_heading ... print &quot;&lt;h1&gt;&quot;
114114+| | | inline &lt;--- enter inline ... print ..
115115+| | | &lt;----------- leave atx_heading ... print &quot;&lt;/h1&gt;&quot;
116116+| | paragraph
117117+| | | inline &lt;--- enter inline ... print ..
118118+| | section &lt;----- enter section (2) ... depth = 2
119119+| | | atx_heading enter atx_heading ... print &quot;&lt;h2&gt;&quot;
120120+| | | | inline &lt;- enter inline ... print ..
121121+| | | | &lt;-------- leave atx_heading ... print &quot;&lt;/h2&gt;&quot;
122122+| | | paragraph
123123+| | | | inline &lt;- enter inline ... print ..
124124+| | | &lt;----------- leave section (2) ... depth = 1
125125+| | &lt;-------------- leave section (1) ... depth = 0 </code></pre>
126126+<p>The <a
127127+href="https://git.peppe.rs/languages/tbsp/tree/examples">examples</a>
128128+directory contains a complete markdown-to-html converter, along with a
129129+few other motivating examples.</p>
130130+<h3 id="usage">Usage</h3>
131131+<p>The <code>tbsp</code> evaluator is written in rust, use cargo to
132132+build and run:</p>
133133+<pre><code>cargo build --release
134134+./target/release/tbsp --help</code></pre>
135135+<p><code>tbsp</code> requires three inputs:</p>
136136+<ul>
137137+<li>a <code>tbsp</code> program, referred to as “program file”</li>
138138+<li>a language</li>
139139+<li>an input file or some input text at stdin</li>
140140+</ul>
141141+<p>You can run the interpreter like so (this program prints an overview
142142+of a rust file):</p>
143143+<pre><code>$ ./target/release/tbsp \
144144+ -f./examples/code-overview/overview.tbsp \
145145+ -l rust \
146146+ src/main.rs
147147+module
148148+ └╴struct Cli
149149+ └╴trait Cli
150150+ └╴fn program
151151+ └╴fn language
152152+ └╴fn file
153153+ └╴fn try_consume_stdin
154154+ └╴fn main</code></pre></description>
155155+<link>https://peppe.rs/posts/introducing_tablespoon/</link>
156156+<pubDate>Thu, 01 Aug 2024 19:18:00 +0000</pubDate>
157157+<guid>https://peppe.rs/posts/introducing_tablespoon/</guid>
158158+</item>
159159+<item>
15160<title>Snip Snap</title>
16161<description><p>I regularly switch between exactly two things while working, a
17162“current” and an “alternate” item; a lot of tools I use seem to support
···11+[tbsp](https://git.peppe.rs/languages/tbsp) (tree-based
22+source-processing language) is an awk-like language that
33+operates on tree-sitter syntax trees. To motivate the need
44+for such a program, we could begin by writing a
55+markdown-to-html converter using `tbsp` and
66+[tree-sitter-md](https://github.com/tree-sitter-grammars/tree-sitter-markdown).
77+We need some markdown to begin with:
88+99+1010+ # 1 heading
1111+1212+ content of first paragraph
1313+1414+ ## 1.1 heading
1515+1616+ content of nested paragraph
1717+1818+1919+For future reference, this markdown is parsed like so by
2020+tree-sitter-md (visualization generated by
2121+[tree-viz](https://git.peppe.rs/cli/tree-viz)):
2222+2323+2424+ document
2525+ | section
2626+ | | atx_heading
2727+ | | | atx_h1_marker "#"
2828+ | | | heading_content inline "1 heading"
2929+ | | paragraph
3030+ | | | inline "content of first paragraph"
3131+ | | section
3232+ | | | atx_heading
3333+ | | | | atx_h2_marker "##"
3434+ | | | | heading_content inline "1.1 heading"
3535+ | | | paragraph
3636+ | | | | inline "content of nested paragraph"
3737+3838+3939+Onto the converter itself. Every `tbsp` program is written as
4040+a collection of stanzas. Typically, we start with a stanza
4141+like so:
4242+4343+4444+ BEGIN {
4545+ int depth = 0;
4646+4747+ print("<html>\n");
4848+ print("<body>\n");
4949+ }
5050+5151+5252+The stanza begins with a "pattern", in this case, `BEGIN`,
5353+and is followed a block of code. This block specifically, is
5454+executed right at the beginning, before traversing the parse
5555+tree. In this stanza, we set a "depth" variable to keep
5656+track of nesting of markdown headers, and begin our html
5757+document by printing the `<html>` and `<body>` tags.
5858+5959+We can follow this stanza with an `END` stanza, that is
6060+executed after the traversal:
6161+6262+6363+ END {
6464+ print("</body>\n");
6565+ print("</html>\n");
6666+ }
6767+6868+6969+In this stanza, we close off the tags we opened at the start
7070+of the document. We can move onto the interesting bits of
7171+the conversion now:
7272+7373+7474+ enter section {
7575+ depth += 1;
7676+ }
7777+ leave section {
7878+ depth -= 1;
7979+ }
8080+8181+8282+The above stanzas begin with `enter` and `leave` clauses,
8383+followed by the name of a tree-sitter node kind: `section`.
8484+The `section` identifier is visible in the
8585+tree-visualization above, it encompasses a markdown-section,
8686+and is created for every markdown header. To understand how
8787+`tbsp` executes above stanzas:
8888+8989+9090+ document ... depth = 0
9191+ | section <-------- enter section (1) ... depth = 1
9292+ | | atx_heading
9393+ | | | inline
9494+ | | paragraph
9595+ | | | inline
9696+ | | section <----- enter section (2) ... depth = 2
9797+ | | | atx_heading
9898+ | | | | inline
9999+ | | | paragraph
100100+ | | | | inline
101101+ | | | <----------- leave section (2) ... depth = 1
102102+ | | <-------------- leave section (1) ... depth = 0
103103+104104+105105+The following stanzas should be self-explanatory now:
106106+107107+108108+ enter atx_heading {
109109+ print("<h");
110110+ print(depth);
111111+ print(">");
112112+ }
113113+ leave atx_heading {
114114+ print("</h");
115115+ print(depth);
116116+ print(">\n");
117117+ }
118118+119119+ enter inline {
120120+ print(text(node));
121121+ }
122122+123123+124124+But an explanation is included nonetheless:
125125+126126+127127+ document ... depth = 0
128128+ | section <-------- enter section (1) ... depth = 1
129129+ | | atx_heading <- enter atx_heading ... print "<h1>"
130130+ | | | inline <--- enter inline ... print ..
131131+ | | | <----------- leave atx_heading ... print "</h1>"
132132+ | | paragraph
133133+ | | | inline <--- enter inline ... print ..
134134+ | | section <----- enter section (2) ... depth = 2
135135+ | | | atx_heading enter atx_heading ... print "<h2>"
136136+ | | | | inline <- enter inline ... print ..
137137+ | | | | <-------- leave atx_heading ... print "</h2>"
138138+ | | | paragraph
139139+ | | | | inline <- enter inline ... print ..
140140+ | | | <----------- leave section (2) ... depth = 1
141141+ | | <-------------- leave section (1) ... depth = 0
142142+143143+144144+The
145145+[examples](https://git.peppe.rs/languages/tbsp/tree/examples)
146146+directory contains a complete markdown-to-html converter,
147147+along with a few other motivating examples.
148148+149149+### Usage
150150+151151+The `tbsp` evaluator is written in rust, use cargo to build
152152+and run:
153153+154154+ cargo build --release
155155+ ./target/release/tbsp --help
156156+157157+158158+`tbsp` requires three inputs:
159159+160160+- a `tbsp` program, referred to as "program file"
161161+- a language
162162+- an input file or some input text at stdin
163163+164164+165165+You can run the interpreter like so (this program prints an
166166+overview of a rust file):
167167+168168+ $ ./target/release/tbsp \
169169+ -f./examples/code-overview/overview.tbsp \
170170+ -l rust \
171171+ src/main.rs
172172+ module
173173+ └╴struct Cli
174174+ └╴trait Cli
175175+ └╴fn program
176176+ └╴fn language
177177+ └╴fn file
178178+ └╴fn try_consume_stdin
179179+ └╴fn main
180180+181181+