Revolucent icon

Kotlin Parser Combinators

Revolucent | PRO | 01/02/22 08:19:53 AM UTC | 0 ⭐ | 12784 👁️ | Never ⏰ | []
Kotlin |

3.02 KB

|

None

|

0 👍

/

0 👎

import kotlin.text.*
 
class ParseException: Exception("A parse exception has occurred")
 
class Context<E>(private val list: List<E>) {
    companion object {
        fun fromString(string: String): Context<Char> = Context<Char>(string.toList())
    }
    
    var index: Int = 0
    val next: E get() = list.elementAtOrNull(index) ?: throw ParseException()
    
    val atEnd: Boolean get() = index >= list.size
    
    infix fun <T> parse(parser: Parser<E, T>): T = parser(this)
}
 
typealias Parser<E, T> = Context<E>.() -> T
typealias ParserS = Context<Char>.() -> String
typealias Transform<I, O> = (I) -> O
 
infix fun <E, T1, T2> Transform<T1, T2>.lift(parser: Parser<E, T1>): Parser<E, T2> {
    val transform = this
    return { transform(parser(this)) }
}
 
fun <E> eof(): Parser<E, Unit> = { if (!this.atEnd) throw ParseException() }
 
fun <E> satisfy(test: (E) -> Boolean): Parser<E, E> = {
    val elem = next
    if (test(elem)) {
        index += 1
        elem
    } else {
      throw ParseException()
    }
}
 
fun char(test: (Char) -> Boolean): ParserS {
    val check = satisfy(test)
    return { check(this).toString() }
}
 
fun char(c: Char): ParserS = char { it == c }
 
operator fun ParserS.plus(parser2: ParserS): ParserS {
    val parser1 = this
    return {
        val s1 = parser1(this)
        val s2 = parser2(this)
        s1 + s2
    }
}
 
infix fun <E, T> Parser<E, T>.or(parser2: Parser<E, T>): Parser<E, T> {
    val parser1 = this
    return {
        try {
            parser1(this)
        } catch(e: ParseException) {
            parser2(this)
        }
    }
}
 
fun <E, T> count(from: Int, to: Int, parser: Parser<E, T>): Parser<E, List<T>> = {
    val results: MutableList<T> = mutableListOf()
    while (results.size < from) {
        results.add(parser(this))
    }
    while (results.size < to) {
        try {
            results.add(parser(this))
        } catch (e: ParseException) {
            break
        }
    }
    results
}
 
fun join(strings: List<String>): String = strings.joinToString(separator = "")
 
fun <E, T> count(range: IntRange, parser: Parser<E, T>): Parser<E, List<T>> = count(range.start, range.endInclusive, parser)
 
fun <E, T> count(to: Int, parser: Parser<E, T>): Parser<E, List<T>> = count(to, to, parser)
 
fun <E, T> atLeast(from: Int, parser: Parser<E, T>): Parser<E, List<T>> = count(from, Int.MAX_VALUE, parser)
 
fun <E, T> many1(parser: Parser<E, T>): Parser<E, List<T>> = atLeast(1, parser)
 
fun <E, T> many(parser: Parser<E, T>): Parser<E, List<T>> = atLeast(0, parser)
 
fun countS(from: Int, to: Int, parser: ParserS): ParserS = ::join lift count(from, to, parser)
 
fun manyS(parser: ParserS): ParserS = ::join lift many(parser)
 
fun many1S(parser: ParserS): ParserS = ::join lift atLeast(1, parser)
 
infix fun <E, T1, T2> Parser<E, T1>.followedBy(parser2: Parser<E, T2>): Parser<E, T1> {
    val parser1 = this
    return {
        val result = this parse parser1
        this parse parser2
        result
    }
}
 

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