fsharp: step 4: Added prn, str, println, and pr-str
[jackhill/mal.git] / fsharp / printer.fs
1 module Printer
2 open System.Text
3 open Types
4
5 type Profile = { Pretty : bool; Separator : string }
6 let pr_str_profile = { Pretty = true; Separator = " " }
7 let str_profile = { Pretty = false; Separator = "" }
8 let prn_profile = { Pretty = true; Separator = " " }
9 let println_profile = { Pretty = false; Separator = " " }
10
11 let print profile nodes =
12 let acc = StringBuilder()
13 let appendStr (str : string) = acc.Append(str) |> ignore
14 let rec pr_node = function
15 | Nil -> appendStr "nil"
16 | List(nodes) -> pr_list nodes
17 | Vector(nodes) -> pr_vector nodes
18 | Map(map) -> pr_map map
19 | Symbol(symbol) -> appendStr symbol
20 | Keyword(keyword) -> appendStr ":"; appendStr keyword
21 | Number(num) -> acc.Append(num) |> ignore
22 | String(str) when profile.Pretty -> pr_str_pretty str
23 | String(str) -> appendStr str
24 | Bool(true) -> appendStr "true"
25 | Bool(false) -> appendStr "false"
26 | Func({ Tag = tag; F = _}) -> pr_func tag
27
28 and pr separator prefix node =
29 appendStr prefix
30 pr_node node
31 separator
32
33 and std_pr = pr " "
34
35 and pr_str_pretty str =
36 let appendChar = function
37 | '\t' -> appendStr "\\t"
38 | '\b' -> appendStr "\\b"
39 | '\n' -> appendStr "\\n"
40 | '\r' -> appendStr "\\r"
41 | '\f' -> appendStr "\\f"
42 | '\'' -> appendStr "\\'"
43 | '"' -> appendStr "\\\""
44 | '\\' -> appendStr "\\\\"
45 | ch -> acc.Append(ch) |> ignore
46 appendStr "\""
47 str |> Seq.iter appendChar
48 appendStr "\""
49
50 and pr_func tag =
51 sprintf "#<func %d>" tag |> appendStr
52
53 and pr_list nodes =
54 appendStr "("
55 nodes |> List.fold std_pr "" |> ignore
56 appendStr ")"
57
58 and pr_vector nodes =
59 appendStr "["
60 nodes |> Seq.fold std_pr "" |> ignore
61 appendStr "]"
62
63 and pr_map map =
64 let pr prefix key value =
65 appendStr prefix
66 pr_node key
67 appendStr " "
68 pr_node value
69 " "
70 appendStr "{"
71 map |> Map.fold pr "" |> ignore
72 appendStr "}"
73
74 nodes |> Seq.fold (pr profile.Separator) "" |> ignore
75 acc.ToString()
76
77 let pr_str : seq<Node> -> string = print pr_str_profile
78 let str : seq<Node> -> string = print str_profile
79 let prn : seq<Node> -> string = print prn_profile
80 let println : seq<Node> -> string = print println_profile