diff options
-rw-r--r-- | docs/index.html | 24 | ||||
-rw-r--r-- | docs/index.xml | 145 | ||||
-rw-r--r-- | docs/posts/index.html | 17 | ||||
-rw-r--r-- | docs/posts/introducing_tablespoon/index.html | 211 | ||||
-rw-r--r-- | docs/style.css | 7 | ||||
-rw-r--r-- | posts/introducing_tablespoon.md | 181 |
6 files changed, 571 insertions, 14 deletions
diff --git a/docs/index.html b/docs/index.html index d42ab2b..2d9b619 100644 --- a/docs/index.html +++ b/docs/index.html | |||
@@ -39,15 +39,15 @@ | |||
39 | <tr> | 39 | <tr> |
40 | <td class=table-post> | 40 | <td class=table-post> |
41 | <div class="date"> | 41 | <div class="date"> |
42 | 29/05 — 2024 | 42 | 01/08 — 2024 |
43 | </div> | 43 | </div> |
44 | <a href="/posts/snip_snap" class="post-link"> | 44 | <a href="/posts/introducing_tablespoon" class="post-link"> |
45 | <span class="post-link">Snip Snap</span> | 45 | <span class="post-link">Introducing Tablespoon</span> |
46 | </a> | 46 | </a> |
47 | </td> | 47 | </td> |
48 | <td class=table-stats> | 48 | <td class=table-stats> |
49 | <span class="stats-number"> | 49 | <span class="stats-number"> |
50 | 2.1 | 50 | 4.5 |
51 | </span> | 51 | </span> |
52 | <span class=stats-unit>min</span> | 52 | <span class=stats-unit>min</span> |
53 | </td> | 53 | </td> |
@@ -56,15 +56,15 @@ | |||
56 | <tr> | 56 | <tr> |
57 | <td class=table-post> | 57 | <td class=table-post> |
58 | <div class="date"> | 58 | <div class="date"> |
59 | 18/06 — 2023 | 59 | 29/05 — 2024 |
60 | </div> | 60 | </div> |
61 | <a href="/posts/plain_text_journaling" class="post-link"> | 61 | <a href="/posts/snip_snap" class="post-link"> |
62 | <span class="post-link">Plain Text Journaling</span> | 62 | <span class="post-link">Snip Snap</span> |
63 | </a> | 63 | </a> |
64 | </td> | 64 | </td> |
65 | <td class=table-stats> | 65 | <td class=table-stats> |
66 | <span class="stats-number"> | 66 | <span class="stats-number"> |
67 | 8.9 | 67 | 2.1 |
68 | </span> | 68 | </span> |
69 | <span class=stats-unit>min</span> | 69 | <span class=stats-unit>min</span> |
70 | </td> | 70 | </td> |
@@ -73,15 +73,15 @@ | |||
73 | <tr> | 73 | <tr> |
74 | <td class=table-post> | 74 | <td class=table-post> |
75 | <div class="date"> | 75 | <div class="date"> |
76 | 03/09 — 2022 | 76 | 18/06 — 2023 |
77 | </div> | 77 | </div> |
78 | <a href="/posts/curing_a_case_of_git-UX" class="post-link"> | 78 | <a href="/posts/plain_text_journaling" class="post-link"> |
79 | <span class="post-link">Curing A Case Of Git-UX</span> | 79 | <span class="post-link">Plain Text Journaling</span> |
80 | </a> | 80 | </a> |
81 | </td> | 81 | </td> |
82 | <td class=table-stats> | 82 | <td class=table-stats> |
83 | <span class="stats-number"> | 83 | <span class="stats-number"> |
84 | 9.6 | 84 | 8.9 |
85 | </span> | 85 | </span> |
86 | <span class=stats-unit>min</span> | 86 | <span class=stats-unit>min</span> |
87 | </td> | 87 | </td> |
diff --git a/docs/index.xml b/docs/index.xml index 9245aba..eec76ca 100644 --- a/docs/index.xml +++ b/docs/index.xml | |||
@@ -12,6 +12,151 @@ | |||
12 | <language>en-us</language> | 12 | <language>en-us</language> |
13 | <copyright>Creative Commons BY-NC-SA 4.0</copyright> | 13 | <copyright>Creative Commons BY-NC-SA 4.0</copyright> |
14 | <item> | 14 | <item> |
15 | <title>Introducing Tablespoon</title> | ||
16 | <description><p><a href="https://git.peppe.rs/languages/tbsp">tbsp</a> (tree-based | ||
17 | source-processing language) is an awk-like language that operates on | ||
18 | tree-sitter syntax trees. To motivate the need for such a program, we | ||
19 | could begin by writing a markdown-to-html converter using | ||
20 | <code>tbsp</code> and <a | ||
21 | href="https://github.com/tree-sitter-grammars/tree-sitter-markdown">tree-sitter-md</a>. | ||
22 | We need some markdown to begin with:</p> | ||
23 | <pre><code># 1 heading | ||
24 | |||
25 | content of first paragraph | ||
26 | |||
27 | ## 1.1 heading | ||
28 | |||
29 | content of nested paragraph</code></pre> | ||
30 | <p>For future reference, this markdown is parsed like so by | ||
31 | tree-sitter-md (visualization generated by <a | ||
32 | href="https://git.peppe.rs/cli/tree-viz">tree-viz</a>):</p> | ||
33 | <pre><code>document | ||
34 | | section | ||
35 | | | atx_heading | ||
36 | | | | atx_h1_marker &quot;#&quot; | ||
37 | | | | heading_content inline &quot;1 heading&quot; | ||
38 | | | paragraph | ||
39 | | | | inline &quot;content of first paragraph&quot; | ||
40 | | | section | ||
41 | | | | atx_heading | ||
42 | | | | | atx_h2_marker &quot;##&quot; | ||
43 | | | | | heading_content inline &quot;1.1 heading&quot; | ||
44 | | | | paragraph | ||
45 | | | | | inline &quot;content of nested paragraph&quot;</code></pre> | ||
46 | <p>Onto the converter itself. Every <code>tbsp</code> program is written | ||
47 | as a collection of stanzas. Typically, we start with a stanza like | ||
48 | so:</p> | ||
49 | <pre><code>BEGIN { | ||
50 | int depth = 0; | ||
51 | |||
52 | print(&quot;&lt;html&gt;\n&quot;); | ||
53 | print(&quot;&lt;body&gt;\n&quot;); | ||
54 | }</code></pre> | ||
55 | <p>The stanza begins with a “pattern”, in this case, <code>BEGIN</code>, | ||
56 | and is followed a block of code. This block specifically, is executed | ||
57 | right at the beginning, before traversing the parse tree. In this | ||
58 | stanza, we set a “depth” variable to keep track of nesting of markdown | ||
59 | headers, and begin our html document by printing the | ||
60 | <code>&lt;html&gt;</code> and <code>&lt;body&gt;</code> tags.</p> | ||
61 | <p>We can follow this stanza with an <code>END</code> stanza, that is | ||
62 | executed after the traversal:</p> | ||
63 | <pre><code>END { | ||
64 | print(&quot;&lt;/body&gt;\n&quot;); | ||
65 | print(&quot;&lt;/html&gt;\n&quot;); | ||
66 | }</code></pre> | ||
67 | <p>In this stanza, we close off the tags we opened at the start of the | ||
68 | document. We can move onto the interesting bits of the conversion | ||
69 | now:</p> | ||
70 | <pre><code>enter section { | ||
71 | depth += 1; | ||
72 | } | ||
73 | leave section { | ||
74 | depth -= 1; | ||
75 | }</code></pre> | ||
76 | <p>The above stanzas begin with <code>enter</code> and | ||
77 | <code>leave</code> clauses, followed by the name of a tree-sitter node | ||
78 | kind: <code>section</code>. The <code>section</code> identifier is | ||
79 | visible in the tree-visualization above, it encompasses a | ||
80 | markdown-section, and is created for every markdown header. To | ||
81 | understand how <code>tbsp</code> executes above stanzas:</p> | ||
82 | <pre><code>document ... depth = 0 | ||
83 | | section &lt;-------- enter section (1) ... depth = 1 | ||
84 | | | atx_heading | ||
85 | | | | inline | ||
86 | | | paragraph | ||
87 | | | | inline | ||
88 | | | section &lt;----- enter section (2) ... depth = 2 | ||
89 | | | | atx_heading | ||
90 | | | | | inline | ||
91 | | | | paragraph | ||
92 | | | | | inline | ||
93 | | | | &lt;----------- leave section (2) ... depth = 1 | ||
94 | | | &lt;-------------- leave section (1) ... depth = 0 </code></pre> | ||
95 | <p>The following stanzas should be self-explanatory now:</p> | ||
96 | <pre><code>enter atx_heading { | ||
97 | print(&quot;&lt;h&quot;); | ||
98 | print(depth); | ||
99 | print(&quot;&gt;&quot;); | ||
100 | } | ||
101 | leave atx_heading { | ||
102 | print(&quot;&lt;/h&quot;); | ||
103 | print(depth); | ||
104 | print(&quot;&gt;\n&quot;); | ||
105 | } | ||
106 | |||
107 | enter inline { | ||
108 | print(text(node)); | ||
109 | }</code></pre> | ||
110 | <p>But an explanation is included nonetheless:</p> | ||
111 | <pre><code>document ... depth = 0 | ||
112 | | section &lt;-------- enter section (1) ... depth = 1 | ||
113 | | | atx_heading &lt;- enter atx_heading ... print &quot;&lt;h1&gt;&quot; | ||
114 | | | | inline &lt;--- enter inline ... print .. | ||
115 | | | | &lt;----------- leave atx_heading ... print &quot;&lt;/h1&gt;&quot; | ||
116 | | | paragraph | ||
117 | | | | inline &lt;--- enter inline ... print .. | ||
118 | | | section &lt;----- enter section (2) ... depth = 2 | ||
119 | | | | atx_heading enter atx_heading ... print &quot;&lt;h2&gt;&quot; | ||
120 | | | | | inline &lt;- enter inline ... print .. | ||
121 | | | | | &lt;-------- leave atx_heading ... print &quot;&lt;/h2&gt;&quot; | ||
122 | | | | paragraph | ||
123 | | | | | inline &lt;- enter inline ... print .. | ||
124 | | | | &lt;----------- leave section (2) ... depth = 1 | ||
125 | | | &lt;-------------- leave section (1) ... depth = 0 </code></pre> | ||
126 | <p>The <a | ||
127 | href="https://git.peppe.rs/languages/tbsp/tree/examples">examples</a> | ||
128 | directory contains a complete markdown-to-html converter, along with a | ||
129 | few other motivating examples.</p> | ||
130 | <h3 id="usage">Usage</h3> | ||
131 | <p>The <code>tbsp</code> evaluator is written in rust, use cargo to | ||
132 | build and run:</p> | ||
133 | <pre><code>cargo build --release | ||
134 | ./target/release/tbsp --help</code></pre> | ||
135 | <p><code>tbsp</code> requires three inputs:</p> | ||
136 | <ul> | ||
137 | <li>a <code>tbsp</code> program, referred to as “program file”</li> | ||
138 | <li>a language</li> | ||
139 | <li>an input file or some input text at stdin</li> | ||
140 | </ul> | ||
141 | <p>You can run the interpreter like so (this program prints an overview | ||
142 | of a rust file):</p> | ||
143 | <pre><code>$ ./target/release/tbsp \ | ||
144 | -f./examples/code-overview/overview.tbsp \ | ||
145 | -l rust \ | ||
146 | src/main.rs | ||
147 | module | ||
148 | └╴struct Cli | ||
149 | └╴trait Cli | ||
150 | └╴fn program | ||
151 | └╴fn language | ||
152 | └╴fn file | ||
153 | └╴fn try_consume_stdin | ||
154 | └╴fn main</code></pre></description> | ||
155 | <link>https://peppe.rs/posts/introducing_tablespoon/</link> | ||
156 | <pubDate>Thu, 01 Aug 2024 19:18:00 +0000</pubDate> | ||
157 | <guid>https://peppe.rs/posts/introducing_tablespoon/</guid> | ||
158 | </item> | ||
159 | <item> | ||
15 | <title>Snip Snap</title> | 160 | <title>Snip Snap</title> |
16 | <description><p>I regularly switch between exactly two things while working, a | 161 | <description><p>I regularly switch between exactly two things while working, a |
17 | “current” and an “alternate” item; a lot of tools I use seem to support | 162 | “current” and an “alternate” item; a lot of tools I use seem to support |
diff --git a/docs/posts/index.html b/docs/posts/index.html index ca9a3ac..a8d321c 100644 --- a/docs/posts/index.html +++ b/docs/posts/index.html | |||
@@ -27,6 +27,23 @@ | |||
27 | <tr> | 27 | <tr> |
28 | <td class=table-post> | 28 | <td class=table-post> |
29 | <div class="date"> | 29 | <div class="date"> |
30 | 01/08 — 2024 | ||
31 | </div> | ||
32 | <a href="/posts/introducing_tablespoon" class="post-link"> | ||
33 | <span class="post-link">Introducing Tablespoon</span> | ||
34 | </a> | ||
35 | </td> | ||
36 | <td class=table-stats> | ||
37 | <span class="stats-number"> | ||
38 | 4.5 | ||
39 | </span> | ||
40 | <span class=stats-unit>min</span> | ||
41 | </td> | ||
42 | </tr> | ||
43 | |||
44 | <tr> | ||
45 | <td class=table-post> | ||
46 | <div class="date"> | ||
30 | 29/05 — 2024 | 47 | 29/05 — 2024 |
31 | </div> | 48 | </div> |
32 | <a href="/posts/snip_snap" class="post-link"> | 49 | <a href="/posts/snip_snap" class="post-link"> |
diff --git a/docs/posts/introducing_tablespoon/index.html b/docs/posts/introducing_tablespoon/index.html new file mode 100644 index 0000000..a6f6ef2 --- /dev/null +++ b/docs/posts/introducing_tablespoon/index.html | |||
@@ -0,0 +1,211 @@ | |||
1 | <!DOCTYPE html> | ||
2 | <html lang="en"> | ||
3 | <head> | ||
4 | <link rel="stylesheet" href="/style.css"> | ||
5 | <link rel="stylesheet" href="/syntax.css"> | ||
6 | <meta charset="UTF-8"> | ||
7 | <meta name="viewport" content="initial-scale=1"> | ||
8 | <meta content="#ffffff" name="theme-color"> | ||
9 | <meta name="HandheldFriendly" content="true"> | ||
10 | <meta property="og:title" content="Introducing Tablespoon"> | ||
11 | <meta property="og:type" content="website"> | ||
12 | <meta property="og:description" content="a static site {for, by, about} me "> | ||
13 | <meta property="og:url" content="https://peppe.rs"> | ||
14 | <link rel="icon" type="image/x-icon" href="/favicon.png"> | ||
15 | <title>Introducing Tablespoon · peppe.rs</title> | ||
16 | <body> | ||
17 | <div class="posts"> | ||
18 | <div class="post"> | ||
19 | <a href="/" class="post-end-link">Home</a> | ||
20 | <span>/</span> | ||
21 | <a href="/posts" class="post-end-link">Posts</a> | ||
22 | <span>/</span> | ||
23 | <a class="post-end-link">Introducing Tablespoon</a> | ||
24 | <a class="stats post-end-link" href="https://git.peppe.rs/web/site/plain/posts/introducing_tablespoon.md | ||
25 | ">View Raw</a> | ||
26 | <div class="separator"></div> | ||
27 | <div class="date"> | ||
28 | 01/08 — 2024 | ||
29 | <div class="stats"> | ||
30 | <span class="stats-number"> | ||
31 | 72.33 | ||
32 | </span> | ||
33 | <span class="stats-unit">cm</span> | ||
34 |   | ||
35 | <span class="stats-number"> | ||
36 | 4.5 | ||
37 | </span> | ||
38 | <span class="stats-unit">min</span> | ||
39 | </div> | ||
40 | </div> | ||
41 | <h1> | ||
42 | Introducing Tablespoon | ||
43 | </h1> | ||
44 | <div class="post-text"> | ||
45 | <p><a href="https://git.peppe.rs/languages/tbsp">tbsp</a> (tree-based | ||
46 | source-processing language) is an awk-like language that operates on | ||
47 | tree-sitter syntax trees. To motivate the need for such a program, we | ||
48 | could begin by writing a markdown-to-html converter using | ||
49 | <code>tbsp</code> and <a | ||
50 | href="https://github.com/tree-sitter-grammars/tree-sitter-markdown">tree-sitter-md</a>. | ||
51 | We need some markdown to begin with:</p> | ||
52 | <pre><code># 1 heading | ||
53 | |||
54 | content of first paragraph | ||
55 | |||
56 | ## 1.1 heading | ||
57 | |||
58 | content of nested paragraph</code></pre> | ||
59 | <p>For future reference, this markdown is parsed like so by | ||
60 | tree-sitter-md (visualization generated by <a | ||
61 | href="https://git.peppe.rs/cli/tree-viz">tree-viz</a>):</p> | ||
62 | <pre><code>document | ||
63 | | section | ||
64 | | | atx_heading | ||
65 | | | | atx_h1_marker "#" | ||
66 | | | | heading_content inline "1 heading" | ||
67 | | | paragraph | ||
68 | | | | inline "content of first paragraph" | ||
69 | | | section | ||
70 | | | | atx_heading | ||
71 | | | | | atx_h2_marker "##" | ||
72 | | | | | heading_content inline "1.1 heading" | ||
73 | | | | paragraph | ||
74 | | | | | inline "content of nested paragraph"</code></pre> | ||
75 | <p>Onto the converter itself. Every <code>tbsp</code> program is written | ||
76 | as a collection of stanzas. Typically, we start with a stanza like | ||
77 | so:</p> | ||
78 | <pre><code>BEGIN { | ||
79 | int depth = 0; | ||
80 | |||
81 | print("<html>\n"); | ||
82 | print("<body>\n"); | ||
83 | }</code></pre> | ||
84 | <p>The stanza begins with a “pattern”, in this case, <code>BEGIN</code>, | ||
85 | and is followed a block of code. This block specifically, is executed | ||
86 | right at the beginning, before traversing the parse tree. In this | ||
87 | stanza, we set a “depth” variable to keep track of nesting of markdown | ||
88 | headers, and begin our html document by printing the | ||
89 | <code><html></code> and <code><body></code> tags.</p> | ||
90 | <p>We can follow this stanza with an <code>END</code> stanza, that is | ||
91 | executed after the traversal:</p> | ||
92 | <pre><code>END { | ||
93 | print("</body>\n"); | ||
94 | print("</html>\n"); | ||
95 | }</code></pre> | ||
96 | <p>In this stanza, we close off the tags we opened at the start of the | ||
97 | document. We can move onto the interesting bits of the conversion | ||
98 | now:</p> | ||
99 | <pre><code>enter section { | ||
100 | depth += 1; | ||
101 | } | ||
102 | leave section { | ||
103 | depth -= 1; | ||
104 | }</code></pre> | ||
105 | <p>The above stanzas begin with <code>enter</code> and | ||
106 | <code>leave</code> clauses, followed by the name of a tree-sitter node | ||
107 | kind: <code>section</code>. The <code>section</code> identifier is | ||
108 | visible in the tree-visualization above, it encompasses a | ||
109 | markdown-section, and is created for every markdown header. To | ||
110 | understand how <code>tbsp</code> executes above stanzas:</p> | ||
111 | <pre><code>document ... depth = 0 | ||
112 | | section <-------- enter section (1) ... depth = 1 | ||
113 | | | atx_heading | ||
114 | | | | inline | ||
115 | | | paragraph | ||
116 | | | | inline | ||
117 | | | section <----- enter section (2) ... depth = 2 | ||
118 | | | | atx_heading | ||
119 | | | | | inline | ||
120 | | | | paragraph | ||
121 | | | | | inline | ||
122 | | | | <----------- leave section (2) ... depth = 1 | ||
123 | | | <-------------- leave section (1) ... depth = 0 </code></pre> | ||
124 | <p>The following stanzas should be self-explanatory now:</p> | ||
125 | <pre><code>enter atx_heading { | ||
126 | print("<h"); | ||
127 | print(depth); | ||
128 | print(">"); | ||
129 | } | ||
130 | leave atx_heading { | ||
131 | print("</h"); | ||
132 | print(depth); | ||
133 | print(">\n"); | ||
134 | } | ||
135 | |||
136 | enter inline { | ||
137 | print(text(node)); | ||
138 | }</code></pre> | ||
139 | <p>But an explanation is included nonetheless:</p> | ||
140 | <pre><code>document ... depth = 0 | ||
141 | | section <-------- enter section (1) ... depth = 1 | ||
142 | | | atx_heading <- enter atx_heading ... print "<h1>" | ||
143 | | | | inline <--- enter inline ... print .. | ||
144 | | | | <----------- leave atx_heading ... print "</h1>" | ||
145 | | | paragraph | ||
146 | | | | inline <--- enter inline ... print .. | ||
147 | | | section <----- enter section (2) ... depth = 2 | ||
148 | | | | atx_heading enter atx_heading ... print "<h2>" | ||
149 | | | | | inline <- enter inline ... print .. | ||
150 | | | | | <-------- leave atx_heading ... print "</h2>" | ||
151 | | | | paragraph | ||
152 | | | | | inline <- enter inline ... print .. | ||
153 | | | | <----------- leave section (2) ... depth = 1 | ||
154 | | | <-------------- leave section (1) ... depth = 0 </code></pre> | ||
155 | <p>The <a | ||
156 | href="https://git.peppe.rs/languages/tbsp/tree/examples">examples</a> | ||
157 | directory contains a complete markdown-to-html converter, along with a | ||
158 | few other motivating examples.</p> | ||
159 | <h3 id="usage">Usage</h3> | ||
160 | <p>The <code>tbsp</code> evaluator is written in rust, use cargo to | ||
161 | build and run:</p> | ||
162 | <pre><code>cargo build --release | ||
163 | ./target/release/tbsp --help</code></pre> | ||
164 | <p><code>tbsp</code> requires three inputs:</p> | ||
165 | <ul> | ||
166 | <li>a <code>tbsp</code> program, referred to as “program file”</li> | ||
167 | <li>a language</li> | ||
168 | <li>an input file or some input text at stdin</li> | ||
169 | </ul> | ||
170 | <p>You can run the interpreter like so (this program prints an overview | ||
171 | of a rust file):</p> | ||
172 | <pre><code>$ ./target/release/tbsp \ | ||
173 | -f./examples/code-overview/overview.tbsp \ | ||
174 | -l rust \ | ||
175 | src/main.rs | ||
176 | module | ||
177 | └╴struct Cli | ||
178 | └╴trait Cli | ||
179 | └╴fn program | ||
180 | └╴fn language | ||
181 | └╴fn file | ||
182 | └╴fn try_consume_stdin | ||
183 | └╴fn main</code></pre> | ||
184 | |||
185 | </div> | ||
186 | |||
187 | <div class="intro"> | ||
188 | Hi. | ||
189 | <div class="hot-links"> | ||
190 | <a href="/index.xml" class="feed-button">Subscribe</a> | ||
191 | </div> | ||
192 | <p>I'm Akshay, programmer and pixel-artist. | ||
193 | I write <a href="https://git.peppe.rs">open-source stuff</a>. | ||
194 | I also design fonts: | ||
195 | <a href="https://git.peppe.rs/fonts/scientifica/about">scientifica</a>, | ||
196 | <a href="https://git.peppe.rs/fonts/curie/about">curie</a>. | ||
197 | </p> | ||
198 | <p>Reach out at [email protected].</p> | ||
199 | </div> | ||
200 | |||
201 | <a href="/" class="post-end-link">Home</a> | ||
202 | <span>/</span> | ||
203 | <a href="/posts" class="post-end-link">Posts</a> | ||
204 | <span>/</span> | ||
205 | <a class="post-end-link">Introducing Tablespoon</a> | ||
206 | <a class="stats post-end-link" href="https://git.peppe.rs/web/site/plain/posts/introducing_tablespoon.md | ||
207 | ">View Raw</a> | ||
208 | </div> | ||
209 | </div> | ||
210 | </body> | ||
211 | </html> | ||
diff --git a/docs/style.css b/docs/style.css index d4a8391..04f78a8 100644 --- a/docs/style.css +++ b/docs/style.css | |||
@@ -52,10 +52,13 @@ div.hot-links { | |||
52 | } | 52 | } |
53 | } | 53 | } |
54 | 54 | ||
55 | body { font-family: 'Inter', sans-serif; } | 55 | body { |
56 | font-family: 'Inter', sans-serif; | ||
57 | font-feature-settings: 'liga' 1, 'calt' 1; /* fix for Chrome */ | ||
58 | } | ||
56 | @supports (font-variation-settings: normal) { | 59 | @supports (font-variation-settings: normal) { |
57 | body { | 60 | body { |
58 | font-family: 'Inter var', sans-serif; | 61 | font-family: 'InterVariable', sans-serif; |
59 | font-feature-settings: 'ss01' 1, 'kern' 1, 'liga' 1, 'cv05' 1, 'tnum' 1; | 62 | font-feature-settings: 'ss01' 1, 'kern' 1, 'liga' 1, 'cv05' 1, 'tnum' 1; |
60 | } | 63 | } |
61 | } | 64 | } |
diff --git a/posts/introducing_tablespoon.md b/posts/introducing_tablespoon.md new file mode 100644 index 0000000..957b6d4 --- /dev/null +++ b/posts/introducing_tablespoon.md | |||
@@ -0,0 +1,181 @@ | |||
1 | [tbsp](https://git.peppe.rs/languages/tbsp) (tree-based | ||
2 | source-processing language) is an awk-like language that | ||
3 | operates on tree-sitter syntax trees. To motivate the need | ||
4 | for such a program, we could begin by writing a | ||
5 | markdown-to-html converter using `tbsp` and | ||
6 | [tree-sitter-md](https://github.com/tree-sitter-grammars/tree-sitter-markdown). | ||
7 | We need some markdown to begin with: | ||
8 | |||
9 | |||
10 | # 1 heading | ||
11 | |||
12 | content of first paragraph | ||
13 | |||
14 | ## 1.1 heading | ||
15 | |||
16 | content of nested paragraph | ||
17 | |||
18 | |||
19 | For future reference, this markdown is parsed like so by | ||
20 | tree-sitter-md (visualization generated by | ||
21 | [tree-viz](https://git.peppe.rs/cli/tree-viz)): | ||
22 | |||
23 | |||
24 | document | ||
25 | | section | ||
26 | | | atx_heading | ||
27 | | | | atx_h1_marker "#" | ||
28 | | | | heading_content inline "1 heading" | ||
29 | | | paragraph | ||
30 | | | | inline "content of first paragraph" | ||
31 | | | section | ||
32 | | | | atx_heading | ||
33 | | | | | atx_h2_marker "##" | ||
34 | | | | | heading_content inline "1.1 heading" | ||
35 | | | | paragraph | ||
36 | | | | | inline "content of nested paragraph" | ||
37 | |||
38 | |||
39 | Onto the converter itself. Every `tbsp` program is written as | ||
40 | a collection of stanzas. Typically, we start with a stanza | ||
41 | like so: | ||
42 | |||
43 | |||
44 | BEGIN { | ||
45 | int depth = 0; | ||
46 | |||
47 | print("<html>\n"); | ||
48 | print("<body>\n"); | ||
49 | } | ||
50 | |||
51 | |||
52 | The stanza begins with a "pattern", in this case, `BEGIN`, | ||
53 | and is followed a block of code. This block specifically, is | ||
54 | executed right at the beginning, before traversing the parse | ||
55 | tree. In this stanza, we set a "depth" variable to keep | ||
56 | track of nesting of markdown headers, and begin our html | ||
57 | document by printing the `<html>` and `<body>` tags. | ||
58 | |||
59 | We can follow this stanza with an `END` stanza, that is | ||
60 | executed after the traversal: | ||
61 | |||
62 | |||
63 | END { | ||
64 | print("</body>\n"); | ||
65 | print("</html>\n"); | ||
66 | } | ||
67 | |||
68 | |||
69 | In this stanza, we close off the tags we opened at the start | ||
70 | of the document. We can move onto the interesting bits of | ||
71 | the conversion now: | ||
72 | |||
73 | |||
74 | enter section { | ||
75 | depth += 1; | ||
76 | } | ||
77 | leave section { | ||
78 | depth -= 1; | ||
79 | } | ||
80 | |||
81 | |||
82 | The above stanzas begin with `enter` and `leave` clauses, | ||
83 | followed by the name of a tree-sitter node kind: `section`. | ||
84 | The `section` identifier is visible in the | ||
85 | tree-visualization above, it encompasses a markdown-section, | ||
86 | and is created for every markdown header. To understand how | ||
87 | `tbsp` executes above stanzas: | ||
88 | |||
89 | |||
90 | document ... depth = 0 | ||
91 | | section <-------- enter section (1) ... depth = 1 | ||
92 | | | atx_heading | ||
93 | | | | inline | ||
94 | | | paragraph | ||
95 | | | | inline | ||
96 | | | section <----- enter section (2) ... depth = 2 | ||
97 | | | | atx_heading | ||
98 | | | | | inline | ||
99 | | | | paragraph | ||
100 | | | | | inline | ||
101 | | | | <----------- leave section (2) ... depth = 1 | ||
102 | | | <-------------- leave section (1) ... depth = 0 | ||
103 | |||
104 | |||
105 | The following stanzas should be self-explanatory now: | ||
106 | |||
107 | |||
108 | enter atx_heading { | ||
109 | print("<h"); | ||
110 | print(depth); | ||
111 | print(">"); | ||
112 | } | ||
113 | leave atx_heading { | ||
114 | print("</h"); | ||
115 | print(depth); | ||
116 | print(">\n"); | ||
117 | } | ||
118 | |||
119 | enter inline { | ||
120 | print(text(node)); | ||
121 | } | ||
122 | |||
123 | |||
124 | But an explanation is included nonetheless: | ||
125 | |||
126 | |||
127 | document ... depth = 0 | ||
128 | | section <-------- enter section (1) ... depth = 1 | ||
129 | | | atx_heading <- enter atx_heading ... print "<h1>" | ||
130 | | | | inline <--- enter inline ... print .. | ||
131 | | | | <----------- leave atx_heading ... print "</h1>" | ||
132 | | | paragraph | ||
133 | | | | inline <--- enter inline ... print .. | ||
134 | | | section <----- enter section (2) ... depth = 2 | ||
135 | | | | atx_heading enter atx_heading ... print "<h2>" | ||
136 | | | | | inline <- enter inline ... print .. | ||
137 | | | | | <-------- leave atx_heading ... print "</h2>" | ||
138 | | | | paragraph | ||
139 | | | | | inline <- enter inline ... print .. | ||
140 | | | | <----------- leave section (2) ... depth = 1 | ||
141 | | | <-------------- leave section (1) ... depth = 0 | ||
142 | |||
143 | |||
144 | The | ||
145 | [examples](https://git.peppe.rs/languages/tbsp/tree/examples) | ||
146 | directory contains a complete markdown-to-html converter, | ||
147 | along with a few other motivating examples. | ||
148 | |||
149 | ### Usage | ||
150 | |||
151 | The `tbsp` evaluator is written in rust, use cargo to build | ||
152 | and run: | ||
153 | |||
154 | cargo build --release | ||
155 | ./target/release/tbsp --help | ||
156 | |||
157 | |||
158 | `tbsp` requires three inputs: | ||
159 | |||
160 | - a `tbsp` program, referred to as "program file" | ||
161 | - a language | ||
162 | - an input file or some input text at stdin | ||
163 | |||
164 | |||
165 | You can run the interpreter like so (this program prints an | ||
166 | overview of a rust file): | ||
167 | |||
168 | $ ./target/release/tbsp \ | ||
169 | -f./examples/code-overview/overview.tbsp \ | ||
170 | -l rust \ | ||
171 | src/main.rs | ||
172 | module | ||
173 | └╴struct Cli | ||
174 | └╴trait Cli | ||
175 | └╴fn program | ||
176 | └╴fn language | ||
177 | └╴fn file | ||
178 | └╴fn try_consume_stdin | ||
179 | └╴fn main | ||
180 | |||
181 | |||