
@samth let me know when you are around. I found a way for you to repro 2018 easily. :slightly_smiling_face:

In fact, I don’t really want to backtrack, I’m just generating a macro, but some patterns of the macro should be ignored and match nothing. The best way would be to have a non-syntax value (say, #f
) that means “don’t generate code here”, but handling syntax attributes with non-syntax values is hard and makes the macro difficult to read, because you need to add ~?
calls everywhere to protect from those #f
values. It becomes especially unhandy when you have ellipsis patterns. I have enough (~? (~@ . (element ...)))
in my code already.

Oh, right, the {~fail #:when #t}
is unnecessary just {~fail}
is fine

Thanks, I will test them out later

around now

I haven’t gotten around to writing all the details of running 2018 under qemu (which is basically what’s done with the racket/.gitlab
shell script - but for your specific environment). I have however managed to rent an aarch64 machine so I can run this on the real deal. If you want to reproduce it, I can give you access. I need to send you a key. One second.

I see it, but I may try on qemu first

@jerome.martin.dev I’m a little confused. If you want a pattern that matches nothing successfully, you can use {~and}
, {~do}
, or {~bind}
. If you want a pattern that matches nothing unsuccessfully, you can use {~fail}
. Your solution, {~not _}
, is of the latter type, so I would think you’d want something like {~fail}
.

I’m using (~alt pattern1 pattern2 (~not _) pattern3 (~not _) ...etc)
which allows me to accept everything that matches the defined alternatives, and reject all the rest.

You could just use {~fail}
there, and it would do the same thing. Both of them will cause the parser to backtrack to the nearest choice point, which in this case will just try the next option in the ~alt
.

Ok, I see!

I didn’t knew exactly how ~alt worked inside.

Well (~fail)
will allow to put an error message, so that’s better! Thanks!

syntax/parse is fully backtracking unless you explicitly cut using ~!
, so every parser that can match in multiple ways (i.e. anything that uses ~alt
or ~or*
) will exhaustively try every option before the parse fails.

There isn’t any difference between two kinds of failure in syntax/parse, except for error reporting purposes if all branches fail.

Wow, that clarifies a lot of assumptions I had about syntax/parse.

The full backtracking by default is very useful, but often it isn’t really what you mean, so putting ~!
and/or ~commit
in the right places can dramatically improve your macro’s error messages.

I didn’t get to use ~!
yet, but I guess it’ll come handy when I start having explicit error messages everywhere in my macros.

The #:commit
option for syntax classes is also extremely useful, and I find it is usually what you want.

I’ll check them out, thanks! Also, if you wonder what I’m working on to have such issues, the code is there: https://github.com/euhmeuh/rilouworld/blob/master/private/bundle/expander.rkt

It’s only 200 lines long, with the tests, but it’s pretty dense, at least for me.

@lexi.lambda There’s one thing I don’t quite get though: When using (~alt (~optional <foo>) <bar>) ...
, the ellipsis is “eaten” by the ~optional
clause. I can refer to <foo>
without using the triple-dots, while <bar>
requires them. Do you know how the ellipsis gets “assimilated” like that? I’m just being curious.

A simpler example of this “eating ellipses” behavior also happens with ~once
.

I didn’t check the implementation code, but I suppose it eats up the depth of its arguments or something

I would play around with using ({~alt {~once pat1} {~once pat2} etc.} ...)
and use that for a list-no-order
-like pattern

Yeah that’s what I’m doing. I understand how it works and what it does. I just wonder what happens under the hood.

I’d say a construction from primitives like ~or

But I’m just to lazy to check the code :stuck_out_tongue:

@jerome.martin.dev Ellipsis-head patterns are special. You should think of ~alt
+ ~optional
/~once
/~between
as being sort of a single syntactic form, not two separate patterns nested inside one another.

Essentially, ellipsis-head patterns are designed to handle common scenarios of parsing “options” in macros, where certain options may appear at most once, but can appear in any order.

So when you use ~once
, that is saying to syntax/parse “for this particular ~alt
sequence, this particular pattern needs to parse exactly once, but it can appear anywhere in that sequence”.

So ~once
and ~alt
cooperate with one another. They aren’t really separable.

~optional
is just like ~once
, but it can also parse zero times.

By the way, it is possible to make ~optional
not “eat” the ellipsis by putting it into a context where it is parsed as a head pattern instead of an ellipsis-head pattern. So, for example, if you were to write {~alt {~seq {~optional <foo>}}} ...
, then <foo>
would be bound with ellipsis depth 1. But this parser is essentially guaranteed to be a bug, since {~seq {~optional <foo>}}
is an ellipsis-head pattern that can match no terms. In theory, such a pattern could cause parsing to never terminate, in the same way that #px"()*"
will never terminate because it will match the empty term forever. But syntax/parse helpfully makes it a runtime error for an ellipsis-head pattern to match nothing, so at least your program just crashes instead. :)

