Alright, I think I see how I confused myself. I load modules in my language dynamically. I use sandboxed evaluators instead of dynamic-require. I used replace-context on the entire module body to make the evaluators see values that I defined and provided during expansion. The problem was that in doing so, I coupled what a single module provided with the module language itself. I could not see a way to create a syntax-binding-set from an existing syntax object. Going off [1], I could only start with a blank set and add individual bindings. I used my blunt instrument and moved on because I was trying to design the language around how module evaluators worked, not the other way around.
Thank you again, Jay. Your examples helped me see what I was doing. [1]: https://docs.racket-lang.org/reference/stxops.html#%28def._%28%28quote._~23~25kernel%29._syntax-binding-set%29%29 ~slg ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐ On Friday, January 1, 2021 12:51 PM, Sage Gerard <[email protected]> wrote: > Alright, thank you for sticking with this. I'm refactoring now. > > ~slg > > ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐ > On Friday, January 1, 2021 11:56 AM, Jay McCarthy <[email protected]> > wrote: > >> I’d imagine that you would only provide program and the modifiers. >> Everything well work out :) >> >> Jay >> >> On Fri, Jan 1, 2021 at 11:44 AM Sage Gerard <[email protected]> wrote: >> >>> Ah, I see. Thank you for that! >>> >>> As for rephrasing my original question: If program were provided as >>> #%module-begin, I expect that syntax-protect would prevent a programmer from >>> using out the phase-0 bindings. But in my version of the program Racket >>> would keep complaining about unbound identifiers unless I provided >>> everything. >>> >>> The thing is, I don't want the user to be able to write things like >>> set-field* in their program just because I'm forced to provide it. >>> That's why I'm trying to figure out a way to say "Ok, this module language >>> happens to include set-field*, but set-field* must only appear >>> in module context, or not at all." >>> >>> ~slg >>> >>> ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐ >>> On Thursday, December 31, 2020 1:40 PM, Jay McCarthy >>> <[email protected]> wrote: >>> >>>> I meant like this: >>>> >>>> ``` >>>> #lang racket/base >>>> (require (for-syntax racket/base >>>> syntax/parse) >>>> syntax/parse/define) >>>> >>>> ;; Run-time >>>> (struct state (a b c d) #:transparent) >>>> (define mt (state #f #f #f #f)) >>>> (define-simple-macro (set-field st:expr f:id v:expr) >>>> (struct-copy state st [f v])) >>>> (define-simple-macro (set-field* f:id v:expr) >>>> (λ (st) (set-field st f v))) >>>> >>>> ;; Compile-time >>>> (begin-for-syntax >>>> (define-struct modifier (f))) >>>> >>>> (define-simple-macro (define-modifier (m . args) body) >>>> (begin >>>> (define-syntax m-f >>>> (syntax-parser [(_ args) #'body])) >>>> (define-syntax m (modifier #'m-f)))) >>>> >>>> (define-modifier (the-a-says x:string) >>>> (set-field* a x)) >>>> (define-modifier (the-b-says 'x:id) >>>> (set-field* b 'x)) >>>> (define-modifier (the-c-is x:string) >>>> (set-field* c x)) >>>> (define-modifier (the-d-looks-like x:nat) >>>> (set-field* d x)) >>>> >>>> (define-syntax-parser term >>>> [(_ ((~var m (static modifier? "state modifier")) . args)) >>>> #:with f (modifier-f (attribute m.value)) >>>> #'(f args)]) >>>> >>>> (define-syntax-parser program >>>> [(_) #'mt] >>>> [(_ x . more) #'((term x) (program . more))]) >>>> >>>> ;; Example >>>> (program >>>> (the-a-says "Aaah") >>>> (the-b-says 'Baah) >>>> (the-c-is "Caaah") >>>> (the-d-looks-like 42)) >>>> ``` >>>> >>>> -- >>>> Jay McCarthy >>>> Associate Professor @ CS @ UMass Lowell >>>> http://jeapostrophe.github.io >>>> Vincit qui se vincit. >>>> >>>> On Thu, Dec 31, 2020 at 12:07 PM Sage Gerard <[email protected]> wrote: >>>> >>>>> I didn't see an answer to my original question, but I still want to make >>>>> sure I understood you before I rephrase. Thank you for the insights! >>>>> >>>>> By your three step suggestion, is something like this what you meant? I'm >>>>> not sure I understood Step 3. It seems like I still have to add new >>>>> structure types and macros to define new terms, which is about as >>>>> laborious as what I was doing with #:datum-literals and struct-copy. >>>>> >>>>> (module id racket/base >>>>> (require racket/format >>>>> (for-syntax racket/base syntax/parse)) >>>>> >>>>> (begin-for-syntax (struct item (name num))) >>>>> >>>>> (define (record-item name num) >>>>> (~a num ". " name)) >>>>> >>>>> (define-syntax (term stx) >>>>> (syntax-parse stx >>>>> #:literals ([stmt item #:phase 1]) >>>>> [(_ (stmt name:id num:exact-positive-integer)) >>>>> #'(define name (record-item 'name num))])) >>>>> >>>>> (define-syntax-rule (program x ...) >>>>> (begin (term x) ...))) >>>>> >>>>> ~slg >>>>> >>>>> ‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐ >>>>> On Thursday, December 31, 2020 9:45 AM, Jay McCarthy >>>>> <[email protected]> wrote: >>>>> >>>>>> Are you trying to take a macro argument and ensure that it is an >>>>>> expression? If so, then you can expand into `#%expression` >>>>>> >>>>>> https://docs.racket-lang.org/reference/__expression.html >>>>>> >>>>>> On the other hand, if you are trying to take a macro argument and ensure >>>>>> that it is NOT an expression... then that means that you know what it is >>>>>> allowed to be, so I don't think there's any better way than to just >>>>>> enumerate what it CAN be. I think I would use a syntax class that >>>>>> specifies the allowable patterns and then use that. For example, in my >>>>>> little teachlog language, I have the `term` syntax class for this purpose >>>>>> >>>>>> https://github.com/jeapostrophe/teachlog/blob/master/main.rkt#L119 >>>>>> >>>>>> Looking at your code, I think what I would do is: >>>>>> 1) Define a phase-1 structure that represents one of these fields and an >>>>>> associated phase-0 function that records its values >>>>>> 2) Define `define-syntax` bindings for each particular field as an >>>>>> instance of these fields >>>>>> 3) Write `update` as a short `syntax-parse` that expects a list where >>>>>> the head is a static instance of the phase-1 structure and expands into >>>>>> an application of the associate phase-0 function on the arguments >>>>>> >>>>>> This would allow you to better abstract things so you don't have tie the >>>>>> `update` function to the particular fields. >>>>>> >>>>>> Jay >>>>>> >>>>>> -- >>>>>> Jay McCarthy >>>>>> Associate Professor @ CS @ UMass Lowell >>>>>> http://jeapostrophe.github.io >>>>>> Vincit qui se vincit. >>>>>> >>>>>> On Wed, Dec 30, 2020 at 10:20 PM Sage Gerard <[email protected]> wrote: >>>>>> >>>>>>> I'm trying to learn how to restrict where expressions appear. Those >>>>>>> expressions might be procedure applications, or macros before expansion. >>>>>>> >>>>>>> [1] shows a library I use to help me implement a collection pass for a >>>>>>> module language. To save you some reading, it uses syntax-parse with a >>>>>>> lengthy #:datum-literals. That's the only way I know how to restrict >>>>>>> what expressions appear in module context. >>>>>>> >>>>>>> One element of the #:datum-literals happens to share an identifier with >>>>>>> a bound procedure, so I expand the calls as-is in a module-level >>>>>>> expression [2][3]. I want that procedure to be applied ONLY in the >>>>>>> module context, but nothing in the language enforces that. >>>>>>> >>>>>>> I don't know what I don't know. Could I please get a link to a part of >>>>>>> the documentation that teaches me what I need to understand? I'm tied >>>>>>> between querying syntax properties for a fully expanded module, and >>>>>>> writing a second set of macros that somehow know where they should be. >>>>>>> Not sure which is best. >>>>>>> >>>>>>> [1]: https://github.com/zyrolasting/xiden/blob/master/pkgdef/expand.rkt >>>>>>> [2]: >>>>>>> https://github.com/zyrolasting/xiden/blob/master/pkgdef/expand.rkt#L111 >>>>>>> [3]: >>>>>>> https://github.com/zyrolasting/xiden/blob/master/pkgdef/expand.rkt#L156 >>>>>>> >>>>>>> ~slg >>>>>>> >>>>>>> -- >>>>>>> You received this message because you are subscribed to the Google >>>>>>> Groups "Racket Users" group. >>>>>>> To unsubscribe from this group and stop receiving emails from it, send >>>>>>> an email to [email protected]. >>>>>>> To view this discussion on the web visit >>>>>>> [https://groups.google.com/d/msgid/racket-users/bVbaZ_0mwFcWTIaeuwqMUr7TVY6Rhr5dusG9LkbT0gqW7gWIYAb8IOEUYnKQPIVR2ZrDGm9QMGnW-2YvYqw81oUJVCSCuwhuX_Wx2OGVG-w%3D%40sagegerard.com](https://groups.google.com/d/msgid/racket-users/bVbaZ_0mwFcWTIaeuwqMUr7TVY6Rhr5dusG9LkbT0gqW7gWIYAb8IOEUYnKQPIVR2ZrDGm9QMGnW-2YvYqw81oUJVCSCuwhuX_Wx2OGVG-w%3D%40sagegerard.com?utm_medium=email&utm_source=footer). >>>>> >>>>> -- >>>>> You received this message because you are subscribed to the Google Groups >>>>> "Racket Users" group. >>>>> To unsubscribe from this group and stop receiving emails from it, send an >>>>> email to [email protected]. >>>>> To view this discussion on the web visit >>>>> [https://groups.google.com/d/msgid/racket-users/AqmR-7s3hD8k0bf_kMXDsZzwswfEDWXltrNMX4L8EmghOzqZdXHsptRiSANiepcq-m_JBjriooGpx8PbJmu9Bppci68ViREo6un9Fv0uXM0%3D%40sagegerard.com](https://groups.google.com/d/msgid/racket-users/AqmR-7s3hD8k0bf_kMXDsZzwswfEDWXltrNMX4L8EmghOzqZdXHsptRiSANiepcq-m_JBjriooGpx8PbJmu9Bppci68ViREo6un9Fv0uXM0%3D%40sagegerard.com?utm_medium=email&utm_source=footer). >>> >>> -- >>> You received this message because you are subscribed to the Google Groups >>> "Racket Users" group. >>> To unsubscribe from this group and stop receiving emails from it, send an >>> email to [email protected]. >>> To view this discussion on the web visit >>> [https://groups.google.com/d/msgid/racket-users/nV9CQYlVP_TDoZiSKSx9xKAATgrOhrG2z9Q5erXF04cza6pfHq3kUIPiTEUZX3HNOJeFVDrcbG-f6qHOYTT79yS6JPYKDM5KbtAdCbWoMdM%3D%40sagegerard.com](https://groups.google.com/d/msgid/racket-users/nV9CQYlVP_TDoZiSKSx9xKAATgrOhrG2z9Q5erXF04cza6pfHq3kUIPiTEUZX3HNOJeFVDrcbG-f6qHOYTT79yS6JPYKDM5KbtAdCbWoMdM%3D%40sagegerard.com?utm_medium=email&utm_source=footer). >> >> -- >> >> -- >> Jay McCarthy >> Associate Professor @ CS @ UMass Lowell >> http://jeapostrophe.github.io >> Vincit qui se vincit. > > -- > You received this message because you are subscribed to the Google Groups > "Racket Users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To view this discussion on the web visit > [https://groups.google.com/d/msgid/racket-users/xhOV-HJg6LAeonQMsnR0YYbbZjGOE8R6e5comR-j0RFDcc0liOMYs3-evzakJI7pOlFFNVzqPy0bguWls1pZHVkhas8NtexR2M2aLn0ujVc%3D%40sagegerard.com](https://groups.google.com/d/msgid/racket-users/xhOV-HJg6LAeonQMsnR0YYbbZjGOE8R6e5comR-j0RFDcc0liOMYs3-evzakJI7pOlFFNVzqPy0bguWls1pZHVkhas8NtexR2M2aLn0ujVc%3D%40sagegerard.com?utm_medium=email&utm_source=footer). -- You received this message because you are subscribed to the Google Groups "Racket Users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/racket-users/UEc8PUyir7lY_62bnHCS8vOkIQGiHoq5BEsxL2EhLpPevCDCURLjj4myIaYZtSbXJ25wl-CCMWFRJXzg2zDdVSvhPGSi_IKAFuGuQn44Pws%3D%40sagegerard.com.

