
Operator-driven parser combinator DSL for compact PEG-style grammars, parsing raw input without tokenization, featuring built-in memoization, typed tuple results, named errors and associativity helpers.
Lightweight PEG-style parser combinators for Kotlin Multiplatform
Xarpeg (/ˈʃɑrpɛɡ/) is a compact, operator-driven parser combinator library for Kotlin. It targets JVM, JS (Node.js), and Native platforms (Linux x64, Linux ARM64, Windows x64), works directly on raw input strings without tokenization, and includes built-in memoization for predictable backtracking performance.
+ for literals/regex/choice, * for sequences, - to ignore tokensTuple0..Tuple16 so you explicitly control what's kept or droppedHere's a complete arithmetic expression parser in just a few lines:
import io.github.mirrgieriana.xarpeg.*
import io.github.mirrgieriana.xarpeg.parsers.*
val expr: Parser<Int> = object {
val number = +Regex("[0-9]+") map { it.value.toInt() } named "number"
val brackets: Parser<Int> = -'(' * ref { root } * -')'
val factor = number + brackets
val mul = leftAssociative(factor, -'*') { a, _, b -> a * b }
val add = leftAssociative(mul, -'+') { a, _, b -> a + b }
val root = add
}.root
fun main() {
check(expr.parseAll("2*(3+4)").getOrThrow() == 14) // ✓ Evaluates to 14
}Key concepts:
+'x' / +"xyz" / +Regex("...") create parsers from literals or patterns* sequences parsers, returning typed tuples-parser matches but ignores the result (useful for delimiters)+ (binary) tries alternatives in ordernamed improves error messagesref { } enables recursive grammarsleftAssociative handles operator precedence without manual recursionBest practices:
+'x' for single characters, not +"x"
+"xyz" for fixed strings, not +Regex("xyz")
named with Regex parsers for better error messages💡 New to parser combinators? Start with our step-by-step tutorial!
Follow our comprehensive tutorial to master parser combinators:
ref { }
mapEx
→ Start the Tutorial: [English] [日本語]
Interactive browser-based parser that demonstrates:
| Operation | Syntax | Description |
|---|---|---|
| Literals |
+'x', +"xyz", +Regex("...")
|
Create parsers from characters, strings, or regex |
| Sequence | parserA * parserB |
Match parsers in order, return typed tuple |
| Choice | parserA + parserB |
Try alternatives; first match wins |
| Ignore | -parser |
Match but drop result from tuple |
| Repetition |
.zeroOrMore, .oneOrMore, .list(min, max)
|
Collect matches into List<T>
|
| Serial | serial(p1, p2, ...) |
Parse multiple different parsers, return List<T> (no tuple limit) |
| Optional | .optional |
Try to match; rewind on failure |
| Transform | .map { ... } |
Convert parsed value to another type |
| Position | .mapEx { ctx, result -> ... } |
Access context and position info |
| Position | .result |
Get full ParseResult<T> with value and positions |
| Lookahead | !parser |
Succeed if parser fails (zero width) |
| Naming | parser named "name" |
Assign name for error messages |
| Hidden | parser.hidden |
Mark parser to exclude from error suggestions |
| Recursion | ref { parser } |
Forward reference for recursive grammars |
| Associativity |
leftAssociative(...), rightAssociative(...)
|
Build operator chains |
| Boundaries |
startOfInput, endOfInput
|
Match at position boundaries |
parseAll(input).getOrThrow() - Parse entire input or throw exceptionparseOrNull(context, start) - Attempt parse at position; return ParseResult<T>?
ParseException - Thrown when parsing fails (either because no parser matched at the current position or because trailing input remains after successful parse)context with errorPosition and suggestedParsers for detailed error reportinguseMemoization = true); disable with useMemoization = false for lower memory usageXarpite - The original project from which Xarpeg was extracted. Demonstrates:
Try the samples locally to see Xarpeg in action:
Minimal JVM Sample:
cd samples/minimal-jvm-sample && ./gradlew runOnline Parser Sample:
cd samples/online-parser && ./gradlew build
# Open samples/online-parser/build/site/index.html in your browserArithmetic Interpreter:
cd samples/interpreter && ./gradlew run --args='-e "2*(3+4)"'Add Xarpeg to your project using Gradle. Replace <latest-version> with the version from Releases.
repositories {
mavenCentral()
}
dependencies {
implementation("io.github.mirrgieriana:xarpeg:<latest-version>")
}The xarpeg artifact uses Gradle module metadata to automatically resolve to the correct platform-specific variant (JVM, JS, Native, etc.) based on your project configuration.
Note: The API may evolve as we refine the DSL. Pin a specific version for production use.
⚠️ Documentation Notice: The natural language descriptions throughout this documentation (including this README) were predominantly generated by AI and may contain inaccuracies. When in doubt, please verify against the actual source code and test the behavior directly.
MIT License - See LICENSE for details.
Logo uses Monaspace
Lightweight PEG-style parser combinators for Kotlin Multiplatform
Xarpeg (/ˈʃɑrpɛɡ/) is a compact, operator-driven parser combinator library for Kotlin. It targets JVM, JS (Node.js), and Native platforms (Linux x64, Linux ARM64, Windows x64), works directly on raw input strings without tokenization, and includes built-in memoization for predictable backtracking performance.
+ for literals/regex/choice, * for sequences, - to ignore tokensTuple0..Tuple16 so you explicitly control what's kept or droppedHere's a complete arithmetic expression parser in just a few lines:
import io.github.mirrgieriana.xarpeg.*
import io.github.mirrgieriana.xarpeg.parsers.*
val expr: Parser<Int> = object {
val number = +Regex("[0-9]+") map { it.value.toInt() } named "number"
val brackets: Parser<Int> = -'(' * ref { root } * -')'
val factor = number + brackets
val mul = leftAssociative(factor, -'*') { a, _, b -> a * b }
val add = leftAssociative(mul, -'+') { a, _, b -> a + b }
val root = add
}.root
fun main() {
check(expr.parseAll("2*(3+4)").getOrThrow() == 14) // ✓ Evaluates to 14
}Key concepts:
+'x' / +"xyz" / +Regex("...") create parsers from literals or patterns* sequences parsers, returning typed tuples-parser matches but ignores the result (useful for delimiters)+ (binary) tries alternatives in ordernamed improves error messagesref { } enables recursive grammarsleftAssociative handles operator precedence without manual recursionBest practices:
+'x' for single characters, not +"x"
+"xyz" for fixed strings, not +Regex("xyz")
named with Regex parsers for better error messages💡 New to parser combinators? Start with our step-by-step tutorial!
Follow our comprehensive tutorial to master parser combinators:
ref { }
mapEx
→ Start the Tutorial: [English] [日本語]
Interactive browser-based parser that demonstrates:
| Operation | Syntax | Description |
|---|---|---|
| Literals |
+'x', +"xyz", +Regex("...")
|
Create parsers from characters, strings, or regex |
| Sequence | parserA * parserB |
Match parsers in order, return typed tuple |
| Choice | parserA + parserB |
Try alternatives; first match wins |
| Ignore | -parser |
Match but drop result from tuple |
| Repetition |
.zeroOrMore, .oneOrMore, .list(min, max)
|
Collect matches into List<T>
|
| Serial | serial(p1, p2, ...) |
Parse multiple different parsers, return List<T> (no tuple limit) |
| Optional | .optional |
Try to match; rewind on failure |
| Transform | .map { ... } |
Convert parsed value to another type |
| Position | .mapEx { ctx, result -> ... } |
Access context and position info |
| Position | .result |
Get full ParseResult<T> with value and positions |
| Lookahead | !parser |
Succeed if parser fails (zero width) |
| Naming | parser named "name" |
Assign name for error messages |
| Hidden | parser.hidden |
Mark parser to exclude from error suggestions |
| Recursion | ref { parser } |
Forward reference for recursive grammars |
| Associativity |
leftAssociative(...), rightAssociative(...)
|
Build operator chains |
| Boundaries |
startOfInput, endOfInput
|
Match at position boundaries |
parseAll(input).getOrThrow() - Parse entire input or throw exceptionparseOrNull(context, start) - Attempt parse at position; return ParseResult<T>?
ParseException - Thrown when parsing fails (either because no parser matched at the current position or because trailing input remains after successful parse)context with errorPosition and suggestedParsers for detailed error reportinguseMemoization = true); disable with useMemoization = false for lower memory usageXarpite - The original project from which Xarpeg was extracted. Demonstrates:
Try the samples locally to see Xarpeg in action:
Minimal JVM Sample:
cd samples/minimal-jvm-sample && ./gradlew runOnline Parser Sample:
cd samples/online-parser && ./gradlew build
# Open samples/online-parser/build/site/index.html in your browserArithmetic Interpreter:
cd samples/interpreter && ./gradlew run --args='-e "2*(3+4)"'Add Xarpeg to your project using Gradle. Replace <latest-version> with the version from Releases.
repositories {
mavenCentral()
}
dependencies {
implementation("io.github.mirrgieriana:xarpeg:<latest-version>")
}The xarpeg artifact uses Gradle module metadata to automatically resolve to the correct platform-specific variant (JVM, JS, Native, etc.) based on your project configuration.
Note: The API may evolve as we refine the DSL. Pin a specific version for production use.
⚠️ Documentation Notice: The natural language descriptions throughout this documentation (including this README) were predominantly generated by AI and may contain inaccuracies. When in doubt, please verify against the actual source code and test the behavior directly.
MIT License - See LICENSE for details.
Logo uses Monaspace