Skip to content

Commit d0dedcb

Browse files
bostonoudnolen
authored and
dnolen
committed
CLJS-710: port clojure.pprint
1 parent 6ab03fb commit d0dedcb

File tree

5 files changed

+4502
-69
lines changed

5 files changed

+4502
-69
lines changed

src/cljs/cljs/pprint.clj

Lines changed: 140 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,144 @@
1-
;;; pprint.clj -- Pretty printer and Common Lisp compatible format function (cl-format) for Clojure
1+
(ns cljs.pprint
2+
(:refer-clojure :exclude [deftype])
3+
(:require [clojure.walk :as walk]))
24

3-
; Copyright (c) Rich Hickey. All rights reserved.
4-
; The use and distribution terms for this software are covered by the
5-
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php)
6-
; which can be found in the file epl-v10.html at the root of this distribution.
7-
; By using this software in any fashion, you are agreeing to be bound by
8-
; the terms of this license.
9-
; You must not remove this notice, or any other, from this software.
105

11-
;; Author: Tom Faulhaber
12-
;; April 3, 2009
6+
;; required the following changes:
7+
;; replace .ppflush with -ppflush to switch from Interface to Protocol
138

14-
(ns cljs.pprint)
9+
(defmacro with-pretty-writer [base-writer & body]
10+
`(let [base-writer# ~base-writer
11+
new-writer# (not (pretty-writer? base-writer#))]
12+
(cljs.core/binding [~'*out* (if new-writer#
13+
(make-pretty-writer base-writer# *print-right-margin* *print-miser-width*)
14+
base-writer#)]
15+
~@body
16+
(-ppflush ~'*out*))))
17+
18+
19+
(defmacro getf
20+
"Get the value of the field a named by the argument (which should be a keyword)."
21+
[sym]
22+
`(~sym @@~'this))
23+
24+
;; change alter to swap!
25+
26+
(defmacro setf
27+
"Set the value of the field SYM to NEW-VAL"
28+
[sym new-val]
29+
`(swap! @~'this assoc ~sym ~new-val))
30+
31+
(defmacro deftype
32+
[type-name & fields]
33+
(let [name-str (name type-name)
34+
fields (map (comp symbol name) fields)]
35+
`(do
36+
(defrecord ~type-name [~'type-tag ~@fields])
37+
(defn- ~(symbol (str "make-" name-str))
38+
~(vec fields)
39+
(~(symbol (str type-name ".")) ~(keyword name-str) ~@fields))
40+
(defn- ~(symbol (str name-str "?")) [x#] (= (:type-tag x#) ~(keyword name-str))))))
41+
42+
(defn- parse-lb-options [opts body]
43+
(loop [body body
44+
acc []]
45+
(if (opts (first body))
46+
(recur (drop 2 body) (concat acc (take 2 body)))
47+
[(apply hash-map acc) body])))
48+
49+
(defmacro pprint-logical-block
50+
"Execute the body as a pretty printing logical block with output to *out* which
51+
must be a pretty printing writer. When used from pprint or cl-format, this can be
52+
assumed.
53+
54+
This function is intended for use when writing custom dispatch functions.
55+
56+
Before the body, the caller can optionally specify options: :prefix, :per-line-prefix
57+
and :suffix."
58+
[& args]
59+
(let [[options body] (parse-lb-options #{:prefix :per-line-prefix :suffix} args)]
60+
`(do (if (cljs.pprint/level-exceeded)
61+
(~'-write cljs.pprint/*out* "#")
62+
(do
63+
(cljs.core/binding [cljs.pprint/*current-level* (inc cljs.pprint/*current-level*)
64+
cljs.pprint/*current-length* 0]
65+
(cljs.pprint/start-block cljs.pprint/*out*
66+
~(:prefix options)
67+
~(:per-line-prefix options)
68+
~(:suffix options))
69+
~@body
70+
(cljs.pprint/end-block cljs.pprint/*out*))))
71+
nil)))
72+
73+
(defn- pll-mod-body [var-sym body]
74+
(letfn [(inner [form]
75+
(if (seq? form)
76+
(let [form (macroexpand form)]
77+
(condp = (first form)
78+
'loop* form
79+
'recur (concat `(recur (inc ~var-sym)) (rest form))
80+
(walk/walk inner identity form)))
81+
form))]
82+
(walk/walk inner identity body)))
83+
84+
(defmacro print-length-loop
85+
"A version of loop that iterates at most *print-length* times. This is designed
86+
for use in pretty-printer dispatch functions."
87+
[bindings & body]
88+
(let [count-var (gensym "length-count")
89+
mod-body (pll-mod-body count-var body)]
90+
`(loop ~(apply vector count-var 0 bindings)
91+
(if (or (not cljs.core/*print-length*) (< ~count-var cljs.core/*print-length*))
92+
(do ~@mod-body)
93+
(~'-write cljs.pprint/*out* "...")))))
94+
95+
(defn- process-directive-table-element [[char params flags bracket-info & generator-fn]]
96+
[char,
97+
{:directive char,
98+
:params `(array-map ~@params),
99+
:flags flags,
100+
:bracket-info bracket-info,
101+
:generator-fn (concat '(fn [params offset]) generator-fn)}])
102+
103+
(defmacro ^{:private true}
104+
defdirectives
105+
[& directives]
106+
`(def ^{:private true}
107+
~'directive-table (hash-map ~@(mapcat process-directive-table-element directives))))
108+
109+
(defmacro formatter
110+
"Makes a function which can directly run format-in. The function is
111+
fn [stream & args] ... and returns nil unless the stream is nil (meaning
112+
output to a string) in which case it returns the resulting string.
113+
114+
format-in can be either a control string or a previously compiled format."
115+
[format-in]
116+
`(let [format-in# ~format-in
117+
my-c-c# cljs.pprint/cached-compile
118+
my-e-f# cljs.pprint/execute-format
119+
my-i-n# cljs.pprint/init-navigator
120+
cf# (if (string? format-in#) (my-c-c# format-in#) format-in#)]
121+
(fn [stream# & args#]
122+
(let [navigator# (my-i-n# args#)]
123+
(my-e-f# stream# cf# navigator#)))))
124+
125+
(defmacro formatter-out
126+
"Makes a function which can directly run format-in. The function is
127+
fn [& args] ... and returns nil. This version of the formatter macro is
128+
designed to be used with *out* set to an appropriate Writer. In particular,
129+
this is meant to be used as part of a pretty printer dispatch method.
130+
131+
format-in can be either a control string or a previously compiled format."
132+
[format-in]
133+
`(let [format-in# ~format-in
134+
cf# (if (string? format-in#) (cljs.pprint/cached-compile format-in#) format-in#)]
135+
(fn [& args#]
136+
(let [navigator# (cljs.pprint/init-navigator args#)]
137+
(cljs.pprint/execute-format cf# navigator#)))))
138+
139+
(defmacro with-pprint-dispatch
140+
"Execute body with the pretty print dispatch function bound to function."
141+
[function & body]
142+
`(cljs.core/binding [cljs.pprint/*print-pprint-dispatch* ~function]
143+
~@body))
15144

16-
(defmacro ^{:private true} prlabel [prefix arg & more-args]
17-
"Print args to *err* in name = value format"
18-
`(prerr ~@(cons (list 'quote prefix) (mapcat #(list (list 'quote %) "=" %)
19-
(cons arg (seq more-args))))))

0 commit comments

Comments
 (0)