xumingming / tracer

trace clojure call stack

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

It seems some functions are not traced

xumingming opened this issue · comments

e.g. when invoke (read-string "\\a") the function read-char* is not traced.

(read-string "\"a\"") also have the same issue:

user> (read-string "\"a\"")
|- (blind.reader/read-string "\"a\"")
| |- (blind.reader/string-push-back-reader "\"a\"")
| | |- (blind.reader/string-push-back-reader "\"a\"" 1)
| | | |- (blind.reader/string-reader "\"a\"")
| | |  \=> #<StringReader blind.reader.StringReader@3ec44cfb>
| |  \=> #<PushbackReader blind.reader.PushbackReader@499a12ee>
|  \=> #<PushbackReader blind.reader.PushbackReader@499a12ee>
| |- (blind.reader/read #<PushbackReader blind.reader.PushbackReader@499a12ee> true nil false)
| | |- (blind.reader/char \")
| |  \=> \"
| | |- (blind.reader/whitespace? \")
| |  \=> false
| | |- (blind.reader/number-literal? #<PushbackReader blind.reader.PushbackReader@499a12ee> \")
| | | |- (blind.reader/numeric? \")
| | |  \=> false
| |  \=> false
| | |- (blind.reader/comment-prefix? \")
| |  \=> false
| | |- (blind.reader/macros \")
| |  \=> #<reader$read_string_STAR_ blind.reader$read_string_STAR_@2f590164>
| | |- (blind.reader/char \a)
| |  \=> \a
| | |- (blind.reader/char \")
| |  \=> \"
|  \=> "a"
 \=> "a"
"a"

that's because those functions are called from a constant lookup https://github.com/Bronsa/blind/blob/master/src/blind/reader.clj#L819-L851

So even though tracer is altering the vars, it's not altering the value of the functions used by macros and dispatch-macros, eg. this problem wouldn't happen if macros would return #'read-string* instead of read-string

I'm not sure if there is a method to solve this problem

@Bronsa Yeah, it seems it is not that easy to trace this kind of functions statically, here is a potential solution:

We already wrapped all the functions in the target namespace, and we stored the mapping from orignal function to wrapped function in an atom(https://github.com/xumingming/tracer/blob/master/src/tracer/core.clj#L15), we have access to functions' return value, we can do one more thing: if the return value is a function, we check whether it is in the mapping, if it is, we replace it with the wrapped function, then it can be traced.

How do you think?

Smallest reproduce case:

user=> (defn a [] "a") (defn  b [] "b") (defn c [num] (case num 1 a 2 b)) (use 'tracer.core) (trace 'user) ((c 1))
#'user/a
#'user/b
#'user/c
nil
Add user/cdoc to trace list.
Add user/sourcery to trace list.
Add user/help to trace list.
Add user/a to trace list.
Add user/defn to trace list.
Add user/c to trace list.
Add user/b to trace list.
Add user/set-signal-handler! to trace list.
Add user/clojuredocs to trace list.
nil
|- (user/c 1)
 \=> #<user$a user$a@1c6250d2>
"a"

Here function a is missing in the call stack.