@ghoetker You could store each pkg
as each value: (values (hash-ref pkg 'name) pkg)
.
OK yes this means you have the name in both the key and inside the pkg
value. For version 0.1 and ~7,000 items, I’m not sure that matters. If it mattered? You could I guess do something like (values (hash-ref pkg 'name) (hash-remove pkg 'name))
.
@krismicinski I’m not sure what you’re asking. What identifier are you referring to?
@samth basically, I want to add a new identifier to the whole module, say, current-call-stack
that will be available in every form of that module, and will give represent the call stack. My vision for how I’d do this is to—at each application site—add the current lambda’s syntactic point to some list that is accessible by the callee (in a degenerate case: some global variable). Obviously there are other ways to keep track of the stack, but this is the best minimal example I can think up for illustrating what I think I need. I’m implementing a runtime security monitor that tracks when you branch on high-security data and needs to add it to a program counter, which is then available in the branches to know what data you’ve currently branched on.
I guess one naive way that I could think to do this would be to gensym a new name while macro-rewriting, and then set! that in all of my macros, and then have my macros insert that symbol as they perform their task, but that doesn’t seem like a very robust idea (and not good for things like threads / exns), so I was thinking of using parameters instead. The identifier doesn’t have to be accessible to the instrumented code, only the macros I’m splicing into the code.
@krismicinski Maybe insert with-continuation-mark
in places. See also errortrace
, which basically does this (though in a different way than modifying #%app
).
yeah, continuation marks are not a bad idea for this, I’ll read up and think over them for a while.
@krismicinski I think you’re maybe overthinking this
just define (#%app f . args)
to expand to (parameterize ([current-call-stack (cons '(f . args) (current-call-stack))]) (#%plain-app f . args))
@samth ah so I tried this, but what I don’t understand here is how current-call-stack
gets defined in the first place, then. At some point, current-call-stack
has to be initialized to an empty list, otherwise I get scoping errors.
~As well as #%app
, you could provide your own #%module-begin
. Maybe that is how/where you would (define current-call-stack (make-parameter '()))
?~
current-call-stack
should be defined in whatever module you define #%app
in
Yeah, so I do it in #%module-begin right now, but that seems broken
When I define it in the module itself I’m getting similar struggles, but I’m not sure why because that makes sense to me
I think it’s because when I type (define current-call-stack (make-parameter '()))
it uses the macro on the make-parameter
application, wherein there’s no current-call-stack
in scope..?
(at least, that’s what I’m getting out of the macro stepper if I’m interpreting it correctly)
why the crossout? This seems like the right intuition to me.
@krismicinski [samth@hermes:~/work/reviews/oopsla18 (master) plt] cat ~/tmp/xx.rkt
#lang racket/load
(module lib racket
(provide (rename-out [app #%app]) current-stack show)
(define-syntax-rule (show)
;; to avoid this appearing in the stack
(displayln (current-stack)))
(define-syntax-rule (app f . args)
(parameterize ([current-stack (cons '(f . args) (#%app current-stack))])
(#%app f . args))) ;; use racket's #%app
(define current-stack (make-parameter null))
)
(module use racket
(require 'lib)
(define (f x)
(g x))
(define (g x)
(h x))
(define (h x)
(show)
1)
(f 100))
(require 'use)
[samth@hermes:~/work/reviews/oopsla18 (master) plt] r ~/tmp/xx.rkt
((h x) (g x) (f 100))
1
This is great!
Really helps..
Am I right in saying that you’re using #%app
to avoid the macro rewriter then calling your rule again..?
yes
although it’s not needed
i’m just making it clearer
right
because it’s called app
there so it wouldn’t be used anyway
One thing I don’t understand is why the (require 'lib)
works the way it does: it’s rewriting the #%app
form. Does that mean that if I redefine #%app
in the current module (e.g., the test module you wrote) it would behave the same way?
I guess I’ve only ever used this like (module name lib ...
@samth great! That works! I think this is actually what I want, too, since I want current-pc
(in my case) to be across the whole program (anything using that code) rather than a per-module variable, too. Here’s my updated implementation for ref of what I came up with: https://github.com/fordsec/racets/blob/master/src/racets-mlang.rkt#L39
@lexi.lambda thanks for the help, too. My suspicion is that I could also do this with continuation marks, but it’s not immediately obvious quite yet. I’ll probably have to ponder that one for a while..
Here’s the test that uses it and now passes :slightly_smiling_face: https://github.com/fordsec/racets/blob/master/src/tests.rkt
(require 'lib)
just requires 'lib
the meaning of #%app
is as if you had written it literally
for continuation marks, just replace the (parameterize ...)
with (with-continuation-mark 'current-stack '(f . args) (#%app f . args))
and access it with (continuation-mark-set->list 'current-stack (current-continuation-marks))
frankly my hesitation here is because I just don’t understand continuation marks well enough, this example makes sense, and I guess if I wanted to instrument application for things like if
statements and branches I’d also just use continuation marks there…?
continuation marks are just a lower-level mechanism that’s a lot like parameters
yeah, makes sense, since parameters seem to do the work of making things nicer than set! for things like dynamic-wind, etc…
for reference, parameters are implemented on top of continuation marks
yeah, that’s what I figured :slightly_smiling_face:. Alright, I’m going to keep charging ahead with this, and then once I have the core problems figured out, just switch to using CMs
I remember looking into CMs when I was trying to write a small abstract interpreter for racket, and they seemed like a good encompassing abstraction