import kotlin.text.* class ParseException: Exception("A parse exception has occurred") class Context(private val list: List) { companion object { fun fromString(string: String): Context = Context(string.toList()) } var index: Int = 0 val next: E get() = list.elementAtOrNull(index) ?: throw ParseException() val atEnd: Boolean get() = index >= list.size infix fun parse(parser: Parser): T = parser(this) } typealias Parser = Context.() -> T typealias ParserS = Context.() -> String typealias Transform = (I) -> O infix fun Transform.lift(parser: Parser): Parser { val transform = this return { transform(parser(this)) } } fun eof(): Parser = { if (!this.atEnd) throw ParseException() } fun satisfy(test: (E) -> Boolean): Parser = { 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 Parser.or(parser2: Parser): Parser { val parser1 = this return { try { parser1(this) } catch(e: ParseException) { parser2(this) } } } fun count(from: Int, to: Int, parser: Parser): Parser> = { val results: MutableList = 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 = strings.joinToString(separator = "") fun count(range: IntRange, parser: Parser): Parser> = count(range.start, range.endInclusive, parser) fun count(to: Int, parser: Parser): Parser> = count(to, to, parser) fun atLeast(from: Int, parser: Parser): Parser> = count(from, Int.MAX_VALUE, parser) fun many1(parser: Parser): Parser> = atLeast(1, parser) fun many(parser: Parser): Parser> = 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 Parser.followedBy(parser2: Parser): Parser { val parser1 = this return { val result = this parse parser1 this parse parser2 result } }