---
title: syntax-parse Example
tags: syntax-parse
slideOptions:
theme: white
slideNumber: 'c/t'
center: false
transition: 'none'
keyboard: true
width: '93%'
height: '100%'
---
<style>
/* basic design */
.reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5, .reveal h6,
.reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p {
font-family: 'Meiryo UI', 'Source Sans Pro', Helvetica, sans-serif, 'Helvetica Neue', 'Helvetica', 'Arial', 'Hiragino Sans', 'ヒラギノ角ゴシック', YuGothic, 'Yu Gothic';
text-align: left;
line-height: 1.8;
letter-spacing: normal;
text-shadow: none;
word-wrap: break-word;
color: #444;
}
.reveal h1, .reveal h2, .reveal h3, .reveal h4, .reveal h5 {font-weight: normal;}, .reveal h6 {font-weight: bold;}
.reveal h1, .reveal h2, .reveal h3 {color: #2980b9;}
.reveal th {background: #DDD;}
.reveal section img {background:none; border:none; box-shadow:none; max-width: 95%; max-height: 95%;}
.reveal blockquote {width: 90%; padding: 0.5vw 3.0vw;}
.reveal table {margin: 1.0vw auto;}
.reveal code {line-height: 1.2;}
.reveal p, .reveal li {padding: 0vw; margin: 0vw;}
.reveal .box {margin: -0.5vw 1.5vw 2.0vw -1.5vw; padding: 0.5vw 1.5vw 0.5vw 1.5vw; background: #EEE; border-radius: 1.5vw;}
/* table design */
.reveal table {background: #f5f5f5;}
.reveal th {background: #444; color: #fff;}
.reveal td {position: relative; transition: all 300ms;}
.reveal tbody:hover td { color: transparent; text-shadow: 0 0 3px #aaa;}
.reveal tbody:hover tr:hover td {color: #444; text-shadow: 0 1px 0 #fff;}
/* blockquote design */
.reveal blockquote {
width: 90%;
padding: 0.5vw 0 0.5vw 6.0vw;
font-style: italic;
background: #f5f5f5;
}
.reveal blockquote:before{
position: absolute;
top: 0.1vw;
left: 1vw;
content: "\f10d";
font-family: FontAwesome;
color: #2980b9;
font-size: 3.0vw;
}
/* font size */
.reveal h1 {font-size: 5.0vw;}
.reveal h2 {font-size: 3.0vw;}
.reveal h3 {font-size: 2.8vw;}
.reveal h4 {font-size: 2.6vw;}
.reveal h5 {font-size: 1.8vw;}
.reveal h6 {font-size: 2.2vw;}
.reveal section, .reveal table, .reveal li, .reveal blockquote, .reveal th, .reveal td, .reveal p {font-size: 2.2vw;}
.reveal code {font-size: 1.6vw;}
/* new color */
.red {color: #EE6557;}
.blue {color: #16A6B6;}
/* split slide */
#right {left: -18.33%; text-align: left; float: left; width: 50%; z-index: -10;}
#left {left: 31.25%; text-align: left; float: left; width: 50%; z-index: -10;}
</style>
<style>
/* specific design */
.reveal h1 {
margin: 0% -100%;
padding: 2% 100% 4% 100%;
color: #fff;
background: #fffa5e; /* fallback for old browsers */
background: linear-gradient(-45deg, #f7f439, #54ffa4, #23A6D5, #238ed5);
background-size: 200% 200%;
animation: Gradient 60s ease infinite;
}
@keyframes Gradient {
0% {background-position: 0% 50%}
50% {background-position: 100% 50%}
100% {background-position: 0% 50%}
}
.reveal h2 {
text-align: center;
margin: -5% -50% 2% -50%;
padding: 3% 10% 1% 10%;
color: #fff;
background: #fffa5e; /* fallback for old browsers */
background: -webkit-linear-gradient(to right, #c74646, #fffa5e); /* Chrome 10-25, Safari 5.1-6 */
background: linear-gradient(to right, #c74646, #fffa5e); /* W3C, IE 10+/ Edge, Firefox 16+, Chrome 26+, Opera 12+, Safari 7+ */
}
.reveal h4 {
text-align: center;
}
</style>
# syntax-parseについて
<br>
syntax/parseライブラリは、マクロを書いて構文を処理するためのフレームワークを提供しています。このライブラリは、強力な構文パターン言語を提供しており、パターンマッチ形式の syntax-parse や、指定形式の define-syntax-class で使用されます。syntax-parseを使用するマクロは、マクロの構文パターンに埋め込まれた説明やメッセージに基づいて、エラーメッセージを自動的に生成します。
---
## Example
このセクションでは、syntax/parseを一連の作業例として紹介します。
---
1.2.1 フェーズと再利用可能な構文クラス
はじめにIntroductionで説明したように、シンタックスクラスを定義する最も簡単な方法は、そのクラスを使用するマクロ定義の中で定義することです。しかし、これでは、シンタックスクラスのスコープが1つのクライアントマクロに限定され、非常に大きなマクロ定義になってしまいます。再利用可能な構文クラスを作成するには、Racket のフェーズレベルの分離を意識する必要があります。モジュール内ですぐに定義された構文クラスは、同じモジュール内のマクロでは使用できません。
```racket
> (module phase-mismatch-mod racket
(require syntax/parse (for-syntax syntax/parse))
(define-syntax-class foo
(pattern (a b c)))
(define-syntax (macro stx)
(syntax-parse stx
[(_ f:foo) #'(+ f.a f.b f.c)])))
syntax-parse: not defined as syntax class
at: foo
in: (syntax-parse stx ((_ f:foo) (syntax (+ f.a f.b f.c))))
```
上記のモジュールでは、シンタックス クラス foo はフェーズ レベル 0 で定義されています。しかし、マクロ内の foo への参照は、マクロ変換器の実装であるため、フェーズ レベル 1 になります。(syntax/parse を通常時とfor-syntax時の2回必要とすることは、フェーズレベルの非互換性の一般的な警告サインです)。
フェーズレベルの不一致は、begin-for-syntaxブロック内にシンタックスクラスの定義を置くことで簡単に解決できます。
```racket
> (module phase-ok-mod racket
(require (for-syntax syntax/parse))
(begin-for-syntax
(define-syntax-class foo
(pattern (a b c))))
(define-syntax (macro stx)
(syntax-parse stx
[(_ f:foo) #'(+ f.a f.b f.c)])))
```
上記の修正されたモジュールでは、foo はフェーズ 1 で定義されているため、マクロの実装で使用することができます。
begin-for-syntaxの代わりに、別のモジュールでシンタックスクラスを定義し、そのモジュールをfor-syntaxとして要求する方法があります。
```
> (module stxclass-mod racket
(require syntax/parse)
(define-syntax-class foo
(pattern (a b c)))
(provide foo))
> (module macro-mod racket
(require (for-syntax syntax/parse
'stxclass-mod))
(define-syntax (macro stx)
(syntax-parse stx
[(_ f:foo) #'(+ f.a f.b f.c)]))
(provide macro))
> (require 'macro-mod)
> (macro (1 2 3))
6
```
構文クラスがリテラル識別子を参照する場合や、構文テンプレートを介して式を計算する場合、構文クラスを含むモジュールは、一般的にパターンやテンプレートで参照されるバインディングをfor-templateで要求しなければなりません。
```
> (module arith-keywords-mod racket
(define-syntax plus (syntax-rules ()))
(define-syntax times (syntax-rules ()))
(provide plus times))
> (module arith-stxclass-mod racket
(require syntax/parse
(for-template 'arith-keywords-mod
racket))
(define-syntax-class arith
#:literals (plus times)
(pattern n:nat
#:with expr #'n)
(pattern (plus a:arith b:arith)
#:with expr #'(+ a.expr b.expr))
(pattern (times a:arith b:arith)
#:with expr #'(* a.expr b.expr)))
(provide arith))
> (module arith-macro-mod racket
(require (for-syntax syntax/parse
'arith-stxclass-mod)
'arith-keywords-mod)
(define-syntax (arith-macro stx)
(syntax-parse stx
[(_ a:arith)
#'(values 'a.expr a.expr)]))
(provide arith-macro
(all-from-out 'arith-keywords-mod)))
> (require 'arith-macro-mod)
> (arith-macro (plus 1 (times 2 3)))
'(+ 1 (* 2 3))
7
```
arith-stxclass-modでは、キーワードがフェーズ0の式で使用されるため、モジュール'arith-keywords-modがfor-templateとして要求されなければなりません。同様に、モジュール racket は、構文クラスに + と * (および実際には暗黙の #%app 構文) を含む構文テンプレートが含まれているため、for-template を要求する必要があります。これらの識別子 (キーワード plus と times、手続き + と *、暗黙の構文 #%app) はすべて、「絶対」位相レベル 0 でバインドされなければなりません。モジュール 'arith-stxclass-mod' は位相レベルオフセット 1 (つまり for-syntax) で要求されるため、位相レベルオフセット -1 (for-template) で補う必要があります。
---
1.2.2