jerome.martin.dev
2019-3-17 12:32:56

Is it possible to pass down a syntax object from one phase to the other? I have a macro at phase 2, which creates a macro at phase 1. But to be able to pass down syntax objects, I put them into structs, then transform them back into syntax objects using stx-map, datum->syntax, and co. Is there a better way?


jerome.martin.dev
2019-3-17 14:31:29

I think I found a simpler way by simply generating a #'() call


soegaard2
2019-3-17 14:38:42

In principle the compilation happening in phase 2 and phase 1 can happen at separate times (say monday and tuesday). Therefore the solution you found (letting phase 2 generate a phase 1 program containing a call to syntax) seems to be The Right Thing®.


jerome.martin.dev
2019-3-17 15:13:50

Ok, another short question… (I feel like I’ll never be finished with that freakin’ macro) If I produce a syntax-list, then bind it with #:with (elem ...) (my-syntax-list-producer) it fails and just binds the first item in the list


soegaard2
2019-3-17 15:14:37

Double check: what does (display (my-syntax-list-producer) print?


jerome.martin.dev
2019-3-17 15:15:07

it prints a correct syntax like so: #'((elem1 blabla) (elem2 blabla))


soegaard2
2019-3-17 15:15:22

Also try #:with ((elem …) …)


alexknauth
2019-3-17 15:16:52

Is it always a list of two-element lists?


jerome.martin.dev
2019-3-17 15:17:36

nope, there can be more or less elements inside


jerome.martin.dev
2019-3-17 15:18:25

oh, wait, I think I see the issue


jerome.martin.dev
2019-3-17 15:18:35

it had a syntax-class


jerome.martin.dev
2019-3-17 15:18:44

but the syntax-class is already resolved at this point


alexknauth
2019-3-17 15:19:10

?


jerome.martin.dev
2019-3-17 15:20:05

Ok, so my issue is that I want to merge two (elem:my-class …) bindings into a single one


alexknauth
2019-3-17 15:20:57

Oh, where my-class is a splicing class?


jerome.martin.dev
2019-3-17 15:21:15

nope


jerome.martin.dev
2019-3-17 15:21:26

it’s a simple class


jerome.martin.dev
2019-3-17 15:21:39

but it parses a lot of stuff and creates attributes


jerome.martin.dev
2019-3-17 15:22:19

and I want to get those attributes later, but since the merge happens between different phases, the attributes are gone


jerome.martin.dev
2019-3-17 15:22:36

(I know, it’s complicated :P)


alexknauth
2019-3-17 15:22:58

That’s a lot of things to do at once


soegaard2
2019-3-17 15:23:23

So you need to rewrite (a1 a2 …) (b1 b2 …) to (a1 b1 a2 b2 …) ?


jerome.martin.dev
2019-3-17 15:23:30

yep


soegaard2
2019-3-17 15:24:14

(append-map list as bs)


jerome.martin.dev
2019-3-17 15:24:32

right now I’m doing an append, then datum->syntax


jerome.martin.dev
2019-3-17 15:24:52

but datum->syntax loses the class attributes, it just renders plain syntax


soegaard2
2019-3-17 15:25:51

attributes on the indivisual elements?


jerome.martin.dev
2019-3-17 15:25:55

yep


soegaard2
2019-3-17 15:26:20

(append-map list (syntax->list as) (syntax->list bs)) ought to be fine?


jerome.martin.dev
2019-3-17 15:27:09

yeah, that’s what I do… but in fact I realize the issue is that I can’t pass attributes down a phase level. I need to render them into a syntax call, so I lose them


soegaard2
2019-3-17 15:28:39

Hmm. I can’t remember how that works.


jerome.martin.dev
2019-3-17 15:29:20

Well, the only way I see would be to make a call to syntax with each attribute rendered in the list


jerome.martin.dev
2019-3-17 15:29:34

so that I can get them back by position


jerome.martin.dev
2019-3-17 15:31:11

something like #:with (elem:class ...) (my-elements) #'(define-syntax my-other-phase (quote-syntax #'(elem.attr1 elem.attr2 elem.attr3)))


alexknauth
2019-3-17 15:31:47

I would do this by having a single attribute of the syntax class to represent the info that needs to be passed down a phase level


jerome.martin.dev
2019-3-17 15:31:53

yep


jerome.martin.dev
2019-3-17 15:31:56

I’m going this way


alexknauth
2019-3-17 15:33:36

And then if that attribute is called nextphase the syntax call would look like #'(elem.nextphase ...)


jerome.martin.dev
2019-3-17 15:34:39

It’s reassuring to know there are people like you who can actually understand what I’m doing… Cause I don’t x)


