sourcework/xetal-ml/libs/Flow/src/Flow.xtlm
1⍝│ Flow: ML data flow written left to right, |> between stages -- each stage becomes one line of X_eTaL
2⍝│
3⍝│ Import it with an alias of your choice: "flow:" u_se< "Flow" (flow:p_ipe<).
4⍝│ Put libs/Flow/src on XETAL_PATH ("just path"); the reference is libs/Flow/docs.
5⍝│ Names with m: are macros; those under h: are private to this file.
6⍝│
7⍝│ A macro is a function from the source text written left and right of
8⍝│ its call to the source that replaces the call, before the program is
9⍝│ compiled (X_eTaL MC10); xetal expand FILE shows the result. The
10⍝│ pipeline was decided in X_eTaL (D155, its docs/spatial.md,
11⍝│ "Pipelines") and is built here (docs/pipeline-macro.md). Its reader
12⍝│ uses all of its text or refuses it: a stage the grammar does not
13⍝│ know is a compile-time error naming the text, never a wrong answer.
14
15"t:" u̲se< "Strings"
16
17⍝━━ The macros
18
19⍝│ The value of a pipeline: the data, then each stage in turn, |>
20⍝│ between them. A stage is a function (act:r_elu, [f_ g_], '{ x -> ... }),
21⍝│ applied to the previous value, or an expression naming the previous
22⍝│ value it (W nn:d_ense it; the order is written, never guessed).
23⍝│ "$name" at a stage's end names its value for the later stages, the
24⍝│ $ touching the name ("$(Q, K, V)" takes a tuple apart, as X_eTaL's
25⍝│ S14 label is written and drawn); " [N O]" after the name is the
26⍝│ shape the value must have, checked when the program runs
27⍝│ (error[shape], naming the stage, its shape and the one expected).
28⍝│ The left side is @; the right is a code string c"...", drawn as
29⍝│ X_eTaL (|> and $ as triangles), and may put one stage per line; a
30⍝│ plain or raw string reads the same.
31⍝│ binds: it
32⍝│ uses: parsed
33⍝│ >> "flow:" u_se< "Flow"
34⍝│ >> x := f_loat 1 2 3 4
35⍝│ >> @ flow:p_ipe< c"x $s |> 2 * it |> it + s"
36⍝│ 3.0 6.0 9.0 12.0
37ᵐp̲ipe< ← { @ text → ʰw̲rite ʰr̲ead text }
38
39⍝│ The pipeline written back from its reading, a string: the stages
40⍝│ trimmed, " |> " between them, each name and shape as written. What
41⍝│ the macro read is what was written, or the call was refused.
42⍝│ uses: parsed
43⍝│ >> "flow:" u_se< "Flow"
44⍝│ >> @ flow:t_ext< c"x $s |> 2 * it |> it + s"
45⍝│ x $s |> 2 * it |> it + s
46ᵐt̲ext< ← { @ text → "\"" c̲at (ʰe̲scape ʰs̲how ʰr̲ead text) c̲at "\"" }
47
48⍝│ The pipeline drawn as math, a LaTeX string: an aligned display of a
49⍝│ row per stage, the data first, each later stage after an arrow, each
50⍝│ label after its stage as X_eTaL draws $ (a triangle, the name, its
51⍝│ shape); an equation stage
52⍝│ ("H[i,k] | n d" e:e_q< "...") as Equations draws it (its e:t_ex<,
53⍝│ the same strings), any other stage as code. The call is read as
54⍝│ flow:p_ipe< reads it, or refused; KaTeX or LaTeX draws the result.
55⍝│ uses: parsed
56⍝│ >> "flow:" u_se< "Flow"
57⍝│ >> @ flow:m_ath< c"x $s |> 2 * it |> it + s"
58⍝│ \begin{aligned} & x \qquad \triangleright \, s \\ \longrightarrow \; & \texttt{2 * it} \\ \longrightarrow \; & \texttt{it + s} \end{aligned}
59ᵐm̲ath< ← { @ text → ʰd̲raw ʰr̲ead text }
60
61⍝│ Every stage's value, as one line of text: a record per value, " | "
62⍝│ between them, each its stage's number, its label ("" for none), its
63⍝│ shape, its smallest and largest item and its first 64 items, ";"
64⍝│ between the fields; a tuple's parts a record each. For pages that
65⍝│ show what each stage gives; the values are those flow:p_ipe< gives.
66⍝│ uses: parsed
67⍝│ >> "flow:" u_se< "Flow"
68⍝│ >> x := f_loat 1 2 3
69⍝│ >> @ flow:s_tages< c"x |> 2 * it $y"
70⍝│ 1;;3;1.0;3.0;1.0 2.0 3.0 | 2;y;3;2.0;6.0;2.0 4.0 6.0
71ᵐs̲tages< ← { @ text → ʰt̲race ʰr̲ead text }
72
73⍝━━ Reading the call
74
75⍝│ The stages of text as (expressions, names, shapes), each a boxed
76⍝│ text per stage ("" for no name or no shape), every rule checked.
77ʰr̲ead ← { text →
78 t ← ᵗt̲rim text
79 _ ← (0 < t̲ally t) ʰr̲equire "an empty pipeline: write the data, then |> and each stage"
80 parts ← '{ p → ᵗt̲rim d̲isclose p } m̲ap "|>" ʰs̲plit t
81 _ ← '{ p → ʰt̲ouches? d̲isclose p } m̲ap parts
82 _ ← ('∧ r̲/ '{ p → 0 < t̲ally d̲isclose p } e̲ach parts) ʰr̲equire "an empty stage (nothing between two |>, or after the last): " c̲at t
83 es ← '{ p → ʰe̲xpr d̲isclose p } m̲ap parts
84 bs ← '{ p → ʰb̲inder d̲isclose p } m̲ap parts
85 ss ← '{ p → ʰs̲hapeOf d̲isclose p } m̲ap parts
86 _ ← '{ i → (ʰf̲latten (i − 1) t̲ake bs) ʰs̲tage? d̲isclose i s̲elect es } m̲ap 1 d̲rop r̲ange t̲ally es
87 _ ← (n̲ot ʰi̲t? d̲isclose f̲irst es) ʰr̲equire "the first stage is the data; nothing precedes it: " c̲at d̲isclose f̲irst es
88 _ ← '{ b → ʰb̲inder? d̲isclose b } m̲ap bs
89 _ ← (ss, bs) ʰs̲hapes? r̲ange t̲ally ss
90 all ← ʰf̲latten bs
91 twice ← (1 < '+ r̲/₂ 0 + all 'm̲atch t̲able all) r̲eplicate all
92 _ ← (0 = t̲ally twice) ʰr̲equire "a name is bound once in a pipeline: " c̲at ʰf̲irstText twice
93 (es, bs, ss)
94}
95
96⍝│ A stage's expression: its text before its label's $, trimmed.
97ʰe̲xpr ← { s →
98 c ← ʰl̲abel s
99 0 = c ? ᵗt̲rim s
100 ᵗt̲rim (c − 1) t̲ake s
101}
102
103⍝│ What follows a stage's $, trimmed ("" for no label).
104ʰa̲fter ← { s →
105 c ← ʰl̲abel s
106 0 = c ? ""
107 ᵗt̲rim c d̲rop s
108}
109
110⍝│ A stage's name (or tuple of names): the text after $ up to its
111⍝│ shape's [, trimmed; "" for none.
112ʰb̲inder ← { s →
113 a ← ʰa̲fter s
114 k ← "[" ʰf̲irstOf a
115 0 = k ? a
116 ᵗt̲rim (k − 1) t̲ake a
117}
118
119⍝│ A stage's shape as written, "[N O]", from its first [ on; "" for none.
120ʰs̲hapeOf ← { s →
121 a ← ʰa̲fter s
122 k ← "[" ʰf̲irstOf a
123 0 = k ? ""
124 ᵗt̲rim (k − 1) d̲rop a
125}
126
127⍝│ Where the first $ outside brackets and strings is in s, or 0.
128ʰl̲abel ← { s → ʰf̲irst "$" ʰo̲utside s }
129
130⍝│ A stage's $ touches the name or tuple it gives ($m, $(Q, K)), as
131⍝│ X_eTaL's own label does: $ m, or a $ with nothing after it, is
132⍝│ refused ("" when the stage has no label or its $ touches).
133ʰt̲ouches? ← { s →
134 c ← ʰl̲abel s
135 0 = c ? ""
136 msg ← "$ labels a stage and touches the name or tuple it gives ($m, $(Q, K)): " c̲at s
137 c = t̲ally s ? (0 = 1) ʰr̲equire msg
138 (((c + 1) s̲elect s) m̲ember? letters c̲at "(") ʰr̲equire msg
139}
140
141⍝│ A stage after the first is a function, or an expression naming the
142⍝│ previous value it or a name bound before it (earlier, boxed); a stage
143⍝│ that calls a macro (an equation, "Y[i] | n" e:e_q< "2 * it[i]") names
144⍝│ them in its strings too. Else the call is refused with the text (""
145⍝│ when it is one of these).
146ʰs̲tage? ← { earlier e →
147 named ← '∨ r̲/ (0 = 1) c̲at '{ w → (d̲isclose w) ʰu̲ses? e } e̲ach earlier
148 ((ʰi̲t? e) ∨ (ʰf̲unction? e) ∨ named) ʰr̲equire "a stage is a function (act:r_elu, [f_ g_], '{ x -> ... }) or an expression naming the previous value it (or a name bound before it), in an equation's strings or out: " c̲at e
149}
150
151⍝│ Whether e names the previous value: the word it, outside strings, or
152⍝│ in the strings of a macro call.
153ʰi̲t? ← { e → "it" ʰu̲ses? e }
154
155⍝│ Whether e uses the name w: outside strings; in a macro call's
156⍝│ strings too (the names an equation reads, x[i,j]).
157ʰu̲ses? ← { w e → (w, ʰm̲acro? e) ʰw̲ord? e }
158
159⍝│ Whether e calls a macro: a word ending in < outside strings (e:e_q<).
160ʰm̲acro? ← { e →
161 ps ← "<" ʰo̲utside e
162 '∨ r̲/ (0 = 1) c̲at '{ p → p = 1 ? 0 = 1◆ ((p − 1) s̲elect e) m̲ember? nameChars } e̲ach ps
163}
164
165⍝│ Whether the word w (a name) occurs whole in e: outside strings, or
166⍝│ anywhere when inStrings holds.
167ʰw̲ord? ← { (w, inStrings) e →
168 ps ← w ᵗf̲ind e
169 0 = t̲ally ps ? 0 = 1
170 q ← ʰq̲uoted e
171 n ← t̲ally w
172 before ← '{ p → p = 1 ? 0 = 1◆ ((p − 1) s̲elect e) m̲ember? nameChars } e̲ach ps
173 after ← '{ p → (p + n) > t̲ally e ? 0 = 1◆ ((p + n) s̲elect e) m̲ember? nameChars } e̲ach ps
174 '∨ r̲/ (n̲ot before) ∧ (n̲ot after) ∧ inStrings ∨ 0 = ps s̲elect q
175}
176
177⍝│ Whether e is written as a function: a quoted function or lambda
178⍝│ ('n_eg, '+ r_/, '{ x -> ... }), a train ([f_ g_]), or one function
179⍝│ name (act:r_elu, t_ally: no blanks, an underline).
180ʰf̲unction? ← { e →
181 ("'" m̲atch 1 t̲ake e) ∨ "[" m̲atch 1 t̲ake e ? 0 = 0
182 (0 = t̲ally w̲here e m̲ember? " ") ∧ (0 < t̲ally w̲here e m̲ember? "_") ∧ '∧ r̲/ e m̲ember? nameChars
183}
184
185⍝│ A name after $ is a plain name (letters and digits, a letter
186⍝│ first) or a tuple of two or more, (Q, K, V); never it; else refused
187⍝│ ("" when it is).
188ʰb̲inder? ← { b →
189 0 = t̲ally b ? ""
190 _ ← (n̲ot "it" m̲atch b) ʰr̲equire "it is the previous value, not a name to bind: " c̲at b
191 ps ← ʰp̲arts b
192 allNames ← '∧ r̲/ '{ p → ʰn̲ame? d̲isclose p } e̲ach ps
193 tuple ← ("(" m̲atch 1 t̲ake b) ∧ (")" m̲atch -1 t̲ake b) ∧ 2 ≤ t̲ally ps
194 (allNames ∧ (tuple ∨ n̲ot "(" m̲atch 1 t̲ake b)) ʰr̲equire "after $ comes a plain name, or a tuple of names (Q, K, V): " c̲at b
195}
196
197⍝│ The names a binder binds, boxed: the name itself, or a tuple's parts.
198ʰp̲arts ← { b →
199 n̲ot "(" m̲atch 1 t̲ake b ? 1 r̲eshape e̲nclose b
200 '{ p → ᵗt̲rim d̲isclose p } m̲ap "," ᵗs̲plit 1 d̲rop -1 d̲rop b
201}
202
203⍝│ Every name the stages bind, boxed, in order.
204ʰf̲latten ← { bs →
205 0 = t̲ally bs ? 0 r̲eshape e̲nclose ""
206 0 = t̲ally d̲isclose f̲irst bs ? ʰf̲latten 1 d̲rop bs
207 (ʰp̲arts d̲isclose f̲irst bs) c̲at ʰf̲latten 1 d̲rop bs
208}
209
210⍝│ Whether b is a plain name: a letter, then letters or digits.
211ʰn̲ame? ← { b →
212 0 = t̲ally b ? 0 = 1
213 ((f̲irst b) m̲ember? letters) ∧ '∧ r̲/ b m̲ember? plainChars
214}
215
216⍝│ The shapes against their names, each stage: a shape needs a single
217⍝│ name before it, is [extents] whole (names or numbers, blanks
218⍝│ between) and nothing follows it; else refused with the text ("" each).
219ʰs̲hapes? ← { (ss, bs) is →
220 '{ i →
221 sh ← d̲isclose i s̲elect ss
222 b ← d̲isclose i s̲elect bs
223 0 = t̲ally sh ? ""
224 _ ← ((0 < t̲ally b) ∧ n̲ot "(" m̲atch 1 t̲ake b) ʰr̲equire "a shape [N O] goes after the stage's name: " c̲at sh
225 _ ← (("]" m̲atch -1 t̲ake sh) ∧ (1 = t̲ally w̲here sh m̲ember? "]") ∧ 1 = t̲ally w̲here sh m̲ember? "[") ʰr̲equire "a shape is [extents] at the stage's end, nothing after it: " c̲at sh
226 items ← ᵗw̲ords 1 d̲rop -1 d̲rop sh
227 ((0 < t̲ally items) ∧ '∧ r̲/ '{ w → '∧ r̲/ (d̲isclose w) m̲ember? plainChars } e̲ach items) ʰr̲equire "a shape's extents are names or numbers, blanks between: " c̲at sh
228 } m̲ap is
229}
230
231⍝━━ Writing the code
232
233⍝│ The expansion: a block binding each stage's value, one line per
234⍝│ stage (a fresh name from []G_ENSYM, or the name given), the shape
235⍝│ checks after their stages, and the last value as the result.
236ʰw̲rite ← { (es, bs, ss) →
237 n ← t̲ally es
238 names ← '{ i → b ← d̲isclose i s̲elect bs◆ 0 = t̲ally b ? ⎕G̲ENSYM "stage"◆ b } m̲ap r̲ange n
239 lines ← '{ i → (es, ss, names) ʰl̲ine i } m̲ap r̲ange n
240 "{ @ ->\n" c̲at ("" ᵗj̲oin lines) c̲at " " c̲at (d̲isclose n s̲elect names) c̲at "\n} @"
241}
242
243⍝│ Stage i's line: the data as written; an expression naming it in a
244⍝│ block of its own (it := the previous value); a function applied to
245⍝│ the previous value; an expression of earlier names as written; then
246⍝│ its shape check, if any.
247ʰl̲ine ← { (es, ss, names) i →
248 e ← d̲isclose i s̲elect es
249 name ← d̲isclose i s̲elect names
250 check ← (i, name) ʰc̲heckOf d̲isclose i s̲elect ss
251 i = 1 ? " " c̲at name c̲at " := " c̲at e c̲at "\n" c̲at check
252 prev ← d̲isclose (i − 1) s̲elect names
253 ʰi̲t? e ? " " c̲at name c̲at " := { @ ->\n it := " c̲at prev c̲at "\n " c̲at e c̲at "\n } @\n" c̲at check
254 ʰf̲unction? e ? " " c̲at name c̲at " := " c̲at (ʰa̲pplied e) c̲at " " c̲at prev c̲at "\n" c̲at check
255 " " c̲at name c̲at " := " c̲at e c̲at "\n" c̲at check
256}
257
258⍝│ A function stage as applied to a value: a quoted lambda or quoted
259⍝│ name loses its quote ('{ x -> ... } and 'n_eg are the function
260⍝│ passed, { x -> ... } v and n_eg v the call); a derived function
261⍝│ ('+ r_/), a train and a name stay as written.
262ʰa̲pplied ← { e →
263 n̲ot "'" m̲atch 1 t̲ake e ? e
264 ("'{" m̲atch 2 t̲ake e) ∨ 0 = t̲ally w̲here e m̲ember? " " ? 1 d̲rop e
265 e
266}
267
268⍝│ The check of stage i's shape sh, "" when it has none.
269ʰc̲heckOf ← { (i, name) sh →
270 0 = t̲ally sh ? ""
271 (i, name) ʰc̲heck sh
272}
273
274⍝│ The run-time check of a stage's shape: nothing when it matches,
275⍝│ else error[shape] naming the stage, its shape and the one expected
276⍝│ (the extents are the caller's values when the program runs).
277ʰc̲heck ← { (i, name) sh →
278 expected ← "r_avel " c̲at " c_at " ᵗj̲oin ᵗw̲ords 1 d̲rop -1 d̲rop sh
279 " _ := { @ ->\n ((s_hape " c̲at name c̲at ") m_atch " c̲at expected c̲at ") ? @\n \"shape\" []S_IGNAL \"stage " c̲at (f̲ormat i) c̲at " (" c̲at name c̲at "): shape \" c_at (f_ormat s_hape " c̲at name c̲at ") c_at \", expected \" c_at f_ormat " c̲at expected c̲at "\n } @\n"
280}
281
282⍝━━ Drawing the call
283
284⍝│ The display: the rows joined, inside \begin{aligned} ... \end{aligned},
285⍝│ as an expression of strings (an equation's row is its library's
286⍝│ t_ex< call, expanded in turn).
287ʰd̲raw ← { (es, bs, ss) →
288 n ← t̲ally es
289 rows ← '{ i → (es, bs, ss) ʰr̲ow i } m̲ap r̲ange n
290 pieces ← (e̲nclose ʰr̲aw "\\begin{aligned} ") c̲at rows c̲at e̲nclose ʰr̲aw " \\end{aligned}"
291 "(" c̲at (" c_at " ᵗj̲oin pieces) c̲at ")"
292}
293
294⍝│ Row i: an arrow before every stage but the data, the stage drawn,
295⍝│ its label after it as X_eTaL draws $ (a small triangle, the name and
296⍝│ its shape), a line break after every row but the last.
297ʰr̲ow ← { (es, bs, ss) i →
298 e ← (es, bs) ʰs̲hown i
299 into ← ʰi̲nto i
300 label ← ʰn̲amed (d̲isclose i s̲elect bs, d̲isclose i s̲elect ss)
301 (ʰr̲aw into) c̲at " c_at " c̲at (ʰd̲rawn e) c̲at " c_at " c̲at ʰr̲aw label c̲at i ʰb̲reak t̲ally es
302}
303
304⍝│ What comes before row i: the column for the data, an arrow then the
305⍝│ column for each later stage.
306ʰi̲nto ← { i →
307 i = 1 ? "& "
308 "\\longrightarrow \\; & "
309}
310
311⍝│ What ends row i of n: a line break, but for the last.
312ʰb̲reak ← { i n →
313 i = n ? ""
314 " \\\\ "
315}
316
317⍝│ A stage's label drawn after it: the triangle, the name, the extents
318⍝│ of its shape (n \\times 16); "" when it has no name.
319ʰn̲amed ← { (b, sh) →
320 0 = t̲ally b ? ""
321 dims ← " \\times " ᵗj̲oin ᵗw̲ords 1 d̲rop -1 d̲rop sh
322 " \\qquad \\triangleright \\, " c̲at b c̲at (": " ʰo̲pt dims)
323}
324
325⍝│ Stage i as drawn: in an equation, it, the previous value, under the
326⍝│ name it came with when it has one (the previous stage's label, or the
327⍝│ data when the data is a name), so it reads X[i,j], not it[i,j]; code
328⍝│ as written.
329ʰs̲hown ← { (es, bs) i →
330 e ← d̲isclose i s̲elect es
331 (i = 1) ∨ 0 = t̲ally "e_q<" ʰo̲utside e ? e
332 ((es, bs) ʰi̲ncoming i − 1) ʰa̲s e
333}
334
335⍝│ The name stage i's value goes by: its label, or the data itself when
336⍝│ it is a plain name; "" for none (a tuple label is no one name).
337ʰi̲ncoming ← { (es, bs) i →
338 b ← d̲isclose i s̲elect bs
339 ʰn̲ame? b ? b
340 (i = 1) ∧ ʰn̲ame? d̲isclose 1 s̲elect es ? d̲isclose 1 s̲elect es
341 ""
342}
343
344⍝│ The i-th character of s, a blank before its start and past its end.
345ʰc̲hr ← { s i → (i < 1) ∨ i > t̲ally s ? 1 s̲elect " "◆ i s̲elect s }
346
347⍝│ e with each whole word it written as name (e as it is for "").
348ʰa̲s ← { name e →
349 0 = t̲ally name ? e
350 ps ← "it" ᵗf̲ind e
351 whole ← '{ p → n̲ot ((e ʰc̲hr p − 1) m̲ember? nameChars) ∨ (e ʰc̲hr p + 2) m̲ember? nameChars } e̲ach ps
352 0 = '+ r̲/ 0 + whole ? e
353 p ← f̲irst whole r̲eplicate ps
354 ((p − 1) t̲ake e) c̲at name c̲at name ʰa̲s (p + 1) d̲rop e
355}
356
357⍝│ A stage drawn, as an expression of a string: an equation by its
358⍝│ library's t_ex< on the same strings (e:e_q< becomes e:t_ex<); a
359⍝│ plain name as itself; anything else as code.
360ʰd̲rawn ← { e →
361 ps ← "e_q<" ʰo̲utside e
362 0 < t̲ally ps ? "(" c̲at ((-1 + f̲irst ps) t̲ake e) c̲at "t_ex<" c̲at ((3 + f̲irst ps) d̲rop e) c̲at ")"
363 ʰn̲ame? e ? ʰr̲aw e
364 ʰr̲aw ʰt̲t e
365}
366
367⍝│ Code as LaTeX's typewriter text, its special characters escaped.
368ʰt̲t ← { s → "\\texttt{" c̲at ("" ᵗj̲oin '{ ch → ʰl̲atexChar ch } m̲ap s) c̲at "}" }
369
370⍝│ One character of code as LaTeX text.
371ʰl̲atexChar ← { ch →
372 ch m̲ember? "\\" ? "\\textbackslash{}"
373 ch m̲ember? "^" ? "\\textasciicircum{}"
374 ch m̲ember? "~" ? "\\textasciitilde{}"
375 ch m̲ember? "{}_$&%#" ? "\\" c̲at ch
376 ch
377}
378
379⍝│ s as a raw string literal, r#"s"#: a backslash stays a backslash.
380ʰr̲aw ← { s → "r#\"" c̲at s c̲at "\"#" }
381
382⍝━━ Tracing the stages
383
384⍝│ The expansion as flow:p_ipe< writes it, the last line the records of
385⍝│ every stage's value instead of the last value.
386ʰt̲race ← { (es, bs, ss) →
387 n ← t̲ally es
388 names ← '{ i → b ← d̲isclose i s̲elect bs◆ 0 = t̲ally b ? ⎕G̲ENSYM "stage"◆ b } m̲ap r̲ange n
389 lines ← '{ i → (es, ss, names) ʰl̲ine i } m̲ap r̲ange n
390 records ← '{ i → ʰr̲ecords (i, d̲isclose i s̲elect bs, d̲isclose i s̲elect names) } m̲ap r̲ange n
391 "{ @ ->\n" c̲at ("" ᵗj̲oin lines) c̲at " " c̲at (" c_at \" | \" c_at " ᵗj̲oin records) c̲at "\n} @"
392}
393
394⍝│ The records of stage i's value (the name it is bound to): one, or
395⍝│ one per part of a tuple label, as code giving text.
396ʰr̲ecords ← { (i, b, name) →
397 "(" m̲atch 1 t̲ake b c̲at " " ? " c_at \" | \" c_at " ᵗj̲oin '{ p → (i, d̲isclose p) ʰr̲ecord d̲isclose p } m̲ap ʰp̲arts b
398 (i, b) ʰr̲ecord name
399}
400
401⍝│ One value's record, as code giving text.
402ʰr̲ecord ← { (i, label) v →
403 "(\"" c̲at (f̲ormat i) c̲at ";" c̲at label c̲at ";\" c_at (f_ormat s_hape " c̲at v c̲at ") c_at \";\" c_at (f_ormat 'm_in r_/ r_avel " c̲at v c̲at ") c_at \";\" c_at (f_ormat 'm_ax r_/ r_avel " c̲at v c̲at ") c_at \";\" c_at f_ormat (64 m_in t_ally r_avel " c̲at v c̲at ") t_ake r_avel " c̲at v c̲at ")"
404}
405
406⍝━━ Writing the call back
407
408⍝│ The pipeline as read, one line: the stages with " |> " between,
409⍝│ " $name" and " [shape]" where given.
410ʰs̲how ← { (es, bs, ss) →
411 one ← '{ i → (d̲isclose i s̲elect es) c̲at (" $" ʰo̲pt d̲isclose i s̲elect bs) c̲at " " ʰo̲pt d̲isclose i s̲elect ss } m̲ap r̲ange t̲ally es
412 " |> " ᵗj̲oin one
413}
414
415⍝│ pre and x, or "" when x is empty.
416ʰo̲pt ← { pre x →
417 0 = t̲ally x ? ""
418 pre c̲at x
419}
420
421⍝│ s as the inside of a string literal: a quote becomes \".
422ʰe̲scape ← { s → "" ᵗj̲oin '{ ch → (ch m̲ember? "\"") ? "\\\""◆ ch } m̲ap s }
423
424⍝━━ Text helpers
425
426⍝│ Nothing when ok holds; else the call is refused with message, at
427⍝│ its text (the right side).
428ʰr̲equire ← { ok message →
429 ok ? ""
430 "bad-pipeline right" ⎕R̲EJECT message
431}
432
433⍝│ Characters of names: of values (Q, m1), of functions (act:r_elu,
434⍝│ n_ame?, p_rint!), and digits.
435nameChars ← "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_:?!"
436⍝│ Characters of plain names and numbers.
437plainChars ← "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
438letters ← "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
439
440⍝│ 1 at each character of s inside a string literal (its quotes included).
441ʰq̲uoted ← { s → ('+ s̲\ 0 + s m̲ember? "\"") m̲od 2 }
442
443⍝│ The positions in s where sep starts outside brackets, braces,
444⍝│ parentheses and strings.
445ʰo̲utside ← { sep s →
446 q ← ʰq̲uoted s
447 d ← '+ s̲\ ((0 + s m̲ember? "([{") − 0 + s m̲ember? ")]}") × 1 − q
448 ps ← sep ᵗf̲ind s
449 (((ps s̲elect d) = 0) ∧ 0 = ps s̲elect q) r̲eplicate ps
450}
451
452⍝│ s cut where sep starts outside brackets and strings: the pieces
453⍝│ between, boxed (one piece when it never does).
454ʰs̲plit ← { sep s →
455 ps ← sep ʰo̲utside s
456 m ← t̲ally sep
457 starts ← 1 c̲at ps + m
458 ends ← ps c̲at 1 + t̲ally s
459 '{ i → ((i s̲elect ends) − i s̲elect starts) t̲ake ((i s̲elect starts) − 1) d̲rop s } m̲ap r̲ange t̲ally starts
460}
461
462⍝│ The first of the boxed texts b ("" for none).
463ʰf̲irstText ← { b →
464 0 = t̲ally b ? ""
465 d̲isclose f̲irst b
466}
467
468⍝│ The first of the positions ps, or 0 for none.
469ʰf̲irst ← { ps →
470 0 = t̲ally ps ? 0
471 f̲irst ps
472}
473
474⍝│ Where the first ch is in s, or 0.
475ʰf̲irstOf ← { ch s → ʰf̲irst w̲here s m̲ember? ch }