diff options
author | Akshay <[email protected]> | 2024-08-01 20:24:57 +0100 |
---|---|---|
committer | Akshay <[email protected]> | 2024-08-01 20:24:57 +0100 |
commit | 9828c78d95f2195cd8e1db04887072cd5f48005b (patch) | |
tree | b5368e31598cd42fcd875b9cb37bfcc6e43a03ff /docs/posts/introducing_tablespoon/index.html | |
parent | 6078433f88969853ae488b8529b7538d342862a8 (diff) |
new post: tablespoon
Diffstat (limited to 'docs/posts/introducing_tablespoon/index.html')
-rw-r--r-- | docs/posts/introducing_tablespoon/index.html | 211 |
1 files changed, 211 insertions, 0 deletions
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> | ||