1
1
mirror of https://github.com/kanaka/mal.git synced 2024-11-13 11:23:59 +03:00
mal/fsharp/printer.fs

88 lines
3.0 KiB
Forth

module Printer
open System.Text
open Types
type Profile = { Pretty : bool; Separator : string }
let pr_str_profile = { Pretty = true; Separator = " " }
let str_profile = { Pretty = false; Separator = "" }
let prn_profile = { Pretty = true; Separator = " " }
let println_profile = { Pretty = false; Separator = " " }
let print profile nodes =
let acc = StringBuilder()
let appendStr (str : string) = acc.Append(str) |> ignore
let rec pr_node = function
| Nil -> appendStr "nil"
| List(_, nodes) -> pr_list nodes
| Vector(_, nodes) -> pr_vector nodes
| Map(_, map) -> pr_map map
| Symbol(symbol) -> appendStr symbol
| Keyword(keyword) -> appendStr ":"; appendStr keyword
| Number(num) -> acc.Append(num) |> ignore
| String(str) when profile.Pretty -> pr_str_pretty str
| String(str) -> appendStr str
| Bool(true) -> appendStr "true"
| Bool(false) -> appendStr "false"
| BuiltInFunc(_, tag, _) | Func(_, tag, _, _, _, _) ->
pr_func "func" tag
| Macro(_, tag, _, _, _, _) -> pr_func "macro" tag
| Atom(tag, r) -> pr_atom tag !r
and pr separator prefix node =
appendStr prefix
pr_node node
separator
and std_pr = pr " "
and pr_str_pretty str =
let appendChar = function
| '\t' -> appendStr "\\t"
| '\b' -> appendStr "\\b"
| '\n' -> appendStr "\\n"
| '\r' -> appendStr "\\r"
| '\f' -> appendStr "\\f"
| '"' -> appendStr "\\\""
| '\\' -> appendStr "\\\\"
| ch -> acc.Append(ch) |> ignore
appendStr "\""
str |> Seq.iter appendChar
appendStr "\""
and pr_func ftype tag =
sprintf "#<%s %d>" ftype tag |> appendStr
and pr_atom tag node =
appendStr "(atom "
pr_node node
appendStr ")"
and pr_list nodes =
appendStr "("
nodes |> List.fold std_pr "" |> ignore
appendStr ")"
and pr_vector nodes =
appendStr "["
nodes |> Seq.fold std_pr "" |> ignore
appendStr "]"
and pr_map map =
let pr prefix key value =
appendStr prefix
pr_node key
appendStr " "
pr_node value
" "
appendStr "{"
map |> Map.fold pr "" |> ignore
appendStr "}"
nodes |> Seq.fold (pr profile.Separator) "" |> ignore
acc.ToString()
let pr_str : seq<Node> -> string = print pr_str_profile
let str : seq<Node> -> string = print str_profile
let prn : seq<Node> -> string = print prn_profile
let println : seq<Node> -> string = print println_profile