Advertisement
Revolucent

Kotlin Parser Combinators

Jan 2nd, 2022
1,773
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Kotlin 3.02 KB | None | 0 0
  1. import kotlin.text.*
  2.  
  3. class ParseException: Exception("A parse exception has occurred")
  4.  
  5. class Context<E>(private val list: List<E>) {
  6.     companion object {
  7.         fun fromString(string: String): Context<Char> = Context<Char>(string.toList())
  8.     }
  9.    
  10.     var index: Int = 0
  11.     val next: E get() = list.elementAtOrNull(index) ?: throw ParseException()
  12.    
  13.     val atEnd: Boolean get() = index >= list.size
  14.    
  15.     infix fun <T> parse(parser: Parser<E, T>): T = parser(this)
  16. }
  17.  
  18. typealias Parser<E, T> = Context<E>.() -> T
  19. typealias ParserS = Context<Char>.() -> String
  20. typealias Transform<I, O> = (I) -> O
  21.  
  22. infix fun <E, T1, T2> Transform<T1, T2>.lift(parser: Parser<E, T1>): Parser<E, T2> {
  23.     val transform = this
  24.     return { transform(parser(this)) }
  25. }
  26.  
  27. fun <E> eof(): Parser<E, Unit> = { if (!this.atEnd) throw ParseException() }
  28.  
  29. fun <E> satisfy(test: (E) -> Boolean): Parser<E, E> = {
  30.     val elem = next
  31.     if (test(elem)) {
  32.         index += 1
  33.         elem
  34.     } else {
  35.       throw ParseException()
  36.     }
  37. }
  38.  
  39. fun char(test: (Char) -> Boolean): ParserS {
  40.     val check = satisfy(test)
  41.     return { check(this).toString() }
  42. }
  43.  
  44. fun char(c: Char): ParserS = char { it == c }
  45.  
  46. operator fun ParserS.plus(parser2: ParserS): ParserS {
  47.     val parser1 = this
  48.     return {
  49.         val s1 = parser1(this)
  50.         val s2 = parser2(this)
  51.         s1 + s2
  52.     }
  53. }
  54.  
  55. infix fun <E, T> Parser<E, T>.or(parser2: Parser<E, T>): Parser<E, T> {
  56.     val parser1 = this
  57.     return {
  58.         try {
  59.             parser1(this)
  60.         } catch(e: ParseException) {
  61.             parser2(this)
  62.         }
  63.     }
  64. }
  65.  
  66. fun <E, T> count(from: Int, to: Int, parser: Parser<E, T>): Parser<E, List<T>> = {
  67.     val results: MutableList<T> = mutableListOf()
  68.     while (results.size < from) {
  69.         results.add(parser(this))
  70.     }
  71.     while (results.size < to) {
  72.         try {
  73.             results.add(parser(this))
  74.         } catch (e: ParseException) {
  75.             break
  76.         }
  77.     }
  78.     results
  79. }
  80.  
  81. fun join(strings: List<String>): String = strings.joinToString(separator = "")
  82.  
  83. fun <E, T> count(range: IntRange, parser: Parser<E, T>): Parser<E, List<T>> = count(range.start, range.endInclusive, parser)
  84.  
  85. fun <E, T> count(to: Int, parser: Parser<E, T>): Parser<E, List<T>> = count(to, to, parser)
  86.  
  87. fun <E, T> atLeast(from: Int, parser: Parser<E, T>): Parser<E, List<T>> = count(from, Int.MAX_VALUE, parser)
  88.  
  89. fun <E, T> many1(parser: Parser<E, T>): Parser<E, List<T>> = atLeast(1, parser)
  90.  
  91. fun <E, T> many(parser: Parser<E, T>): Parser<E, List<T>> = atLeast(0, parser)
  92.  
  93. fun countS(from: Int, to: Int, parser: ParserS): ParserS = ::join lift count(from, to, parser)
  94.  
  95. fun manyS(parser: ParserS): ParserS = ::join lift many(parser)
  96.  
  97. fun many1S(parser: ParserS): ParserS = ::join lift atLeast(1, parser)
  98.  
  99. infix fun <E, T1, T2> Parser<E, T1>.followedBy(parser2: Parser<E, T2>): Parser<E, T1> {
  100.     val parser1 = this
  101.     return {
  102.         val result = this parse parser1
  103.         this parse parser2
  104.         result
  105.     }
  106. }
  107.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement