Skip to content

User guide⚓︎

This is only a user guide, after reading it, it's recommended that you also read KDoc.

What is PEG?⚓︎

From Wikipedia:

In computer science, a parsing expression grammar (PEG), is a type of analytic formal grammar, i.e. it describes a formal language in terms of a set of rules for recognizing strings in the language.

How to use kpeg?⚓︎

Info

kpeg is a PEG parser, not PEG parser generator.

To use it you need to follow these simple steps:

1. Define your grammar and objects⚓︎

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
object MyGrammar {

    val MySymbol: EvalSymbol<MyObj> = Symbol.rule(name = "MySymbol") { /* PE */ }

    private val A: EvalSymbol<Int> = Symbol.rule(name = "A") { /* PE */ }

    private val B: EvalSymbol<BObj> = Symbol.rule(name = "B") { /* PE */ }

    private val C: EvalSymbol<String> = Symbol.rule(name = "C") { /* PE */ }
}
1
2
3
data class MyObj(val a: Int, val b: BObj, val c: String)

data class BObj(val p: Double, val q: String)

2. Define a utility function for parsing⚓︎

1
fun parseMySymbol(text: String) = PegParser.parse(symbol = MyGrammar.MySymbol, text)

3. Use it⚓︎

1
2
3
4
5
fun main() {
    val result = parseMySymbol(text = "your text")

    println(result)
}

How to define a Symbol?⚓︎

The definition of a Symbol is a Rule. To write a rule, you need to use the Symbol.rule factory method.

It creates symbols lazily, so the order in which they are declared doesn't matter:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
object MyGrammar {

    val MarkedPersonSym = Symbol.rule(name = "MarkedPersonSym") { // `Operators` scope
        // Any available operator, e.g. a sequence:
        seq<Pair<String, Char>> { // `SequenceBuilder<Pair<String, Char>>` : `Operators` scope
            val person = +PersonSym
            val mark = +MarkSym

            value { person to mark }
        }
    }

    val PersonSym = Symbol.rule(name = "PersonSym") { // `Operators` scope
        // Any available operator, e.g. a literal:
        literal("Alice")
    }

    val MarkSym = Symbol.rule(name = "MarkSym") { // `Operators` scope
        // Any available operator, e.g. a character:
        char('A')
    }
}

Attention

Before, there was two factory methods available, Symbol.rule and Symbol.lazyRule. The first one was eager, and the second one was lazy. But after a while, it became clear that the eager one had no major advantages, so it was removed and the Symbol.lazyRule was renamed to Symbol.rule. So, currently there is only one way to create a Symbol - using the lazy Symbol.rule. Hope this makes sense 😉

Library operators and their comparison with the classic PEG syntax⚓︎

Info

The list below describes only those operators that have an analogy in the classic PEG syntax. A complete list of all available operators can be found here (KDoc).

Library operator Analogy of the classic PEG syntax Description
char(Char) ' ' Character
char(Char, Char, ...) One of the characters
char { (Char) -> Boolean } Character described by the block
char(CharRange) [ ] Character class
literal(String) " " Literal string
literal { (String) -> Boolean } Literal string described by the block
ANY . Any character
(PE) (e) Grouping
PE.optional() e? Optional
PE.zeroOrMore() e* Zero-or-more
PE.oneOrMore() e+ One-or-more
and(PE) &e And-predicate
not(PE) !e Not-predicate
seq { ... } e1 e2 ... en Sequence
choice(PE, PE, ...) e1 / e2 / ... / en Prioritized choice

Please share your ideas⚓︎

The lib is currently not promises backward-compatability, so feel free to pull request.

Need help?⚓︎

For more in-depth documentation, see the KDoc.

If you have any questions left, please, feel free to ask them here.