# Macro that checks string value at compile time

**URL:** https://racket.discourse.group/t/macro-that-checks-string-value-at-compile-time/1826
**Category:** Questions & Answers
**Created:** [March 20, 2023, 2:22pm UTC](https://racket.discourse.group/t/macro-that-checks-string-value-at-compile-time/1826 "2023-03-20T14:22:49Z")
**Posts on this page:** 5
**Page:** 1

<div class="post-metadata">

### Author: ![ryanslade](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/ryanslade/32/1066_2.png) [@ryanslade](https://racket.discourse.group/u/ryanslade)
#### Post date: [March 20, 2023, 2:22pm UTC](https://racket.discourse.group/t/macro-that-checks-string-value-at-compile-time/1826/1 "2023-03-20T14:22:49Z")

</div>

I'm playing around with the idea of a macro that can, at compile time, find syntax errors in SQL queries. I'm very new to Racket in general and so for now I'm simply trying to write a macro that won't compile if I provide a string that contains a specific substring. I can't figure out how to do this and would love some pointers:

```scheme
#lang racket

(define-for-syntax (contains-secret? str)
  (regexp-match? #rx"secret" str))

; How can I use contains-secret? in here?
; When I try and check `s` I get the error: s: pattern variable cannot be used outside of a template in: s
(define-syntax (foo str)
  (syntax-case str ()
    [(_ s) (syntax "redacted")]
    [(_ _) (syntax str)]))
    
(foo "secret") ; Should return "redacted"
(foo "anything else") ; Should return "anything else"

```

I was thinking I could use fender expression but I can't get that to work.

---

<div class="post-metadata">

### Author: ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)
#### Post date: [March 20, 2023, 2:47pm UTC](https://racket.discourse.group/t/macro-that-checks-string-value-at-compile-time/1826/2 "2023-03-20T14:47:06Z")

</div>

Here's a version using fender expressions, and a version using `syntax-parse` which I think is nicer:

```scheme
#lang racket

(require (for-syntax syntax/parse))

(define-for-syntax (contains-secret? str)
  (regexp-match? #rx"secret" str))

; How can I use contains-secret? in here?
; When I try and check `s` I get the error: s: pattern variable cannot be used outside of a template in: s
(define-syntax (foo str)
  (syntax-case str ()
    [(_ s)
     (and (string? (syntax-e #'s)) (contains-secret? (syntax-e #'s)))
     (syntax "redacted")]
    [(_ s) (syntax s)]))
    
(foo "secret") ; Should return "redacted"
(foo "anything else") ; Should return "anything else"

(define-syntax (foo* stx)
  (syntax-parse stx
    [(_ s:str)
     #:when (regexp-match? #rx"secret" (syntax-e #'s))
     #'"redacted"]
    [(_ s:str) #'s]))

(foo* "secret") ; Should return "redacted"
(foo* "anything else") ; Should return "anything else"

```

---

<div class="post-metadata">

### Author: ![ryanslade](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/ryanslade/32/1066_2.png) [@ryanslade](https://racket.discourse.group/u/ryanslade)
#### Post date: [March 20, 2023, 3:13pm UTC](https://racket.discourse.group/t/macro-that-checks-string-value-at-compile-time/1826/3 "2023-03-20T15:13:48Z")

</div>

Thanks! The first answer using `syntax-case` works but the second using `syntax-parse` fails with this error:

```scheme
 _: wildcard not allowed as an expression
  after encountering unbound identifier (which is possibly the real problem):
   syntax-parse in: (_ s:str)

```

---

<div class="post-metadata">

### Author: ![samth](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/samth/32/3_2.png) [@samth](https://racket.discourse.group/u/samth)
#### Post date: [March 20, 2023, 3:14pm UTC](https://racket.discourse.group/t/macro-that-checks-string-value-at-compile-time/1826/4 "2023-03-20T15:14:27Z")

</div>

I think you need to include the addition `require` that I added to the program.

---

<div class="post-metadata">

### Author: ![soegaard](https://yyz2.discourse-cdn.com/free1/user_avatar/racket.discourse.group/soegaard/32/19_2.png) [@soegaard](https://racket.discourse.group/u/soegaard)
#### Post date: [March 20, 2023, 3:17pm UTC](https://racket.discourse.group/t/macro-that-checks-string-value-at-compile-time/1826/5 "2023-03-20T15:17:29Z")

</div>

Inspired by the solution of `samth`:

```scheme
#lang racket

(require (for-syntax syntax/parse))

(begin-for-syntax
  (define (contains-secret? str)
    (regexp-match? #rx"secret" str))

  (define-syntax-class secret-str 
    #:description "string containing secret"
    (pattern s:str
             #:fail-when (not (contains-secret? (syntax-e #'s))) 
                         "did not contain secret")))

(define-syntax (foo stx)
  (syntax-parse stx
    [(_ s:secret-str) #'"redacted"]
    [(_ s:str) #'s]))

(foo "secret") ; Should return "redacted"
(foo "anything else")

```
