💨
Swift Parsing を使うときにKuuがつまづいたところ
Swift Parsing を使うときにKuuがつまづいたところ
Swift-Parsing (と XCTest) で「トークナイザ」を作ろうとした時につまづいたり、これははまると思ったなってトコをまとめます。
つまづいたこと & 実際の対策
Ambiguous use of 'init(_:)
といわれる
○1. .map(String.init) // ← これだと不明義
原因
-
String.init
はSubstring
,Character
など複数の型に対応していて、どの型を使いたいのか Swift が判断できずエラーになる。 - 特に
Prefix(...)
のような文字列系パーサと組み合わせた時に起きやすい。
対策
- クロージャで型を明示することで、意図をコンパイラに伝える。
.map { (sub: Substring) -> String in String(sub) }
-
.map(String.init)
が使えるのは、型が完全に明確な時だけ。
Cannot convert value of type '(A, B) -> Token' to expected argument type 'Token'
○2. Parse(Token.variable) { ... } // ← よくやりたくなるやつ
原因
-
Parse(Token.variable)
は(A, B) -> Token
のような unlabeled な関数しか受け取れない。 -
Token.variable(type: DataType, name: String)
のようにラベル付きだと、それが合わずにエラーになる。
対策
-
map
を使って明示的に組み立てるのが安全。
Parse {
dataTypeParser
identifier
}.map { type, name in
Token.variable(type: type, name: name)
}
- または
case variable(DataType, String)
のようにラベルなしにして、Parse(Token.variable)
を使えるようにする。
Attempt
が見つからない
○3. 原因
- swift-parsing のバージョンによって、バックトラック用のパーサの名前が違う。
- 0.9.x:
BacktrackingParser
- 0.10〜0.11:
Attempt
- 0.12以降:
Backtrack
対策
- バージョンに合わせて正しいものを使う。
Backtrack { ... } // for 0.12+
-
Attempt {}
がないと言われたらBacktrack {}
に切り替える。 - SwiftPM の指定を最新版 (
from: "0.12.0"
) にすることで解消できることも多い。
Inheritance from non-protocol type 'Parser'
○4. 原因
-
Parser
はParsing
モジュールの中にあるプロトコル。 -
Foundation
や標準ライブラリには存在しない。
対策
import Parsing
struct MyParser: Parsing.Parser { ... }
-
Parsing.Parser
のようにモジュール名つきで明示してあげるとエラーが消える。
static let
にしているのに Cannot use instance member
えられる
○5. 変数は 原因
-
static let
の初期化時点では instance が存在しないため、self.identifier
のようなインスタンスプロパティを参照できない。
対策
-
全部
static
に統一する。 - もしくは
identifier
をファイルスコープ定数にして、どこからでも参照できるようにする。 - インスタンスメンバが必要なら
var parser: ... { ... }
のように計算プロパティとして定義する。
体系化すると...
- 「パーサの構成は全部 static let にして、.erasetoAnyParser() する」
- 「OneOf の順序は気を付ける (特定なものは先に)」
- 「Parse().map の形は .map { x, y in Token(x, y) } にする」
- 「Backtrack が必要な場所は明示的に書く」
- 「型推論に期待せず、必要なら型注釈で補助する」
結論。
SwiftParsingは真面目に使えばむしろ保守性ある文法で、実践的にも使える。けどコンパイラの次元解析に依存してる部分が大きいので、一歩づつコンパイラが何を言ってるかに対応できる感覚は必要です。
ある種の「Swiftの型システム」と「ResultBuilderの癖」を両方読める力が問われる感あります。
Discussion