ステップ1:クイックスタート

数分で最初のパーサを構築します。このガイドでは、コアDSLの概念を示す最小限の例を説明します。

最初のパーサ

count=42のようなパターンにマッチするシンプルなキーバリューパーサを構築してみましょう:

import io.github.mirrgieriana.xarpeg.*
import io.github.mirrgieriana.xarpeg.parsers.*

val identifier = +Regex("[a-zA-Z][a-zA-Z0-9_]*") map { it.value } named "identifier"
val number = +Regex("[0-9]+") map { it.value.toInt() } named "number"
val kv: Parser<Pair<String, Int>> =
    identifier * -'=' * number map { (key, value) -> key to value }

fun main() {
    val result = kv.parseAll("count=42").getOrThrow()
    check(result == ("count" to 42))  // 結果が(count, 42)であることを確認
}

コードの理解

単項+演算子は、リテラルや正規表現パターンをパーサに変換します:

*演算子は、パーサを順番に連結します(例:identifier * -'=' * number)。結果は型付きタプルにパッケージされます。

単項-演算子は、パーサにマッチしますが、その値を結果のタプルから除外します(例:-'='=文字をドロップします)。

map関数は、解析された値を変換します:

named関数は、より良いエラーメッセージのためにパーサに名前を割り当てます(例:named "identifier")。

パーサの実行

parseAll(...).getOrThrow()は、入力全体が消費されることを要求します:

import io.github.mirrgieriana.xarpeg.*
import io.github.mirrgieriana.xarpeg.parsers.*

val identifier = +Regex("[a-zA-Z][a-zA-Z0-9_]*") map { it.value } named "identifier"
val number = +Regex("[0-9]+") map { it.value.toInt() } named "number"
val kv: Parser<Pair<String, Int>> =
    identifier * -'=' * number map { (key, value) -> key to value }

fun main() {
    // 成功ケース
    check(kv.parseAll("count=42").getOrThrow() == ("count" to 42))  // ✓
    check(kv.parseAll("x=100").getOrThrow() == ("x" to 100))        // ✓

    // エラーケースは例外をスローします:
    // kv.parseAll("=42").getOrThrow()        // ✗ ParseException
    // kv.parseAll("count").getOrThrow()      // ✗ ParseException
    // kv.parseAll("count=42x").getOrThrow()  // ✗ ParseException
}

例外の種類:

重要なポイント

ベストプラクティス

パーサの型を選択する際は、最適なパフォーマンスと明確性のために以下のガイドラインに従ってください:

単一文字にはCharトークンを使用:

固定文字列にはStringトークンを使用:

パターンにはnamedを付けたRegexトークンを使用:

まとめ:

次のステップ

基本を理解したので、より洗練された方法でパーサを組み合わせる方法を学びましょう。

ステップ2:コンビネータ