Skip to content

Commit eae5d0f

Browse files
authored
Merge pull request #1126 from lean-ja/Seasawher/issue1103
Syntax 型を紹介する
2 parents a42232e + 19d1747 commit eae5d0f

File tree

2 files changed

+119
-0
lines changed

2 files changed

+119
-0
lines changed
+118
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/- # Syntax
2+
3+
`Lean.Syntax` は、Lean の具象構文木(concrete syntax tree)を表すデータ型です。
4+
5+
具象構文木とは何かを理解するには、私たちがエディタに `#eval "Hello"` などと入力したとき、Lean がこれを実行する過程で何をしているかを考えるとわかりやすいでしょう。入力された `#eval "Hello"` は最初は単なる文字列ですが、Lean はまずこれを Lean の文法に照らして合法的なコードであるか解析します。合法ならば次のステップに進むことができますし、そうでなければ「こんなコマンドは知らない」というエラーを表示します。この解析結果を保存する中間的データが具象構文木(`Syntax`)として表現されます。
6+
7+
なお、ただの文字列を解析して構文木を得ることを構文解析またはパース(parse)と呼びます。
8+
9+
## 定義
10+
11+
`Syntax` 型は以下のように[帰納型](#{root}/Reference/Declarative/Inductive.md)として定義されています。
12+
-/
13+
import Lean --#
14+
namespace Hidden --#
15+
16+
open Lean
17+
18+
/-- 構文木 -/
19+
inductive Syntax where
20+
/-- パース時のエラー。エラーが起こったときにそれ以降のパースが
21+
すべて失敗するということを避けるために用意されている。-/
22+
| missing : Syntax
23+
24+
/-- 構文木のノード -/
25+
| node (info : SourceInfo) (kind : SyntaxNodeKind) (args : Array Syntax) : Syntax
26+
27+
/-- アトム(`atom`)は、構文木の葉の部分を構成する。
28+
`⊕` や `+` などの演算子、`(` や `)` などの括弧がこれにあたる。-/
29+
| atom (info : SourceInfo) (val : String) : Syntax
30+
31+
/-- 識別子(`ident`)は、構文木の葉の部分を構成する。たとえば以下は識別子である。
32+
* `Nat.add` などの関数名
33+
* 式 `1 + x` における変数名 `x`
34+
-/
35+
| ident (info : SourceInfo) (rawVal : Substring)
36+
(val : Name) (preresolved : List Syntax.Preresolved) : Syntax
37+
38+
--#--
39+
-- **Syntax の定義の変更を確認するためのコード**
40+
/--
41+
info: inductive Lean.Syntax : Type
42+
number of parameters: 0
43+
constructors:
44+
Lean.Syntax.missing : Lean.Syntax
45+
Lean.Syntax.node : SourceInfo → SyntaxNodeKind → Array Lean.Syntax → Lean.Syntax
46+
Lean.Syntax.atom : SourceInfo → String → Lean.Syntax
47+
Lean.Syntax.ident : SourceInfo → Substring → Name → List Syntax.Preresolved → Lean.Syntax
48+
-/
49+
#guard_msgs in #print _root_.Lean.Syntax
50+
--#--
51+
end Hidden --#
52+
53+
/- ## パースと構文木
54+
実際に、`s : String` を解析して `Syntax` の項を得ることができます。-/
55+
56+
open Lean Parser
57+
58+
/-- `s : String` をパースして `Syntax` の項を得る。`cat` は構文カテゴリ。-/
59+
def parse (cat : Name) (s : String) : MetaM Syntax := do
60+
let .ok s := runParserCategory (← getEnv) cat s | throwError s
61+
return s
62+
63+
-- `true` は識別子としてパースされている。
64+
/--
65+
info: Lean.Syntax.ident
66+
(Lean.SourceInfo.original "".toSubstring { byteIdx := 0 } "".toSubstring { byteIdx := 4 })
67+
"true".toSubstring
68+
`true
69+
[]
70+
-/
71+
#guard_msgs in
72+
#eval parse `term "true"
73+
74+
-- `0` は構文木のノードになっていて、
75+
-- 子としてアトムが一つある。
76+
/--
77+
info: Lean.Syntax.node
78+
(Lean.SourceInfo.none)
79+
`num
80+
#[Lean.Syntax.atom (Lean.SourceInfo.original "".toSubstring { byteIdx := 0 } "".toSubstring { byteIdx := 1 }) "0"]
81+
-/
82+
#guard_msgs in
83+
#eval parse `term "0"
84+
85+
/- 見ての通りすぐに複雑怪奇になってしまうので、以降は表示を簡略化しましょう。`Syntax` は [`ToString`](#{root}/Reference/TypeClass/ToString.md) のインスタンスを実装しており、これは `SourceInfo` などを含まないシンプルな表現をしてくれるので、それを利用します。-/
86+
87+
-- 文字列として表示するとかなり簡略化される
88+
/-- info: `true -/
89+
#guard_msgs in
90+
run_meta IO.println (← parse `term "true")
91+
92+
/-- info: (num "0") -/
93+
#guard_msgs in
94+
run_meta IO.println (← parse `term "0")
95+
96+
/-- info: (term!_ "!" `false) -/
97+
#guard_msgs in
98+
run_meta IO.println (← parse `term "! false")
99+
100+
-- 識別子はアトムと違って `Name` を受け取るのでバッククォートがつく
101+
/-- info: `Nat.zero -/
102+
#guard_msgs in
103+
run_meta IO.println (← parse `term "Nat.zero")
104+
105+
/- もちろん項(`term`)以外の構文カテゴリについてもパースを行うことができます。あと少しだけ例を見ましょう。 -/
106+
107+
-- コマンドをパースする例
108+
/-- info: (Command.eval "#eval" (str "\"hello\"")) -/
109+
#guard_msgs in
110+
run_meta IO.println (← parse `command "#eval \"hello\"")
111+
112+
-- タクティクをパースする例
113+
-- 木構造が現れている
114+
/--
115+
info: (Tactic.«tactic_<;>_» (Tactic.constructor "constructor") "<;>" (Tactic.intro "intro" [`h]))
116+
-/
117+
#guard_msgs in
118+
run_meta IO.println (← parse `tactic "constructor <;> intro h")

booksrc/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
- [List: 連結リスト](./Reference/Type/List.md)
106106
- [Prop: 命題全体](./Reference/Type/Prop.md)
107107
- [String: 文字列](./Reference/Type/String.md)
108+
- [Syntax: 具象構文木](./Reference/Type/Syntax.md)
108109
- [Type: 型の型](./Reference/Type/Type.md)
109110

110111
- [タクティク](./Reference/Tactic/README.md)

0 commit comments

Comments
 (0)