1 import Base 2 import ./lex.bend as Lex 3 4 def hexd(+n: U32) -> Char: 5 Chr{Lex.sel(U32.is_lt(n, 10), (n + 48 : U32), (n + 87 : U32))} 6 7 # \uXXXX, lowercase hex as Python writes it. 8 def uesc(+n: U32) -> String: 9 "\\u" ++ SCon{hexd(((n >> 12n) .&. 15 : U32)), SCon{hexd(((n >> 8n) .&. 15 : U32)), SCon{hexd(((n >> 4n) .&. 15 : U32)), SCon{hexd((n .&. 15 : U32)), SNil{}}}}} 10 11 def uesc.pair(+c: U32) -> String: 12 uesc((55296 + ((c - 65536) >> 10n) : U32)) ++ uesc((56320 + ((c - 65536) .&. 1023) : U32)) 13 14 def esc.high(ascii: Bool, +c: U32) -> String: 15 match ascii: 16 case False{}: 17 SCon{Chr{c}, SNil{}} 18 case True{}: 19 Lex.sel.s(U32.is_lt(c, 65536), uesc(c), uesc.pair(c)) 20 21 def esc.rest(ascii: Bool, +c: U32) -> String: 22 Lex.sel.s(U32.is_lt(c, 32), uesc(c), 23 Lex.sel.s(U32.is_lt(c, 127), SCon{Chr{c}, SNil{}}, esc.high(ascii, c))) 24 25 # One char as Python's encoder writes it inside quotes. ensure_ascii escapes 26 # everything above `~` (U+007F included); otherwise only controls. 27 def esc.char(+ascii: Bool, +c: U32) -> String: 28 Lex.sel.s(U32.is_eq(c, 34), "\\\"", 29 Lex.sel.s(U32.is_eq(c, 92), "\\\\", 30 Lex.sel.s(U32.is_eq(c, 10), "\\n", 31 Lex.sel.s(U32.is_eq(c, 13), "\\r", 32 Lex.sel.s(U32.is_eq(c, 9), "\\t", 33 Lex.sel.s(U32.is_eq(c, 8), "\\b", 34 Lex.sel.s(U32.is_eq(c, 12), "\\f", 35 Lex.sel.s(U32.is_eq(c, 127), Lex.sel.s(ascii, uesc(127), SCon{Chr{127}, SNil{}}), esc.rest(ascii, c))))))))) 36 37 def quote.body(s: String, +ascii: Bool) -> String: 38 match s: 39 case SNil{}: 40 SNil{} 41 case SCon{Chr{c}, t}: 42 esc.char(ascii, c) ++ quote.body(t, ascii) 43 44 # `"text"` with escapes. 45 def quote(s: String, ascii: Bool) -> String: 46 "\"" ++ quote.body(s, ascii) ++ "\"" 47 48 # style 0: compact `,` `:`; 1: Python's default `, ` `: `; 2: indent=2. 49 def indent(d: Nat) -> String: 50 String.repeat(" ", d) 51 52 def nl(style: U32, d: Nat) -> String: 53 Lex.sel.s(U32.is_eq(style, 2), "\n" ++ indent(d), "") 54 55 def sep(+style: U32, d: Nat) -> String: 56 Lex.sel.s(U32.is_eq(style, 0), ",", Lex.sel.s(U32.is_eq(style, 1), ", ", ",\n" ++ indent(d))) 57 58 def colon(+style: U32) -> String: 59 Lex.sel.s(U32.is_eq(style, 0), ":", ": ") 60 61 # Separator between a chain cell and the next: nothing at the end.