hyln9 / ikarus

Optimizing incremental native-code compiler for R6RS scheme. This is a forked repository.
https://launchpad.net/ikarus
Other
5 stars 0 forks source link

add something like plt's syntax-local-value #221

Closed hyln9 closed 10 years ago

hyln9 commented 10 years ago

Basically, I'd like to grab the value associated with a syntax binding

; mzscheme example

(define-syntax print-syntax-value (lambda (stx) (syntax-case stx () ((_ id) (identifier? #'id) (begin (display (syntax-local-value #'id)) (newline)

'(begin))))))

(define-syntax vv 42)

; displays 42 during expansion phase (print-syntax-value vv)

This feature would allow macro-controlled expansion of subexpressions, and extensible macros using syntactical keywords.

Ikarus restricts syntax bindings to procedures, which is less than ideal, but this can be worked around by wrapping arbitrary values in a lambda. (Omitted in the example for clarity)

Launchpad Details: #LP225387 Stephen Wrobleski - 2008-05-01 15:48:16 -0400

hyln9 commented 10 years ago

On May 1, 2008, at 3:48 PM, Stephen Wrobleski wrote:

Basically, I'd like to grab the value associated with a syntax binding

; mzscheme example

(define-syntax print-syntax-value (lambda (stx) (syntax-case stx () ((_ id) (identifier? #'id) (begin (display (syntax-local-value #'id)) (newline)

'(begin))))))

(define-syntax vv 42)

; displays 42 during expansion phase (print-syntax-value vv)

Does this only work at the top-level?

(let ([x 3]) (print-syntax-value x) 12) syntax-local-value: not defined as syntax: #syntax::298 === context === /Applications/PLT Scheme v3.99.0.18/collects/scheme/private/misc.ss:68:7

Launchpad Details: #LPC Abdulaziz Ghuloum - 2008-05-01 16:05:29 -0400

hyln9 commented 10 years ago

On May 1, 2008, at 3:48 PM, Stephen Wrobleski wrote:

(define-syntax vv 42)

Sorry, missed that. I thought that was (define vv 42).

Launchpad Details: #LPC Abdulaziz Ghuloum - 2008-05-01 18:29:39 -0400

hyln9 commented 10 years ago

On May 1, 2008, at 3:48 PM, Stephen Wrobleski wrote:

This feature would allow macro-controlled expansion of subexpressions, and extensible macros using syntactical keywords.

Can you provide an example of each of these two things that you're
trying to do?

Launchpad Details: #LPC Abdulaziz Ghuloum - 2008-05-01 19:37:20 -0400

hyln9 commented 10 years ago

It looks like my email reply to

Explicit expansion is the obvious case of something you can't do under r6rs (+ikarus) that would be enabled

; "expands" the outer level of the given expression ; 1. assumes the first element is a syntactical keyword ; 2. does not deal with expansions of the other elements, nested forms, or a ; new returned syntax form

(define (expand-outer stx) (syntax-case stx () [(id etc ...) ((syntax-local-value #'id) stx)]))

Fixing the restrictions in the example would create a full-functional explicit expansion mechanism. Such explicit subexpansion would be necessary to implement functionality similar to the local defines of let and lambda.

(define-syntax define-five (syntax-rules (define-five) [(define-five id)
(define id 5)]))

; evaluates to 5 (let () (define-five vv) vv)

a user-defined 'let' can only know what to do with define-five after it explicitly expands and sees that it's a define clause (rather than an expression)

Imagine a 'class' syntax definition, which uses two keywords 'method' and 'field'. The keywords are defined to raise an error, and the 'class' expander does a free-identifier=? to test for their usage.

To be able to create a new definition on top of that library (without touching the library itself), the class macro must explicitly pre-expand forms so that it can check for returned method and field forms.

There are cases where I would like to be able to check for the presence of a syntactical definition rather than blindly expanding, which is why I see syntax-local-value as more useful than a generic expand.

..

For the case of arbitrary values being passed around at expansion time as syntactical keywords, think of the r6rs syntactic record layer. When defining a record, a syntactical definition is created for the 'type', which is used by further macros to influence the code they generate. I'd like that generalized capability to use in my own code.

...

When not transforming, syntax-local-value errors out (as there is no transformer environment to look in)

When called on kernel syntax (like #'if), syntax-local-value also errors out, as it is not a syntax transformer.

Launchpad Details: #LPC Stephen Wrobleski - 2008-05-06 06:13:27 -0400

hyln9 commented 10 years ago

On May 6, 2008, at 3:13 AM, Stephen Wrobleski wrote:

It looks like my email reply to

Explicit expansion is the obvious case of something you can't do
under r6rs (+ikarus) that would be enabled

; "expands" the outer level of the given expression ; 1. assumes the first element is a syntactical keyword ; 2. does not deal with expansions of the other elements, nested
forms, or a ; new returned syntax form

(define (expand-outer stx) (syntax-case stx () [(id etc ...) ((syntax-local-value #'id) stx)]))

This will not work in general for all keyword-bound identifiers for two reasons:

  1. You are collapsing two macro expansion steps into one. This will cause incorrect (and often insidious) hygiene problems in the mark/antimark algorithm.
  2. Not all syntaxes are bound to procedures so you cannot just call the value.

Fixing the restrictions in the example would create a full- functional explicit expansion mechanism. Such explicit subexpansion would be necessary to implement functionality similar to the local defines of let and
lambda.

(define-syntax define-five (syntax-rules (define-five) [(define-five id) (define id 5)]))

; evaluates to 5 (let () (define-five vv) vv)

a user-defined 'let' can only know what to do with define-five
after it explicitly expands and sees that it's a define clause (rather than an expression)

Hmmm. I'm not sure I understand here.

A user-define let in terms of lambda would not have to know about define-five. Just try it:

(let-syntax ([let (syntax-rules () [( ([x v] ...) b b* ...) ((lambda (x ...) b b* ...) v ...)])]) (let () (define-syntax define-five (syntax-rules () [( id) (define id 5)])) (define-five vv) vv)) 5

If what you want is actually implement full internal defines, that would require me to expose all of the expander's internals and you would have to know how to handle each and every form the expander may throw at you. Neither you nor I would want to do this. Since lambda already has an internal defines context in its body, you can just use that.

Imagine a 'class' syntax definition, which uses two keywords
'method' and 'field'. The keywords are defined to raise an error, and the
'class' expander does a free-identifier=? to test for their usage.

Like quasiquote recognizing unquote and unquote-splicing (each of which raises a syntax error), right?

To be able to create a new definition on top of that library
(without touching the library itself), the class macro must explicitly pre-expand forms
so that it can check for returned method and field forms.

Well, that's not how I'd do it. I'd just let it fail and the syntax error trace would show the original offender.

There are cases where I would like to be able to check for the
presence of a syntactical definition rather than blindly expanding, which is why
I see syntax-local-value as more useful than a generic expand.

localexpand, macroexpand, macroexpand1, or whatever procedure that allows a transformer to fully or partially expand its input are not in the Ikarus macro expansion model and it's unlikely that they will be wedged in.

For the case of arbitrary values being passed around at expansion
time as syntactical keywords, think of the r6rs syntactic record layer. When defining a record, a syntactical definition is created for the
'type', which is used by further macros to influence the code they generate. I'd
like that generalized capability to use in my own code.

This, I agree, is useful. There should be a way to inject arbitrary values into the compile time environment and retrieve them at later times. All other compile-time values (e.g., lexical variables, transformers, record type identifiers, enumeration types, module names, primitive keywords, etc. etc.) will not be exposed to the user though. So, if you put a value in, you can get it out, and nothing more.

I know this sounds like it won't be fulfilling all your needs, but this is what I'm offering right now. How does it sound?

Aziz,,,

Launchpad Details: #LPC Abdulaziz Ghuloum - 2008-05-12 03:08:48 -0400

hyln9 commented 10 years ago

Added the ability to add compile time values in revision 1677. (I know it's too late, sorry)

Launchpad Details: #LPC Abdulaziz Ghuloum - 2008-11-14 05:54:56 -0500