I’m reading Beautiful Racket. I decided to change the jsonic delimiters @$ … $@ to just ( … ). This raised the difficulty of reading s-exp recursively. Beautiful Racket’s from/to
is not sufficient for this. I could perhaps call read directly from the tokenizer as soon as I see "(". But I’d have to somehow put the "(" back in the stream otherwise read would start after the parenthesis.
I also considered leaving that up to the parser. That seems more difficult. It requires me to write macros I don’t know how to write. I built, for instance, this kind of parse-tree. parser-test1.rkt> (parse-to-datum (apply-tokenizer-maker make-tokenizer "(= 2 (+ 1 1))"))
'(jsonic-program
(jsonic-sexp
"("
(jsonic-program
(jsonic-char "=")
(jsonic-char " ")
(jsonic-char "2")
(jsonic-char " ")
(jsonic-sexp
"("
(jsonic-program
(jsonic-char "+")
(jsonic-char " ")
(jsonic-char "1")
(jsonic-char " ")
(jsonic-char "1"))
")"))
")"))
But I don’t know how to write a macro jsonic-sexp that would perhaps concatenate all of its arguments as a final string and then call read and eval on it. All macros are string-producing so jsonic-sexp needs to just handle lots of strings, concatenate them and eval. That’s how I see it right now. I kinda feel that, given the level I am right now, I should handle this with a trick or two in the tokenizer. For instance, I could perhaps write a recursive procedure that reads the port until it finds the complete s-exp, producing a single token with the entire s-exp in there. (I also don’t really know how to do this right now, but I think I could somehow pull it off. I mean, I don’t know because the "(" has already been read out of the port.)
If your port is a file-stream port or a string port, you can use the following unget
function to put (
back:
(define (unget s port)
(file-position port (- (file-position port) (string-utf-8-length s))))
E.g.:
(lexer
["("
(begin
(unget lexeme input-port)
(read input-port))]
That’s so cool! That’s really the trick I was looking for! Very cool! Thank yu so much! tokenizer.rkt> (apply-tokenizer-maker make-tokenizer "(= 2 (+ 1 1))")
'((= 2 (+ 1 1)))
I have a unit
defining a struct
named packed-vector
with #:property prop:sequence
. I wanted to make in-packed-vector
using define-sequence-syntax
and use it with prop:sequence
, but unfortunately it seems define-unit: cannot export syntax from a unit in: in-packed-vector
. Is there any way to parametrize a module (such as is possible with unit
) while still allowing me to do what I want?
samth spoke about “just using a lambda instead of a unit” for parametrization. But I don’t get what he means.
I guess it means you can create a normal module, where all the functions are wrapped in a single lambda that takes the ‘unit parameters’ as arguments and returns all the functions
You can also put all the generated functions in a struct and return the struct for convenience of the caller
(I’m just guessing here, I haven’t done that myself)
Ah, yes! I somehow forgot that Racket allowed returning multiple values! I think that’ll do the trick. Thanks! :+1:
You can (maybe) put the use of define-sequence-syntax in the unit signature
How can I make a macro where I replace part of an identifier name with an argument value, i.e.: (define-fictive-macro (replace-part-of-id part) (part-whatever #t)) and results would be (replace-part-of-id a) -> (a-whatever #t), (replace-part-of-id b) -> (b-whatever #t) and so on… ?
You can use format-id
in a #:with
clause of define-simple-macro
(or define-syntax-parse-rule
if you have the latest version of racket)
Let us know if you get stuck
I have a contract like [u2-vector-set! (-> u2-vector? exact-nonnegative-integer? between-zero-and-max-element any)]
. Is there a way to do better than exact-nonnegative-integer?
here? Such as, is there some way to tell the contract system: “test that the runtime value is less than the vector length” (of course, I can do that in the implementation but just curious)
Take a look at dependent function contract.
I have a collection of many identifiers such as packed-vector, packed-vector-ref, etc. I would like to make a macro to change those according to an argument, i.e u2-vector, u2-vector-ref, etc. where the argument would be ‘u2’. I understand how to replace an identifier by another, but that would mean I have to provide all the new names as arguments instead of just ‘u2’ in this example. Is there a way to make that easier by replacing only part of the identifier? I’m a bit stuck…
@laurent.orseau mentioned format-id
above which is what you would want to use to synthesize a new name in your macro. For example, something like: (define-simple-macro (example arg)
#:with name (format-id #'arg "~a-vector" (syntax->datum #'arg))
(name #t))
(define (test-vector v)
(println v))
(example test); => #t
I got lost in the docs. Indeed, I found the relevant portion now thanks to your example. Sorry about this!