package blitz.parse.comb2 import blitz.collections.RefVec import blitz.str.charsToString import kotlin.math.absoluteValue import kotlin.math.sign fun whitespaces(): Parser = repeatedNoSave(oneOf("\n\t\r\b ".toList())) fun digit(): Parser = oneOf("0123456789".toList()) fun uintLit(): Parser> = verifyValueWithSpan(withSpan(repeated(digit()))) { if (it.size == 0) "need digits after sign in num lit" else null } fun intLit(): Parser = mapValue(then(choose(mapValue(just('+')) { +1 }, mapValue(just('-')) { -1 }, value(+1)), uintLit())) { (sign, v) -> sign * v.charsToString().toInt() } fun floatLit(): Parser = mapValue( then( thenIgnore( intLit(), just('.')), orElseVal(uintLit(), RefVec.of('0')))) { (pre, post) -> var p = post.charsToString().toDouble() while (p.absoluteValue >= 1) { p *= 0.1 } (pre.toDouble().absoluteValue + p) * pre.toDouble().sign } fun escapeChar(): Parser = thenOverwrite(just('\\'), mapErrors(choose(just('"'), just('\''), just('\\'), mapValue(just('n')) { '\n' }, mapValue(just('r')) { '\r' }, mapValue(just('b')) { '\b' }, mapValue(just('t')) { '\t' })) { RefVec.of(ParseError(it[0].loc, "invalid escape sequence")) } ) fun stringLit(): Parser = mapValue(thenIgnore(then(just('"'), repeated(choose(escapeChar(), filter("a") { it != '"' }))), just('"'))) { (_, str) -> str.charsToString() } inline fun delimitedBy(crossinline self: Parser, crossinline delim: Parser): Parser> = orElse(mapValue(then(repeated(thenIgnore(self, delim)), self)) { (a, b) -> a.pushBack(b); a }, value(RefVec.of()))