macro librarylibs/Csv/src/Csv.xtlm
Csv: its macro library -- c_olumns<, a table's columns as named, typed variables. Imported with the functions, under one alias: "cs:" u_se< "Csv". A macro is a function from the source text written left and right of its call to the source that replaces the call, run before the program is compiled (X_eTaL MC10). Names with m: are macros; those under h: are private to this file.
Parsing
ʰn̲ame? : Truthy a => Char -> a
Whether a text can be a variable's name.
ʰn̲ame? ← { n → (0 < t̲ally n) ∧ ((f̲irst n) m̲ember? lowers) ∧ '∧ r̲/ n m̲ember? letters }
ʰc̲ut : Char -> Int
A column's name and kind, from "name:kind".
ʰc̲ut ← { c → (f̲irst w̲here c = f̲irst ":") − 1 }
ʰc̲olumn? : Truthy a => Char -> a
Whether a column is "name:text" or "name:number".
ʰc̲olumn? ← { c → 1 ≠ t̲ally w̲here c = f̲irst ":" ? 0 = 1 (ʰn̲ame? ʰc̲olName c) ∧ ("text" m̲atch ʰc̲olKind c) ∨ "number" m̲atch ʰc̲olKind c }
ʰc̲ode : Char -> Char -> Char
The code for one column of table tb: its texts, found by header, the header left out; numbers read from them when the kind is number.
ʰc̲ode ← { tb c → n ← ʰc̲olName c texts ← "(1 d_rop ((f_irst " c̲at tb c̲at ") i_ndexOf e_nclose \"" c̲at n c̲at "\") s_elect_2 " c̲at tb c̲at ")" "text" m̲atch ʰc̲olKind c ? n c̲at " := " c̲at texts n c̲at " := n_umbers d_isclose '{ e_nclose (d_isclose _l) c_at \" \" c_at d_isclose _r } r_/ " c̲at texts }
The macro
ᵐc̲olumns< : Char -> Char -> Char
"city:text population:number" cs:c_olumns< "t": the columns of table t (a table as cs:r_ows gives it, its first row the header) as variables named after them: city the texts of column "city", population its numbers (Floats). When the program is compiled the schema is checked and a definition written per column, so the rest of the program uses the columns by name and their kinds are type-checked like any variable (population c_at "x" is a type error). A malformed schema or table name stops the compiler: error[bad-columns]. Columns are found by their header when the program runs.
ᵐc̲olumns< ← { schema tb → cs ← ᵗw̲ords schema 0 = t̲ally cs ? "bad-columns left" ⎕R̲EJECT "no columns: write name:text or name:number" bad ← (n̲ot '{ ʰc̲olumn? d̲isclose ⍵ } e̲ach cs) r̲eplicate cs 0 < t̲ally bad ? "bad-columns left" ⎕R̲EJECT (d̲isclose f̲irst bad) c̲at " is not a column: write name:text or name:number (a lowercase name)" n̲ot ʰn̲ame? ᵗt̲rim tb ? "bad-columns right" ⎕R̲EJECT tb c̲at " is not a table's name" "\n" ᵗj̲oin '{ c → (ᵗt̲rim tb) ʰc̲ode d̲isclose c } m̲ap cs }