[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: |
Tue, 6 Aug 2019 01:58:16 +0200 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.8.0 |
Hi Mark!
Thank you for your help!
I must have been blind from moving code back and forth and the (display
...) was still from when the output of the macro was simply a symbol,
for checking whether the guard expression in the (syntax-case ...) cases
works. Also I was confused because the error message mentioned the whole
define expression, which is why I looked in the wrong place : )
I got it working now, including the more complex case of having
variables in request URLs.
(https://gitlab.com/ZelphirKaltstahl/guile-scheme-macros/blob/fccb603a92f2c2d2709e169bbdd516fcf05a6816/procedure-defining/runnable-example.scm)
Fortunately I re-read the Guile docs and read about with-syntax.
Suddenly with-syntax made a lof of sense :D
I think I am finally getting it more or less. There were quite a few
snares to overcome for me, but I think that with some trial and error I
can now get things done.
The complex case should also be moved out of the syntax-case directly
and then I can use it in the library and can finally define API routes
without much trouble (hopefully! unless I overlooked some possibility
for sending requests to the docker API), yay!
Regards,
Zelphir
On 8/5/19 8:51 PM, Mark H Weaver wrote:
> Hi Zelphir,
>
> Zelphir Kaltstahl <address@hidden> writes:
>
>> 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.
> Right. Before, you were trying to perform the check within a procedural
> macro, whose code was run when the 'define-api-route' macro was being
> _defined_, which is too early. Here you have the right idea.
>
>> (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!
> No, that's not it. The problem is not with the macro itself, but with
> how you're attempting to use it.
>
> The problem is simply that the macro expands into a definition, and you
> are trying to use it within an expression context, where definitions are
> not allowed, here:
>
>> (display
>> (define-api-route /containers/json GET
>> "application/x-www-form-urlencoded"))
> This fails for the same reason that the following fails:
>
> (display (define foo 1))
>
>> While it was possible to have a define form inside a syntax-rules,
>> suddenly it seems impossible inside a syntax-case?
> For purposes of this issue, it is irrelevant whether the macro was
> defined using syntax-rules or syntax-case.
>
> If you have a macro that expands into a definition, then you can only
> use that macro in a context where definitions are allowed.
>
> Best,
> Mark