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 }