|
26 | 26 |
|
27 | 27 | ;;;; ## Instrumentation
|
28 | 28 | ;;;
|
29 |
| -;;; The top-level instrumenting function is `read-and-instrument`. See |
| 29 | +;;; The top-level instrumenting function is `instrument-tagged-code`. See |
30 | 30 | ;;; its doc for more information.
|
31 | 31 | ;;;
|
32 | 32 | ;;; Each of the other `instrument-*` functions is responsible for
|
|
208 | 208 | Only forms with a ::breakfunction metadata will be
|
209 | 209 | instrumented, and even then only if it makes sense (e.g., the
|
210 | 210 | binding names in a let form are never instrumented).
|
211 |
| - See `read-and-instrument` for more information." |
| 211 | + See `instrument-tagged-code` for more information." |
212 | 212 | [form]
|
213 | 213 | (condp #(%1 %2) form
|
214 | 214 | ;; Function call, macro call, or special form.
|
|
225 | 225 | ;;;
|
226 | 226 | ;;; The following functions are used to populate with metadata and
|
227 | 227 | ;;; macroexpand code before instrumenting it. This is where we
|
228 |
| -;;; calculate all the ::coor vectors. See `read-and-instrument`. |
| 228 | +;;; calculate all the ::coor vectors. See `instrument-tagged-code`. |
229 | 229 | (defn- walk-indexed
|
230 | 230 | "Walk through form calling (f coor element).
|
231 | 231 | The value of coor is a vector of indices representing element's
|
|
236 | 236 | (let [map-inner (fn [forms]
|
237 | 237 | (map-indexed #(walk-indexed (conj coor %1) f %2)
|
238 | 238 | forms))
|
239 |
| - ;; Maps are unordered, but we can try to use the keys (and |
240 |
| - ;; they're important enough that we're willing to risk |
241 |
| - ;; getting the position wrong). |
242 |
| - result (cond (map? form) (into {} (map (fn [[k v]] |
243 |
| - [k (walk-indexed (conj coor (pr-str k)) f v)]) |
244 |
| - form)) |
245 |
| - ;; Order of sets is unpredictable, unfortunately. |
246 |
| - (set? form) form |
247 |
| - ;; Borrowed from clojure.walk/walk |
248 |
| - (list? form) (apply list (map-inner form)) |
249 |
| - (instance? clojure.lang.IMapEntry form) (vec (map-inner form)) |
250 |
| - (seq? form) (doall (map-inner form)) |
251 |
| - (coll? form) (into (empty form) (map-inner form)) |
252 |
| - :else form)] |
| 239 | + ;; Clojure uses array-maps up to some map size (8 currently). |
| 240 | + ;; So for small maps we take advantage of that, otherwise fall |
| 241 | + ;; back to the heuristic below. |
| 242 | + ;; Maps are unordered, but we can try to use the keys as order |
| 243 | + ;; hoping they can be compared one by one and that the user |
| 244 | + ;; has specified them in that order. If that fails we don't |
| 245 | + ;; instrument the map. We also don't instrument sets. |
| 246 | + ;; This depends on Clojure implementation details. |
| 247 | + walk-indexed-map (fn [map] |
| 248 | + (map-indexed (fn [i [k v]] |
| 249 | + [(walk-indexed (conj coor (* 2 i)) f k) |
| 250 | + (walk-indexed (conj coor (inc (* 2 i))) f v)]) |
| 251 | + map)) |
| 252 | + result (cond |
| 253 | + (map? form) (if (<= (count form) 8) |
| 254 | + (into {} (walk-indexed-map form)) |
| 255 | + (try |
| 256 | + (into (sorted-map) (walk-indexed-map (into (sorted-map) form))) |
| 257 | + (catch Exception e |
| 258 | + form))) |
| 259 | + ;; Order of sets is unpredictable, unfortunately. |
| 260 | + (set? form) form |
| 261 | + ;; Borrowed from clojure.walk/walk |
| 262 | + (list? form) (apply list (map-inner form)) |
| 263 | + (instance? clojure.lang.IMapEntry form) (vec (map-inner form)) |
| 264 | + (seq? form) (doall (map-inner form)) |
| 265 | + (coll? form) (into (empty form) (map-inner form)) |
| 266 | + :else form)] |
253 | 267 | (f coor (m/merge-meta result (meta form))))))
|
254 | 268 |
|
255 | 269 | (defn coord<
|
|
0 commit comments