guile-user
[Top][All Lists]
Advanced

[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




reply via email to

[Prev in Thread] Current Thread [Next in Thread]