sourcedemos/rosetta/rosetta.xtl

1⍝!/usr/bin/env xetal 2⍝ The Rosetta stone (docs/rosetta.md): how languages write the same 3⍝ idiom, on an impossible object. The whole stone rolls through the 4⍝ idioms; its top half turns through the languages; its bottom half 5⍝ turns, on its own, through the languages compared with. The data is 6⍝ demos/rosetta/data.toml, read as aligned arrays over the two axes; 7⍝ the state machine is Comparison.xtl, the geometry Stone.xtl. The 8⍝ program runs on events ([]E_VENT): each tick eases the axes and 9⍝ shows a frame; keys turn the axes (Up/Down the idioms, Left/Right 10⍝ the top language, a/d the bottom; space, s, w pause a half or the 11⍝ drum); the end of the events prints the state and stops. 12ᶜᵐ⁼u̲se< "Comparison" 13ˢᵗ⁼u̲se< "Stone" 14ᵛ⁼u̲se< "Svg" 15 16data ← "demos/rosetta/data.toml" 17idioms ← data ⎕L̲IST "idioms" 18idiomNames ← data ⎕L̲IST "idiom_names" 19languages ← data ⎕L̲IST "languages" 20languageNames ← data ⎕L̲IST "language_names" 21ᵘt̲able ← { name → ((e̲nclose data) c̲at e̲nclose name) ⎕T̲ABLE "idioms" "languages" } 22source ← ᵘt̲able "source" 23output ← ᵘt̲able "output" 24notes ← ᵘt̲able "notes" 25spans ← ᵘt̲able "spans" 26 27⍝ The colors of code on a face, by class: X_eTaL's classes as []V_IEW 28⍝ names them, and the same names for the spans other languages' cells 29⍝ may carry in data.toml. 30ᵘc̲olor ← { class → 31 class m̲atch "builtin" ? "#1d4ed8" 32 class m̲atch "userfunc" ? "#7c3aed" 33 class m̲atch "libfunc" ? "#7c3aed" 34 class m̲atch "macro" ? "#7c3aed" 35 class m̲atch "number" ? "#b45309" 36 class m̲atch "string" ? "#15803d" 37 class m̲atch "symbol" ? "#111827" 38 class m̲atch "comment" ? "#6b7280" 39 class m̲atch "lambdaarg" ? "#0f766e" 40 class m̲atch "keyword" ? "#1d4ed8" 41 class m̲atch "function" ? "#1d4ed8" 42 class m̲atch "operator" ? "#111827" 43 class m̲atch "name" ? "#000000" 44 "#000000" 45} 46 47⍝ Runs of classified text (an n x 2 matrix of boxed texts, text then 48⍝ class) as colored markup for a face. 49ᵘr̲uns ← { m → ᵘj̲oin '{ k → (ᵘc̲olor d̲isclose 2 s̲elect k s̲elect m) ᵛs̲pan d̲isclose 1 s̲elect k s̲elect m } m̲ap r̲ange 1 s̲elect s̲hape m } 50 51⍝ The classes of a cell that has no spans of its own, guessed from its 52⍝ characters, as the same n x 2 matrix: digits are 53⍝ numbers, letters and the underscore names, spaces plain, and 54⍝ everything else a built-in, which in an array language's glyphs is 55⍝ nearly always right. Runs of one class are one span; the work is 56⍝ all primitives (one lambda per run, not per character). 57ᵘg̲uess ← { src → 58 cls ← (src m̲ember? "0123456789") + (2 × src m̲ember? "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_") + 3 × src = f̲irst " " 59 starts ← 1 c̲at (1 d̲rop cls) ≠ -1 d̲rop cls 60 runs ← ('+ s̲\ starts) p̲artition src 61 kinds ← (e̲nclose "builtin") c̲at (e̲nclose "number") c̲at (e̲nclose "name") c̲at e̲nclose "plain" 62 classes ← (1 + (w̲here starts) s̲elect cls) s̲elect kinds 63 o̲\ (2 c̲at t̲ally runs) r̲eshape runs c̲at classes 64} 65 66⍝ A cell's spans from data.toml, "class text|class text|...", as the 67⍝ same n x 2 matrix; a cell without spans has its classes guessed. 68ᵘs̲pans ← { src spans → 69 0 = t̲ally spans ? ᵘg̲uess src 70 pieces ← (n̲ot spans = f̲irst "|") p̲artition spans 71 o̲ne ← { p → t ← d̲isclose p◆ cut ← t i̲ndexOf f̲irst " "◆ (e̲nclose cut d̲rop t) c̲at e̲nclose (cut − 1) t̲ake t } 72 ((t̲ally pieces) c̲at 2) r̲eshape d̲isclose '{ x y → e̲nclose (d̲isclose x) c̲at d̲isclose y } r̲/ 'o̲ne m̲ap pieces 73} 74 75⍝ The source of a cell as colored markup: X_eTaL source through 76⍝ []V_IEW (so the coloring is the language's own), any other through 77⍝ the cell's spans when it has them. 78ᵘc̲olored ← { il src → 79 i ← 1 s̲elect il 80 l ← 2 s̲elect il 81 (d̲isclose l s̲elect languages) m̲atch "xetal" ? ᵘr̲uns ⎕V̲IEW src 82 ᵘr̲uns src ᵘs̲pans d̲isclose l s̲elect i s̲elect spans 83} 84 85⍝ How many characters a line of code fits at full size (the code is a 86⍝ tenth of the face high and about 0.6 as wide), and the smallest the 87⍝ code may get. 88fits ← 15 89smallest ← 0.05 90 91⍝ A line of markup of n visible characters, shrunk to fit the face when 92⍝ it is longer than fits characters (never below smallest). 93ᵘf̲itted ← { n markup → 94 n ≤ fits ? markup 95 size ← 0.1 × (f̲loat fits) ÷ f̲loat n 96 (size m̲ax smallest) ᵛs̲ized markup 97} 98 99⍝ Source too long for one line split in two at the space nearest its 100⍝ middle, as a box of one or two texts (a text without spaces stays 101⍝ whole, however long). 102ᵘs̲plit ← { src → 103 n ← t̲ally src 104 n ≤ fits ? e̲nclose src 105 spaces ← w̲here src = f̲irst " " 106 0 = t̲ally spaces ? e̲nclose src 107 away ← a̲bs (2 × spaces) − n 108 cut ← (away i̲ndexOf 'm̲in r̲/ away) s̲elect spaces 109 (e̲nclose (cut − 1) t̲ake src) c̲at e̲nclose cut d̲rop src 110} 111 112⍝ Words (a box of texts) as lines of at most width characters, as a box 113⍝ of texts; a word longer than the width is a line of its own. 114ᵘl̲ines ← { width ws → 115 0 = t̲ally ws ? ws 116 lens ← '{ b → t̲ally d̲isclose b } e̲ach ws 117 room ← width ≥ (('+ s̲\ lens) + r̲ange t̲ally ws) − 1 118 k ← 1 m̲ax '+ r̲/ room 119 line ← d̲isclose '{ x y → e̲nclose (d̲isclose x) c̲at " " c̲at d̲isclose y } r̲/ k t̲ake ws 120 (e̲nclose line) c̲at width ᵘl̲ines k d̲rop ws 121} 122 123⍝ A text wrapped at its spaces into lines of at most width characters. 124ᵘw̲rap ← { width t → width ᵘl̲ines (n̲ot t = f̲irst " ") p̲artition t } 125 126⍝ A result's lines as one, " / " between them (a matrix, or a language's 127⍝ own box drawing of one, on a face's single result line). 128ᵘo̲neLine ← { out → d̲isclose '{ x y → e̲nclose (d̲isclose x) c̲at " / " c̲at d̲isclose y } r̲/ (n̲ot out = f̲irst "\n") p̲artition out } 129 130⍝ The lines of a language's face for an idiom: its name, the source 131⍝ colored (on two lines when it is long, each shrunk to fit), and the 132⍝ output when there is one; or the note for a missing source, wrapped. 133⍝ Each line is markup. 134ᵘf̲ace ← { i l → 135 name ← ᵛe̲scape d̲isclose l s̲elect languageNames 136 src ← d̲isclose l s̲elect i s̲elect source 137 out ← d̲isclose l s̲elect i s̲elect output 138 note ← d̲isclose l s̲elect i s̲elect notes 139 missing ← "0 = t_ally note" i̲f< "\"(no concise idiom)\"; note"
i̲f< expands to
({ @ → (0 = t̲ally note) ? "(no concise idiom)"◆ note } @)
140 result ← "0 = t_ally out" i̲f< "\"\"; \"-> \" c_at u:o_neLine out"
i̲f< expands to
({ @ → (0 = t̲ally out) ? ""◆ "-> " c̲at ᵘo̲neLine out } @)
141 n̲oteLine ← { b → 0.07 ᵛs̲ized "#4b5563" ᵛs̲pan d̲isclose b } 142 0 = t̲ally src ? (e̲nclose name) c̲at 'n̲oteLine m̲ap 18 ᵘw̲rap missing 143 c̲odeLine ← { b → (t̲ally d̲isclose b) ᵘf̲itted (i c̲at l) ᵘc̲olored d̲isclose b } 144 code ← 'c̲odeLine m̲ap ᵘs̲plit src 145 (e̲nclose name) c̲at code c̲at e̲nclose (t̲ally result) ᵘf̲itted "#4b5563" ᵛs̲pan result 146} 147 148⍝ The item an axis's side shows: the one its turn started from plus 149⍝ the side's offset, wrapped. (axis offset) ᵘi̲tem state. 150ᵘi̲tem ← { ao state → 151 axis ← 1 s̲elect ao 152 n ← f̲loor 0.5 + (axis c̲at ᶜᵐCOUNT) ᶜᵐa̲t state 153 n ᶜᵐw̲rap 1 + (f̲loor 2 s̲elect ao) + ˢᵗb̲ase (axis c̲at ᶜᵐANGLE) ᶜᵐa̲t state 154} 155 156⍝ The stone as a picture of a state: the two halves' sides show the 157⍝ languages for the idiom the stone stands on, the top half's lid and 158⍝ the bottom half's floor name the neighboring idioms, the caps between 159⍝ the halves are bare; everything is painted far to near as one solid. 160⍝ Faces 1 to 6 are the top half's (front, right, back, left, lid, 161⍝ floor), 7 to 12 the bottom half's. 162ᵘs̲tone ← { state → 163 i ← (ᶜᵐIDIOM c̲at 0.0) ᵘi̲tem state 164 roll ← (ᶜᵐIDIOM c̲at ᶜᵐANGLE) ᶜᵐa̲t state 165 top ← 1 ˢᵗr̲ing ((ᶜᵐTOP c̲at ᶜᵐANGLE) ᶜᵐa̲t state) c̲at roll 166 bottom ← -1 ˢᵗr̲ing ((ᶜᵐBOTTOM c̲at ᶜᵐANGLE) ᶜᵐa̲t state) c̲at roll 167 all ← top c̲at bottom 168 c̲apName ← { k → ᵛe̲scape d̲isclose ((ᶜᵐIDIOM c̲at f̲loat k s̲elect ˢᵗcapOffsets) ᵘi̲tem state) s̲elect idiomNames } 169 c̲apText ← { k → 170 k = 5 ? c̲apName 1 171 k = 12 ? c̲apName 2 172 "" 173 } 174 c̲ap ← { k → (e̲nclose "#e9e4db") c̲at (e̲nclose "") c̲at e̲nclose c̲apText k } 175 t̲opPanel ← { k → (e̲nclose "#fdfcfa") c̲at i ᵘf̲ace (ᶜᵐTOP c̲at f̲loat k s̲elect ˢᵗringOffsets) ᵘi̲tem state } 176 b̲ottomPanel ← { k → (e̲nclose "#f4f1ec") c̲at i ᵘf̲ace (ᶜᵐBOTTOM c̲at f̲loat k s̲elect ˢᵗringOffsets) ᵘi̲tem state } 177 l̲ines ← { k → 178 k ≤ 4 ? t̲opPanel k 179 k ≤ 6 ? c̲ap k 180 k ≤ 10 ? b̲ottomPanel k − 6 181 c̲ap k 182 } 183 p̲anel ← { k → (l̲ines k) ˢᵗp̲anel k s̲elect all } 184 painted ← ᵘj̲oin 'p̲anel m̲ap ˢᵗp̲ainting all 185 caption ← ((ᵛa̲t (ˢᵗsize ÷ 2) c̲at 28) c̲at ("font-size" ᵛa̲ttr "18") c̲at ("text-anchor" ᵛa̲ttr "middle") c̲at (ᵛf̲ill "#374151") c̲at "font-family" ᵛa̲ttr "ui-sans-serif, system-ui, sans-serif") ᵛt̲ext d̲isclose i s̲elect idiomNames 186 (ˢᵗsize c̲at ˢᵗsize) ᵛp̲icture caption c̲at painted 187} 188 189ᵘj̲oin ← { b → d̲isclose '{ x y → e̲nclose (d̲isclose x) c̲at d̲isclose y } r̲/ b } 190 191⍝ Where the stone stands, for the host: "at IDIOM TOP BOTTOM" by their 192⍝ keys, printed whenever it changes (the page reads it for its controls 193⍝ and the address bar). It names what the faces show, which changes 194⍝ when a turn lands, not what an axis is turning toward (its steps), 195⍝ so the page's lists never run ahead of the picture. 196ᵘw̲here ← { s → 197 i ← d̲isclose ((ᶜᵐIDIOM c̲at 0.0) ᵘi̲tem s) s̲elect idioms 198 t ← d̲isclose ((ᶜᵐTOP c̲at 0.0) ᵘi̲tem s) s̲elect languages 199 b ← d̲isclose ((ᶜᵐBOTTOM c̲at 0.0) ᵘi̲tem s) s̲elect languages 200 "at " c̲at i c̲at " " c̲at t c̲at " " c̲at b 201} 202 203⍝ The loop: an event, the state after it, a frame on each tick, the 204⍝ position and the tour's mode when they change ("at IDIOM TOP 205⍝ BOTTOM", "mode touring|holding|paused..."); the state when the 206⍝ events end. 207ᵘl̲oop ← { state → 208 e ← ⎕E̲VENT @ 209 kind ← ⎕E̲KIND e 210 kind m̲atch "end" ? state 211 next ← state ᶜᵐu̲pdate e 212 "(u:w_here state) m_atch u:w_here next" u̲nless< "p_rint! u:w_here next"
u̲nless< expands to
{ @ → ((ᵘw̲here state) m̲atch ᵘw̲here next) ? @◆ p̲rint! ᵘw̲here next◆ @ } @
213 "(cm:m_ode state) m_atch cm:m_ode next" u̲nless< "p_rint! \"mode \" c_at cm:m_ode next"
u̲nless< expands to
{ @ → ((ᶜᵐm̲ode state) m̲atch ᶜᵐm̲ode next) ? @◆ p̲rint! "mode " c̲at ᶜᵐm̲ode next◆ @ } @
214 "n_ot kind m_atch \"tick\"" u̲nless< "[]S_HOW u:s_tone next"
u̲nless< expands to
{ @ → (n̲ot kind m̲atch "tick") ? @◆ ⎕S̲HOW ᵘs̲tone next◆ @ } @
215 ᵘl̲oop next 216} 217 218⍝ Start at the beginning of the tour: the first idiom, the first 219⍝ language on top and the second below, at rest, every axis playing 220⍝ (the attract mode begins after the first dwell). 221start ← ᶜᵐr̲esume ᶜᵐs̲ettle (ᶜᵐBOTTOM c̲at 2.0) ᶜᵐc̲hoose (t̲ally idioms) ᶜᵐs̲tart t̲ally languages 222shown ← p̲rint! ᵘw̲here start 223mode ← p̲rint! "mode " c̲at ᶜᵐm̲ode start 224ᵘl̲oop start