alexknauth
2019-3-17 15:35:47

I’ve learned because I’ve failed before but kept going eventually finding it


jerome.martin.dev
2019-3-17 15:37:00

So, before I try putting everything in a single syntax for the next phase… Can you confirm that there’s no way to create a syntax-class instance manually?


jerome.martin.dev
2019-3-17 15:37:32

cause that would simplify the code


alexknauth
2019-3-17 15:40:48

Not sure what you mean


soegaard2
2019-3-17 15:43:57

Do you (@jerome.martin.dev) mean something like this? (syntax-parse <manually-created-syntax-object [elem:class <use elem here>])


jerome.martin.dev
2019-3-17 15:44:52

yep, except I’d like to return the bound value instead of using it. But I guess it’s not possible


jerome.martin.dev
2019-3-17 15:45:51

It breaks the fundamentals of syntax-parsing


jerome.martin.dev
2019-3-17 15:46:59

I’m going to use a simple list with two elements and put the attributes I need in there


jerome.martin.dev
2019-3-17 15:48:12

like this: (list (quote-syntax (<elem>.attr1 ...)) (quote-syntax (<elem>.attr2 ...)))


jerome.martin.dev
2019-3-17 15:51:06

or maybe…


jerome.martin.dev
2019-3-17 15:51:37
(quote-syntax ((<elem>.attr1 <elem>.attr2) ...))

jerome.martin.dev
2019-3-17 15:57:37

then I can do #:with ((attr1 attr2) ...) (merge-elements)



jerome.martin.dev
2019-3-17 16:06:20

Oh my god my code works


jerome.martin.dev
2019-3-17 16:07:38

I think it’s the most complicated macro I ever wrote


jerome.martin.dev
2019-3-17 16:07:48

and it’s only 150 lines long x)


jerome.martin.dev
2019-3-17 16:09:30

well, actually even less than that, I’m counting (define-for-syntax) helpers too


jerome.martin.dev
2019-3-17 16:10:16

it generate macros that can inherit from other macros


jerome.martin.dev
2019-3-17 16:14:18

I just have a small question for you @alexknauth : Remember yesterday you gave me the way to create a wrapper around struct ids at compile time? I have doubts about #:property prop:procedure being passed (make-variable-like-transformer #'internal-id). It takes only one argument so when a call is done like so (my-own-wrapper value1 value2 value3) it fails as “arity mismatch”


jerome.martin.dev
2019-3-17 16:19:48

