[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: syntax-case identifier name predicate in guard expression
From: |
Zelphir Kaltstahl |
Subject: |
Re: syntax-case identifier name predicate in guard expression |
Date: |
Sun, 4 Aug 2019 22:53:03 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.8.0 |
Hi Guile Users!
I made some progress in writing a procedure defining macro for creating
procedures which talk to an API.
I now have working code, which checks the name of an identifier in a
guard expression:
----8<----8<----8<----
(use-modules (web uri)
(web client)
(json)
(ice-9 iconv)
(ice-9 regex))
(define* (send-request-to-docker-socket request-url docker-socket
my-content-type #:key (data #f))
(call-with-values
(lambda ()
(http-get request-url
#:port docker-socket
#:version '(1 . 1)
#:keep-alive? #f
#:headers `((host . ("localhost" . #f))
(content-type . (my-content-type (charset
. "utf-8"))))
#:body (scm->json-string data)
#:decode-body? #t
#:streaming? #f))
(lambda (response response-text)
(let ([resp-text-as-string (bytevector->string response-text
"utf-8")])
(cons response resp-text-as-string)))))
(define-syntax define-api-route
(lambda (stx)
(define (identifier-name->string id)
(symbol->string (syntax->datum id)))
;; Not needed yet.
;; (define (identifier->symbol id)
;; (syntax->datum id))
(define (contains-url-template-variable? route-as-string)
(string-match "<[^>]+>" route-as-string))
;; We do not need a macro to produce syntax. Instead we need to use
a procedure to produce the
;; syntax, because we want to use it while evaluating another macro.
(define make-simple-api-route-definition-syntax
(lambda (route http-method my-content-type route-as-string)
(syntax
(quote simple-route))))
(syntax-case stx (GET HEAD POST PUT DELETE CONNECT OPTIONS TRACE PATH)
[(_ route GET my-content-type)
(contains-url-template-variable? (identifier-name->string (syntax
route)))
(syntax (quote aaa))]
;; an else branch basically
[(_ route GET my-content-type) #t
(syntax
(define* (route docker-socket #:key (data #f))
(call-with-values
(lambda ()
;; GET request because syntax GET was specified
(http-get request-url
#:port docker-socket
#:version '(1 . 1)
#:keep-alive? #f
#:headers `((host . ("localhost" . #f))
(content-type . (my-content-type
(charset . "utf-8"))))
#:body (scm->json-string data)
#:decode-body? #t
#:streaming? #f))
(lambda (response response-text)
(let ([resp-text-as-string (bytevector->string
response-text "utf-8")])
(cons response resp-text-as-string))))))])))
(define* (connect-to-docker-socket #:key (socket-path
"/var/run/docker.sock"))
(let ([docker-sock-addr (make-socket-address AF_UNIX socket-path)]
[docker-sock (socket PF_UNIX SOCK_STREAM 0)])
(setsockopt docker-sock SOL_SOCKET SO_REUSEADDR 1)
(connect docker-sock docker-sock-addr)
docker-sock))
(display
(define-api-route /containers/json GET
"application/x-www-form-urlencoded"))
;; (let ([dock-sock (connect-to-docker-socket)])
;; (let ([resp-and-resp-text
;; (/containers/json dock-sock
;; #:data '(("all" . "true")
;; ("filters" . (("name" . #("db"))
;; ("status" .
#("running" "exited"))))))])
;; (display resp-and-resp-text)
;; (newline)))
(display
(define-api-route /container/json GET "application/x-www-form-urlencoded"))
----8<----8<----8<----
However, it seems, that now I have a new problem. It seems I cannot use
a define form inside a syntax-case case!
Running the above code I get the following error:
----8<----8<----8<----
ice-9/boot-9.scm:222:17: In procedure map1:
Syntax error:
/home/user/development/Guile/macros/procedure-defining/runnable-example.scm:78:1:
definition in expression context, where definitions are not allowed, in
form (define /containers/json (lambda* (docker-socket #:key (data #f))
(call-with-values (lambda () (http-get request-url #:port docker-socket
#:version (quote (1 . 1)) #:keep-alive? #f #:headers (quasiquote ((host
"localhost" . #f) (content-type "application/x-www-form-urlencoded"
(charset . "utf-8")))) #:body (scm->json-string data) #:decode-body? #t
#:streaming? #f)) (lambda (response response-text) (let
((resp-text-as-string (bytevector->string response-text "utf-8"))) (cons
response resp-text-as-string))))))
----8<----8<----8<----
While it was possible to have a define form inside a syntax-rules,
suddenly it seems impossible inside a syntax-case?
Removing the (syntax ...) around the define form does not help either
and gives the following error:
----8<----8<----8<----
ice-9/psyntax.scm:2612:57: In procedure build-dispatch-call:
Syntax error:
/home/user/development/Guile/macros/procedure-defining/runnable-example.scm:50:7:
definition in expression context, where definitions are not allowed, in
form (define route (lambda* (docker-socket #:key (data #f))
(call-with-values (lambda () (http-get request-url #:port docker-socket
#:version (quote (1 . 1)) #:keep-alive? #f #:headers (quasiquote ((host
"localhost" . #f) (content-type my-content-type (charset . "utf-8"))))
#:body (scm->json-string data) #:decode-body? #t #:streaming? #f))
(lambda (response response-text) (let ((resp-text-as-string
(bytevector->string response-text "utf-8"))) (cons response
resp-text-as-string))))))
----8<----8<----8<----
Once I exchange the define form inside the syntax-case with something
like (syntax (quote abc)), the error disappears, but then I am not
reaching the goal of defining a procedure.
I don't know how to make progress and it is not like searching
"procedure defining macros" yields particularly useful results and
examples of syntax-case usage I could find simply only use one case and
are not helpful for my purpose. I could not even find information about
whether there is an "else" keyword for syntax-case and decided to simply
use #t for the guard expression. If anyone can point me to an easy to
understand resource, which collects all this information and what to do
how with macros, that would awesome. I started reading the syntax-case
paper by Dybvig, but really, it should not be necessary to read all of
it, in order to understand how to use macros. I still seem to have gaps
in my understanding, otherwise I would be able to simply write this
macro down and be done. Currently I am not sure where I can find useful
examples of comparable macros, that show me how these things are usually
done.
What can I do, how can I change my code to get my procedure defined
inside syntax-case, or better even call another procedure, which give me
back the syntax, which will be the result of that syntax-case case?
Regards, Zelphir
- Re: syntax-case identifier name predicate in guard expression,
Zelphir Kaltstahl <=