
In scribble doc, is it possible to link to an identifier like with @racket[some-id], but actually display another identifier? More precisely, I import (require (prefix-in rkt (only-in racket/base define)))
, and I want to write > …, just like racket’s @racket[rkt:define] but I want to render > …, just like racket’s define

@selcukahmed has joined the channel

Take a look at make-element-id-transformer

Would make-variable-id
(<https://docs.racket-lang.org/scribble/scheme.html?q=make-element-id-transformer#%28def._%28%28lib._scribble%2Fracket..rkt%29._make-variable-id%29%29|link to doc>) also be appropriate?

In this case no - since define
is a special form and not a variable. For functions it would be fine.

Thanks! That doesn’t look as straightforward as I hoped :smile:

It would be nice if there were a library form for this.

Here is a more complete solution. In order for @racket[rkt:id]
to render as @racket[id]
, we need to import id
without prefix. So I think one needs to put the code below in a separate module and then export all identifiers that begin with rkt:
#lang scribble/manual
@(require (for-label racket))
@(require (for-syntax racket/base scribble/manual syntax/parse racket/syntax scribble/racket))
@(require (for-syntax doc-coverage racket/set))
@(require scribble/racket)
@(define-syntax (define-elements-for-prefixed-imports stx)
(syntax-parse stx
[(_ prefix modname)
(define all-exports ; make sure each identifer occurs once only
(set->list (list->set (module->all-exported-names (syntax-e #'modname)))))
(define (format-sym id) (format-id stx "~a" id #:source stx))
(define (format-pre:id id) (format-id stx "~a:~a" #'prefix id #:source stx))
(define (format-elm:id id) (format-id stx "~a:~a" #'elm1234 id #:source stx))
(with-syntax* ([(id ...) (map format-sym all-exports)]
[(pre:id ...) (map format-pre:id all-exports)]
[(elm:id ...) (map format-elm:id all-exports)])
(syntax/loc stx
(begin
(begin
(define elm:id @racket[id])
(define-syntax pre:id (make-element-id-transformer (λ _ #'elm:id))))
...)))]))
@(define-elements-for-prefixed-imports rkt racket/base)
@section{Foo}
@racket[rkt:define]

Wow, thanks! That’s even more complicated than I imagined :smile:

Yeah - I underestimated it too.

What’s the correct way (pointer appreciated) with rackunit to check compile time error messages? (I’m writing a macro that should provide good error messages and not mix up the different possible messages)

I can imagine doing a dynamic require or an eval, but there must be something more standard somewhere


Wonderful, precisely what I was looking for! Thanks @popa.bogdanp!

Ouch, it doesn’t seem to test define
properly: #lang racket
(require syntax/macro-testing
rackunit)
(check-exn #rx"aaa"
(λ () (convert-syntax-error (define x 3))))
This catches: "define: not allowed in an expression context"
:disappointed:

I guess I can wrap it inside a (let () ...)
but that doesn’t sound right

There are some places in the docs that do this, so you could look for the source

Do you happen to remember such an identifier by any chance?


Too bad is still not accepted

The PR-er seems to delete the forked repo, so I don’t know if they want to continue working on it. I just asked in the PR if they are OK with someone taking it over.

Ah:
> Happy to take this on. I have a new year’s resolution to get back to some > of the open source work I had that piled up during the pandemic :slightly_smiling_face:. I’ll reassociate myself with this PR and write up the changes. Nice :slightly_smiling_face:

Hi all. I have added two sections to the macro tutorial. As before comments on contents, grammar, exposition are needed. Section “4. Syntax objects: Representing program fragments” and section “5. Exploring syntax objects” are new.

This is very nice!

I’ve never seen the word “enrichen” before. I google-d it and it looks like “to enrich” is more idiomatic.

Noted.

“During the expansion pass macros … rewrite program fragments” << should have a comma between “pass” and “macros”

Added.

High level comment: can we simplify section 3 by skipping read
and expand
and use read-syntax
and expand-syntax
right away?

I don’t know who the targeted audience is, but to me, I guess it would be people who can write simple macros and now want to understand macros better. The read
vs read-syntax
would be a distraction for these audiences IMO, and might cause them to feel “scared” (what the heck is namespace-syntax-introduce
?!?)

I feel it introduces more questions than answers

> … people who can write simple macros and now want to understand macros better. I like this way of putting it.
And you are right about expand-syntax
. I attempted to preface the last part of the experiment with for the second reading only
, but I think you are right that it is better to leave it out. Or perhaps return to it in a later section after namespace-syntax-introduce
has been discussed.

I’m trying to include code written in a custom language into another file at compile-time. This is what I have at the moment(see below), which compiles without errors but doesn’t appear to include the contents of “elf”. Expanding the include line shows the following error: “string::1: include/reader: read error (Encountered parsing error near #f (token ’no-tokens) while parsing #<path:/home/jonathan/git/identify/src/magic/elf> [line=#f, column=#f, offset=#f]) in: (include/reader “elf” magic-read-syntax-raw)”.
Am I on the correct path or am I misunderstanding what include/reader is supposed to do? My magic-read-syntax-raw returns a syntax object without the normal module wrapping. The “elf” file isn’t a racket file. It is written in the file command’s “magic” DSL, which I’ve written a racket implementation of. #lang racket
(require (for-syntax magic/reader))
(module rules magic/expander
(include/reader "elf" magic-read-syntax-raw))
(require 'rules)

Step 1 must be to check that magic-read-syntax-raw
can read the contents of “elf” without errors. Does (magic-read-syntax-raw "elf" (open-input-string "the contents of elf here"))
work as expected?

Does magic-read-syntax-raw
return a syntax object?

Yes, magic-read-syntax-raw appears to be working as I expect it to: reader.rkt> (define inport (open-input-file "/home/jonathan/git/identify/src/magic/elf"))
reader.rkt> (magic-read-syntax-raw "/home/jonathan/git/identify/src/magic/elf" inport)
'(#<syntax:/home/jonathan/git/identify/src/magic/elf:17:0 (named-query (name-line (offset 0) (name-type "name") elf-mips) (level) (line (offset 0) (type (numeric "lelong" (nummask (op "&") 4026531840))) (test (numtest 0)) (message "MIPS-I")) (level) (line (offset 0) (type (numeric "lelong" (nummask (op "&") 40...>
#<syntax:/home/jonathan/git/identify/src/magic/elf:30:0 (named-query (name-line (offset 0) (name-type "name") elf-sparc) (level) (line (offset 0) (type (numeric "lelong" (nummask (op "&") 16776960))) (test (numtest 256)) (message "V8+ Required,")) (level) (line (offset 0) (type (numeric "lelong" (nummask (op...>
#<syntax:/home/jonathan/git/identify/src/magic/elf:39:0 (named-query (name-line (offset 0) (name-type "name") elf-pa-risc) (level) (line (offset 2) (type (numeric "leshort")) (test (numtest 532)) (message "2.0")) (level) (line (offset 0) (type (numeric "leshort")) (test (numtest "&" 8)) (message "(LP64)")))>
#<syntax:/home/jonathan/git/identify/src/magic/elf:43:0 (named-query (name-line (offset 0) (name-type "name") elf-le) (level) (line (offset 16) (type (numeric "leshort")) (test (numtest 0)) (message "no file type,")) (level) (line (offset 16) (type (numeric "leshort")) (test (numtest 1)) (message "relocatabl...>
#<syntax:/home/jonathan/git/identify/src/magic/elf:298:0 (query (line (offset 0) (type (string8 "string")) (test (strtest "\u007FELF")) (message "ELF")) (level) (line (offset 4) (type (numeric "byte")) (test (numtest 0)) (message "invalid class")) (level) (line (offset 4) (type (numeric "byte")) (test (numtes...>)
reader.rkt>

Although, now that I look at it again, that appears to be a list of syntax objects instead of a syntax object.

That’s probably it.

Shouldn’t strip-context here be returning a syntax object: (define (magic-read-syntax-raw path port)
(define parse-tree
(stx-cdr
(stx-cdr
(parse path (make-tokenizer port)))))
;(eprintf "parse tree = ~a" parse-tree)
(strip-context parse-tree))

?

That’s my expectation as well.

I’m not sure what the problem is then. Am I interpreting that output above correctly? That is a list of syntax objects and not a syntax object, right? If so maybe I can just do something different with or instead of syntax-context.

> (syntax? '(1 2 3))
#f

You could make into a syntax object: (with-syntax ([(x ...) tree) #'(x ...))

Or maybe a call to datum->syntax
is better?

I think, it leaves any syntax objects in a list untouched.

It appears that strip-context will accept non-stx. So yes, I think datum-syntax may be better.

Just making sure, we are not talking past each other: (datum->syntax #'here (strip-context parse-tree)))

Hmm. We are on the same page here, but I still get the same error when I expand the include line. magic-read-syntax-raw is returning a syntax object now though. If this should be workable in theory, I will keep experimenting with it.

This is what I have now: (define (magic-read-syntax-raw path port)
(define parse-tree
(stx-cdr
(stx-cdr
(parse path (make-tokenizer port)))))
;(eprintf "parse tree = ~a" parse-tree)
(datum->syntax #'here (strip-context parse-tree)))

The idea looks fine to me.

Using include/reader that is.

Ok, great. Thanks very much for your help. I will keep tinkering with it.

Is token 'no-tokens)
part of the output of your reader, or does it come from include/reader ?

I’m not entirely sure because the parse function is from #lang brag. I was thinking it was probably from include/reader but I could be wrong.

I get different errors from include/reader if it can’t find the file or if I use the wrong read-syntax function though.

In that case I think it comes from the parser.
Maybe check how the input for the reader looks like, when include/reader is involved. Just to be sure. For example, insert an displayln in your reader to print its input.

brag has a token function, so it could be the parse function. But I don’t get the error from magic-read-syntax-raw in isolation.

Btw - line=#f, column=#f, offset=#f]) shows that line numbers aren’t counted. You can use (port-count-lines! port)
to turn it on.

hmm, my make-tokenizer function does do that, so I’m not sure why they aren’t being counted. unless the file really isn’t being read or something.

@alama got your newsletter, bought Remember because it was written in Racket, would love to see a write-up on developing iOS/Android apps in Racket

@popa.bogdanp did a write-ups discussing macOS and iOS https://defn.io/page/2/\|https://defn.io/page/2/

Thanks for buying Remember! And thanks to @alama for the shout-out! Like @spdegabrielle mentioned, I did a couple write-ups about embedding Racket into native apps on https://defn.io/2020/01/04/remember-internals/\|macOS and https://defn.io/2020/01/05/racket-on-ios/\|iOS on that blog. I’m also planning to do another one on embedding Racket CS at some point. Remember is source-available so if you’re curious about its internals, you can find the code https://github.com/bogdanp/remember\|here.

In syntax-parse
, the error message for a #:fail-when
of a syntax-class is tailored to the enclosing macro name, which is pretty cool. But is there a way to make it ‘bounce’ to a super enclosing macro? syntax/loc
doesn’t help here (afaict).

Does #:context
help?

#lang racket
(require (for-syntax racket/base
syntax/parse))
(begin-for-syntax
(define-syntax-class aclass
(pattern x
#:fail-when (= 3 (syntax-e #'x))
"x must not be 3")))
(define-syntax (foo stx)
(syntax-parse stx
#:context (syntax-parse stx
[(_ orig-stx _ ...) #'orig-stx])
[(_ _orig-stx x:aclass ...) #''(x ...)]))
(define-syntax (bar stx)
(syntax-parse stx
[(_ . args) #`(foo #,stx . args)]))
(bar 3)

Here’s a quick and dirty approach

A better approach might be to use a syntax parameter to communicate the context

I have an unfinished library that does this by default

alas I want to use foo
directly also sometimes. It’s going to get dirtier :slightly_smiling_face:

Thanks for the pointer though

Maybe the syntax parameter idea is better. I’ve never used them

I notice macros that accept the original syntax are usually suffixed with /derived

E.g., struct/derived
, for/fold/derived

so you can do foo/derived

and both foo
and bar
would call foo/derived

My actual case is lambda
and define

But yeah, there could be a lambda/derived
I guess

seems messy though

Well, my first attempt with syntax-parameters was unsuccessful, whereas the dirty approach with /derived
does work and , so… thanks :smile:


Why is it that struct?
is #f
when the value is a made from a struct without #:transparent
and vice-versa?

(regexp-match #px"[[^:space:]+" bs start)

can anyone tell me why this isnt working ? im trying to filter out spaces and "\t" and such

From: > (regexp-match #px"[[^:space:]+" "foo bar baz")
'("a")
We can see at :space: is interpreted as the characters : s p a c e . So we need to figure out where :space: can be used.

so that example is only giving back “a” ? what about all the other characters?

It seems the problem is that the syntax is [:space:]
. > (regexp-match #px"[^[:space:]]+" "foo bar baz")
'("foo")

what if you want the rest of the characters? like bar and baz?

Quick example: (struct foo (a))
(struct? (foo 1))
(struct bar (a) #:transparent)
(struct? (bar 1))
I think it might have to do with inspectors, but I don’t know what those are or why they’re relevant.

Then use regexp-match*
: > (regexp-match* #px"[^[:space:]]+" "foo bar baz")
'("foo" "bar" "baz")

ohhh

Btw - in this particular case, you can also use string-split
. https://docs.racket-lang.org/reference/strings.html?q=string-split#%28def._%28%28lib._racket%2Fstring..rkt%29._string-split%29%29

one last constraint, i need to filter out backslashes and quotes

(#"\"H&C-54-s0sc1\"")

\" "\

(regexp-match #px"[^[:space:],^[\"]+")
seems to work

thanks for the help!

This also filters out commas.

Maybe: > (regexp-match* #px"[^[:space:]\"\\\\]+" "foo bar,baz\\qux")
'("foo" "bar,baz" "qux")

One more thing to try: Use an absolute path instead of a relative one (to make sure, the proper file is read). I managed to make an example with the standard reader:
#lang racket
(require racket/include)
(begin-for-syntax
(define (reader source-name port)
(read-accept-lang #t)
(read-accept-reader #t)
(read-syntax source-name port)))
(include/reader (file "/Users/soegaard/tmp/w1.rkt") reader)
(require 'w1)
x
The file w1.rkt contains: #lang racket
(define x 42)
(provide x)

struct?
means that it “struct-ness” is accessible to you, such as via reflection. Lots of things are structures that are opaque, such as channels or functions, and conceptually everything is a struct.

maybe we ought to have named that predicate differently

Yes, the name suggests that it’s useful but it isn’t

cant seem to find a built in way to flatten vectors

i presume i turn a vector->list , flatten, then list->vector ?

you could iterate over them with a for loop so you don’t have to construct an intermediate list

I was never able to get this to work, but I’ve moved on. I did switch to using ‘file’ to provide a full path and was able to get an example using the standard reader to work. Thanks for your help though. Much appreciated!

what is the extension for pure data s-expression files? e.g, ones that don’t have a #lang #(
"potion"
"sword"
)
currently saving these as items.rkt
which is fine but im wondering if there’s another name people use

huh, looks like there is none… welp, gonna call them .x
then for now

@amol.jha has joined the channel

@jestarray does it have to have a special extension?

you could just put .dat or something on it to denote that it’s just data

nah not really, at minimum i just want it to differ from the .rkt
because the file manager puts a racket icon on it despite it being not really being an executable script. I’m surprised there isn’t a formally defined name for this

.rktd


so you just want your file manager to show it as a racket file even though it doesn’t contain racket code?

no, that’s what i dont want lol, anywhoo i decided on .dat like you said

sounds good