For the record, a complete example: ;; in begin-for-syntax: (struct metactor (normal struct-info attributes) #:property prop:procedure (struct-field-index normal) #:property prop:struct-info (lambda (self) (metactor-struct-info self)) #:property prop:metattributes (lambda (self) (metactor-attributes self))) ;; in macro template for next phase: (struct <id> () #:name internal-id #:constructor-name internal-id) (define-syntax <id> (metactor (make-variable-like-transformer #'internal-id) (extract-struct-info (syntax-local-value #'internal-id)) (~? (quote-syntax ((<own-attr>.parse-pattern <own-attr>.term) ...)) #'())))


jerome.martin.dev
2019-3-17 16:22:33

the only part I don’t understand is the use of make-variable-like-transformer and struct-field-index


jerome.martin.dev
2019-3-17 16:29:01

obviously it just works if I use internal-id instead, so it’s not a big deal for me. I just want to understand what’s happening


alexknauth
2019-3-17 17:08:02

I’ll have to try it on my computer


jerome.martin.dev
2019-3-17 17:13:16

Thanks! I cannot express how awesome the help I get here is :slightly_smiling_face: When I’m describing my problem I feel like I’m using some weird incantation spells, but you actually understand!


alexknauth
2019-3-17 17:25:07

Oh, sorry, I forgot that make-variable-like-transformer produces a set!-transformer instead of a “normal” procedure.


alexknauth
2019-3-17 17:25:49

So to get around this I usually define: (begin-for-syntax (define (make-var-like-transformer id) (set!-transformer-procedure (make-variable-like-transformer id))))


alexknauth
2019-3-17 17:27:30

To whoever made make-variable-like-transformer, why is the value it returns not a procedure?


alexknauth
2019-3-17 17:28:27

And to whoever made prop:procedure why do you get an “arity mismatch” error if the value doesn’t lead to a procedure, instead of a “not a procedure” error?


soegaard2
2019-3-17 17:32:03

It returns a set!-transformer. So something needs to know whether a transformer is a set!-transformer. Probably set!-values. But is that what you are getting at?


alexknauth
2019-3-17 17:33:14

But something can be both a set!-transformer? and a procedure? if it implements both prop:set!-transformer and prop:procedure


soegaard2
2019-3-17 17:34:08

Could it be that set!-transformers are older than applicable structs?


jerome.martin.dev
2019-3-17 17:54:47

Thanks! It works fine now :slightly_smiling_face:


soegaard2
2019-3-17 19:31:20

It seems 203 is the first version of the docs where “structures as functions” are mentioned (that section is not in the 202 docs).


soegaard2
2019-3-17 19:32:02

On the other hand set!-transformers are older. But as I read the old docs on set!-transformer a normal procedure is expected.


mflatt
2019-3-17 19:37:27

That choice allows procedure? to be a constant-time test.


alexknauth
2019-3-17 19:39:06
(define x 5)
(define-syntax m1 (make-set!-transformer (λ (stx) #'x)))
m1 ;=> 5
(define-syntax m2 (compose identity (make-set!-transformer (λ (stx) #'x))))
;=error>
;compose: contract violation
;  expected: procedure?
;  given: #<set!-transformer>

soegaard2
2019-3-17 19:40:23

Anyone knows what’s the oldest version of PLT Scheme that still runs on macOS?


alexknauth
2019-3-17 19:40:28

That makes sense as to why procedure? would return true. However, it doesn’t make sense why the error message would say “arity mismatch”


soegaard2
2019-3-17 19:42:40

:slightly_smiling_face: Attempted to download v103. Got to choose between Mac Classic ppc or 68k.


soegaard2
2019-3-17 19:50:03

Version 350 gives a similar error message: procedure application: expected procedure, given: #<set!-transformer>; arguments were: #<syntax::474>


mflatt
2019-3-17 20:00:08

I guess it’s more that procedure-arity returns '() (and since procedure? returns true, then procedure-arity needs to return something). With that choice, attempting to apply the procedure should report an arity error.


diego
2019-3-17 21:35:34

Thanks for the link! A great book for a Commodore fan :slightly_smiling_face:


alexknauth
2019-3-18 01:02:27

I have a function that’s just like make-variable-like-transformer except that it doesn’t produce a set!-transformer or handle setter-stx.

What should it be called? make-constant-like-transformer doesn’t seem right. Is something like make-expression-id-transformer better? Expression alias? Named expression transformer? Other ideas?


alexknauth
2019-3-18 01:05:40

I seem to copy some version of this function into every file or every project I write. Also, the fact that it doesn’t exist in the base racket distribution has caused problems for both me and just recently for Jerome.


alexknauth
2019-3-18 01:06:19

The only problem I’m having is giving it a name.


greg
2019-3-18 01:08:18

@alexknauth I think you already solved this? https://twitter.com/AlexKnauth/status/1063213319031570432


alexknauth
2019-3-18 01:09:20

Is make-id-transformer a good name?


alexknauth
2019-3-18 01:10:18

I am constantly frustrated because both make-rename-transformer and make-variable-like-transformer are so close but can’t be used in so many situations that require a procedure? value.


ryanc
2019-3-18 02:36:47

@alexknauth You could change make-variable-like-transformer to return an instance of a struct that implements both prop:set!-transformer and prop:procedure. Or you could add an argument to suppress the make-set!-transformer wrapper.


alexknauth
2019-3-18 02:37:47

Should make-set!-transformer return such a struct that has both?


ryanc
2019-3-18 02:40:50

I don’t know. That’s a bigger change, and it risks breaking code that assumes set!-transformers and procedures are disjoint. I don’t know if any such code exists.


alexknauth
2019-3-18 02:41:27

I think the procedure? behavior should be the default behavior of some procedure in the documentation. I don’t want it to be “hidden” behind an optional argument.


ryanc
2019-3-18 02:43:44

I think it’s fine to change make-variable-like-transformer to return something that implements both interfaces. (It’s more recent and less widely used than set!-transformer, which is why I think there’s less risk with it.)


alexknauth
2019-3-18 02:44:24

Okay.


alexknauth
2019-3-18 03:29:52

@ryanc That’s what I’ve now done in https://github.com/racket/racket/pull/2540