improver parser perf

This commit is contained in:
alex_s168
2024-09-19 21:55:17 +00:00
parent 39f34ee77b
commit 8c2325bdd3
15 changed files with 606 additions and 455 deletions

View File

@@ -1,67 +1,63 @@
package blitz.parse.comb2
import blitz.collections.RefVec
import blitz.str.charsToString
import kotlin.math.absoluteValue
import kotlin.math.sign
fun whitespaces(): Parser<Char, String> =
oneOf("\n\t\r\b ".toList())
.repeated()
.mapValue { it.charsToString() }
fun whitespaces(): Parser<Char, Unit> =
repeatedNoSave(oneOf("\n\t\r\b ".toList()))
fun digit(): Parser<Char, Char> =
oneOf("0123456789".toList())
fun uintLit(): Parser<Char, UInt> =
withSpan(digit().repeated())
.verifyValueWithSpan { if (it.isEmpty()) "need digits after sign in num lit" else null }
.mapValue { it.charsToString().toUInt() }
fun uintLit(): Parser<Char, RefVec<Char>> =
verifyValueWithSpan(withSpan(repeated(digit())))
{ if (it.size == 0) "need digits after sign in num lit" else null }
fun intLit(): Parser<Char, Int> =
choose(just('+').mapValue { +1 },
just('-').mapValue { -1 },
value(+1))
.then(uintLit())
.mapValue { (sign, v) -> sign * v.toInt() }
mapValue(then(choose(mapValue(just('+')) { +1 },
mapValue(just('-')) { -1 },
value(+1)),
uintLit()))
{ (sign, v) -> sign * v.charsToString().toInt() }
fun floatLit(): Parser<Char, Double> =
intLit()
.then(just('.')
.then(uintLit())
.mapValue { it.second }
.orElseVal(0u))
.mapValue { (pre, post) ->
var p = post.toDouble()
while (p.absoluteValue >= 1) {
p *= 0.1
}
(pre.toDouble().absoluteValue + p) * pre.toDouble().sign
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<Char, Char> =
just('\\').then(
choose(just('"'),
thenOverwrite(just('\\'),
mapErrors(choose(just('"'),
just('\''),
just('\\'),
just('n').mapValue { '\n' },
just('r').mapValue { '\r' },
just('b').mapValue { '\b' },
just('t').mapValue { '\t' })
.mapErrors { listOf(ParseError(it.first().loc, "invalid escape sequence")) }
).mapValue { it.second }
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<Char, String> =
just('"')
.then(choose(escapeChar(),
filter("a") { it != '"' })
.repeated())
.thenIgnore(just('"'))
.mapValue { (_, str) -> str.charsToString() }
mapValue(thenIgnore(then(just('"'),
repeated(choose(escapeChar(),
filter("a") { it != '"' }))),
just('"')))
{ (_, str) -> str.charsToString() }
fun <I, O, T> Parser<I, O>.delimitedBy(delim: Parser<I, T>): Parser<I, List<O>> =
thenIgnore(delim)
.repeated()
.then(this)
.mapValue { (a, b) -> a + b }
.orElse(value(listOf()))
inline fun <I, O: Any, T: Any> delimitedBy(crossinline self: Parser<I, O>, crossinline delim: Parser<I, T>): Parser<I, RefVec<O>> =
orElse(mapValue(then(repeated(thenIgnore(self, delim)), self))
{ (a, b) -> a.pushBack(b); a },
value(RefVec.of()))