Skip to content

Commit

Permalink
Improve readme
Browse files Browse the repository at this point in the history
  • Loading branch information
alllex committed Jul 28, 2023
1 parent 90eb5b9 commit b3883a8
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 18 deletions.
19 changes: 12 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,18 @@ grammar formats.

## Quick Reference

| Description | Procedural Grammar | Combinator Grammar | Parsing |
| ----------- | ------------------ | ------------------ | ------- |
| Parsing token and getting its text | <pre> val ab by regexToken("a[bB]")<br/> override val root by parser {<br/> val abMatch = ab()<br/> abMatch.text<br/> }</pre> | <pre> val ab by regexToken("a[bB]")<br/> override val root by ab map { it.text }</pre> | `ab` => (`ab`)<br/>`aB` => (`aB`) |
| Parsing two tokens sequentially | <pre> val a by literalToken("a")<br/> val b by regexToken("[bB]")<br/> override val root by parser {<br/> val aMatch = a()<br/> val bMatch = b()<br/> aMatch.text to bMatch.text<br/> }</pre> | <pre> val a by literalToken("a")<br/> val b by regexToken("[bB]")<br/> override val root by a and b map<br/> { (aM, bM) -> aM.text to bM.text }</pre> | `ab` => (`a`, `b`)<br/>`aB` => (`a`, `B`) |
| Parsing one of two tokens | <pre> val a by literalToken("a")<br/> val b by regexToken("[bB]")<br/> override val root by parser {<br/> val abMatch = choose(a, b)<br/> abMatch.text<br/> }</pre> | <pre> val a by literalToken("a")<br/> val b by regexToken("[bB]")<br/> override val root by a or b map { it.text }</pre> | `a` => (`a`)<br/>`b` => (`b`)<br/>`B` => (`B`) |
| Parsing an optional token | <pre> val a by literalToken("a")<br/> val b by regexToken("[bB]")<br/> override val root by parser {<br/> val aMatch = poll(a)<br/> val bMatch = b()<br/> aMatch?.text to bMatch.text<br/> }</pre> | <pre> val a by literalToken("a")<br/> val b by regexToken("[bB]")<br/> override val root by optional(a) and b map<br/> { (aM, bM) -> aM?.text to bM.text }</pre> | `ab` => (`a`, `b`)<br/>`aB` => (`a`, `B`)<br/>`b` => (null, `b`)<br/>`B` => (null, `B`) |
| Parsing a token and ignoring its value | <pre> val a by literalToken("a")<br/> val b by regexToken("[bB]")<br/> override val root by parser {<br/> skip(a) // or just a() without using the value<br/> val bMatch = b()<br/> bMatch.text<br/> }</pre> | <pre> val a by literalToken("a")<br/> val b by regexToken("[bB]")<br/> override val root by -a * b map { it.text }</pre> | `ab` => (`b`)<br/>`aB` => (`B`) |
This is a reference of some of the basic combinators provided by the library.

There is a combinator available in both procedural-style and combinator-style grammars.
You can pick and choose the style for each parser and sub-parser, as there are no restrictions.

| Description | Grammars |
| ----------- | -------- |
| Parsing a token and getting its text<br/><br/>Parses: `ab`, `aB` | Procedural:<br/><pre>val ab by regexToken("a[bB]")<br/>override val root by parser {<br/> val abMatch = ab()<br/> abMatch.text<br/>}</pre>Combinator:<br/><pre>val ab by regexToken("a[bB]")<br/>override val root by ab map { it.text }</pre> |
| Parsing two tokens sequentially<br/><br/>Parses: `ab`, `aB` | Procedural:<br/><pre>val a by literalToken("a")<br/>val b by regexToken("[bB]")<br/>override val root by parser {<br/> val aMatch = a()<br/> val bMatch = b()<br/> aMatch.text to bMatch.text<br/>}</pre>Combinator:<br/><pre>val a by literalToken("a")<br/>val b by regexToken("[bB]")<br/>override val root by a and b map<br/> { (aM, bM) -> aM.text to bM.text }</pre> |
| Parsing one of two tokens<br/><br/>Parses: `a`, `b`, `B` | Procedural:<br/><pre>val a by literalToken("a")<br/>val b by regexToken("[bB]")<br/>override val root by parser {<br/> val abMatch = choose(a, b)<br/> abMatch.text<br/>}</pre>Combinator:<br/><pre>val a by literalToken("a")<br/>val b by regexToken("[bB]")<br/>override val root by a or b map { it.text }</pre> |
| Parsing an optional token<br/><br/>Parses: `ab`, `aB`, `b`, `B` | Procedural:<br/><pre>val a by literalToken("a")<br/>val b by regexToken("[bB]")<br/>override val root by parser {<br/> val aMatch = poll(a)<br/> val bMatch = b()<br/> aMatch?.text to bMatch.text<br/>}</pre>Combinator:<br/><pre>val a by literalToken("a")<br/>val b by regexToken("[bB]")<br/>override val root by optional(a) and b map<br/> { (aM, bM) -> aM?.text to bM.text }</pre> |
| Parsing a token and ignoring its value<br/><br/>Parses: `ab`, `aB` | Procedural:<br/><pre>val a by literalToken("a")<br/>val b by regexToken("[bB]")<br/>override val root by parser {<br/> skip(a) // or just a() without using the value<br/> val bMatch = b()<br/> bMatch.text<br/>}</pre>Combinator:<br/><pre>val a by literalToken("a")<br/>val b by regexToken("[bB]")<br/>override val root by -a * b map { it.text }</pre> |

## Introduction

Expand Down
27 changes: 17 additions & 10 deletions buildSrc/src/main/kotlin/GenerateQuickReferenceMarkdown.kt
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,20 @@ abstract class GenerateQuickReferenceMarkdown : DefaultTask() {
private fun generateMarkdown(input: String): String {
val entries = parseSource(input)
return buildString {
appendLine("| Description | Procedural Grammar | Combinator Grammar | Parsing |")
appendLine("| ----------- | ------------------ | ------------------ | ------- |")
appendLine("| Description | Grammars |")
appendLine("| ----------- | -------- |")
for (entry in entries) {
append("| ")
append(entry.description)
append("<br/>")
append("<br/>")
append("Parses: ")
append(entry.testCases.joinToString(", ") { "`$it`" })
append(" | ")
append("Procedural:<br/>")
append(entry.proceduralGrammar.toMultilineMarkdownCodeBlock())
append(" | ")
append("Combinator:<br/>")
append(entry.combinatorGrammar.toMultilineMarkdownCodeBlock())
append(" | ")
append(entry.testCases.joinToString("<br/>"))
appendLine(" |")
}
}
Expand Down Expand Up @@ -88,17 +91,21 @@ abstract class GenerateQuickReferenceMarkdown : DefaultTask() {

val testCases = testCaseLines.asSequence()
.map { it.trim().removeSuffix(",") }
.map { it.replace("\"", "`") }
.map { it.replaceFirst(" to ", " => ") }
.map { it.replace(" to ", ", ") }
.map { it.replace("\"([^\"]+)\".*".toRegex(), "$1") }
.toList()

fun parseGrammarLines() = linesIter.collectUntil { it.startsWith(" }") }
.joinToString("\n") { it }
.trimIndent()
.lines()

// Find the procedural grammar and extract it
linesIter.skipUntil { it.trim().startsWith("val proc") } ?: break
val proceduralGrammarLines = linesIter.collectUntil { it.startsWith(" }") }
val proceduralGrammarLines = parseGrammarLines()

// Find the combinator grammar and extract it
linesIter.skipUntil { it.trim().startsWith("val comb") } ?: break
val combinatorGrammarLines = linesIter.collectUntil { it.startsWith(" }") }
val combinatorGrammarLines = parseGrammarLines()

// Add the entry
entries += QuickRefEntry(
Expand Down
2 changes: 1 addition & 1 deletion src/commonTest/kotlin/me/alllex/parsus/ReadmeTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class ReadmeTests {

@Test
fun quickRefTokenText() {
// Parsing token and getting its text
// Parsing a token and getting its text
val testCases = listOf(
"ab" to ("ab"),
"aB" to ("aB"),
Expand Down

0 comments on commit b3883a8

Please sign in to comment.