(Though I think Racket actually makes #px"()*"
an error, too, so similar idea.)

In any case, the ~optional
isn’t actually helpful there, since you could just write {~alt <foo>} ...
and get the behavior you probably actually wanted, since the {~alt ....}
already includes the notion that the match might not succeed, and it should try one of the other branches, instead.

Thanks for that complete explanation! In fact, I need the (~optional)
in my cases because I want the term to be present only once or never. But I get what you’re saying :slightly_smiling_face:

@samth @jeapostrophe Travis is stuck on a couple build jobs so I tried directly locally and https://mirror.racket-lang.org/ seems not able to connect (same w/o TLS)

@jbclements are you around?

I’m here, yes. I’m teaching in five minutes, though.

I’ve been waiting for all Hell to break loose on this part of the build process, so I won’t be surprised by things going wrong. I’m also unable to ssh to winooski right now, though I thought it might be a fail2ban issue.

@greg Greg, are you saying that you’re not able to connect to mirror.racket-lang? If so, I agree. @samth, is mirror hosted by winooski? Also, happy to take this to DM.

@jbclements yes, mirror is winooski

and I was assuming based on the date that the build process had crashed it

That seems likely to me. I ran the build process under a tmux session, which doesn’t seem likely to have crashed it, but it’s at least possible. Also, pinging @stamourv here. In fact, speaking of ping, winooski still responds fine to ping.

So: Is it uncommon for winooski to go down on a build? Independently, what’s involved in bringing it back up?

Sigh. Off to class, back in 2 hours.

@jbclements winooski should never go down — currently no one can download racket in the default way

so this is quite bad

FWIW, I cannot ssh to winooski.

Will ping Stephen + mgmt.

Do we need another racket mirror? I would be happy to host a racket mirror in Europe - Germany.

@pocmatos: The other mirrors should be up.

@mflatt or @robby Do either of you know if there is any reason we couldn’t break off event% into something like racket/event
, and have racket/gui/base
re-export it? (Like with racket/draw
)?

But in general, though, another mirror could maybe be useful, I don’t know.

@mflatt or @robby would know, though.

I ask because i seems like its mostly just a container class for…well mostly symbols. And it would be useful to use in places where you can’t initialize racket/gui/base
(for the second time).

I don’t remember any particular obstacle.

http://mirror.racket-lang.org\|mirror.racket-lang.org seems to be back up again, thanks to whomever intervened!

A CDN that knew to try alternate origin servers — so the one URL still worked somehow — would be wonderful, but possibly not within PLT budget.

I did a naive guesstimate for AWS cloudfront and got about $90/month

although within AWS using S3 with cross-site replication is probably a simpler set up.

Is there a standard technique for encoding eval contexts in redex with a specific nesting depth? (e.g., the kind of thing where E_k
has k
nesting levels of some pattern, say)

@greg the major problem is that CDNs mostly don’t like/charge a lot for the size of the downloads

That’s why they’re not just on S3 like everything else

Another way of putting it is that the free unmetered 10G Ethernet jack in my office is worth a lot of money

What is the most popular racket based web framework?

Something like Ruby on Rails?