increase parser perf by a lot

This commit is contained in:
alex_s168
2024-09-21 10:27:34 +00:00
parent 8c2325bdd3
commit f18798bb5c
7 changed files with 315 additions and 188 deletions

View File

@@ -1,37 +1,38 @@
package blitz.parse
import blitz.collections.RefVec
import blitz.parse.comb2.*
import org.json.JSONObject
import kotlin.math.min
import kotlin.system.measureNanoTime
object JSON {
val jsonBool: Parser<Char, Element> = choose {
it(mapValue(seq("true".toList())) { Element.newBool(true) })
it(mapValue(seq("false".toList())) { Element.newBool(false) })
}
val jsonNull: Parser<Char, Element> =
mapValue(seq("null".toList())) { Element.newNull() }
val jsonNum: Parser<Char, Element> =
mapValue(floatLit, Element::newNum)
val jsonString: Parser<Char, Element> =
mapValue(stringLit, Element::newStr)
val jsonElement = futureRec { jsonElement: Parser<Char, Element> ->
val jsonNum: Parser<Char, Element> =
mapValue(floatLit(), ::Number)
val jsonString: Parser<Char, Element> =
mapValue(stringLit(), ::Str)
val jsonArray: Parser<Char, Element> =
thenIgnore(
thenIgnore(
thenOverwrite(just('['),
mapValue(delimitedBy(jsonElement, just(',')))
{ Array(it.toList())}),
whitespaces()),
mapValue(delimitedBy(jsonElement, just(',')), Element::newArr)),
whitespaces),
just(']')
)
val jsonBool: Parser<Char, Element> = choose(
mapValue(seq("true".toList())) { Bool(true) },
mapValue(seq("false".toList())) { Bool(false) },
)
val jsonNull: Parser<Char, Element> =
mapValue(seq("null".toList())) { Nul() }
val jsonObj: Parser<Char, Element> =
mapValue(thenIgnore(thenIgnore(thenOverwrite(
just('{'),
@@ -40,74 +41,99 @@ object JSON {
thenIgnore(
thenIgnore(
thenOverwrite(
whitespaces(),
stringLit()),
whitespaces()),
whitespaces,
stringLit),
whitespaces),
just(':')),
jsonElement),
just(','))),
whitespaces()),
just('}'))) { Obj(it.toMap()) }
whitespaces),
just('}'))) { Element.newObj(it.toMap()) }
thenIgnore(thenOverwrite(
whitespaces(),
choose(
jsonArray,
jsonNum,
jsonString,
jsonObj,
jsonBool,
jsonNull
)),
whitespaces())
whitespaces,
choose {
it(jsonArray)
it(jsonNum)
it(jsonString)
it(jsonObj)
it(jsonBool)
it(jsonNull)
}),
whitespaces)
}
interface Element {
val arr get() = (this as Array).value
val num get() = (this as Number).value
val str get() = (this as Str).value
val obj get() = (this as Obj).value
val bool get() = (this as Bool).value
class Element(
@JvmField val kind: Int,
@JvmField val _boxed: Any? = null,
@JvmField val _num: Double = 0.0,
@JvmField val _bool: Boolean = false,
) {
companion object {
const val NUM = 0
const val BOOL = 1
const val NULL = 2
const val ARR = 3
const val STR = 4
const val OBJ = 5
fun isArr() = this is Array
fun isNum() = this is Number
fun isStr() = this is Str
fun isObj() = this is Obj
fun isBool() = this is Bool
fun isNul() = this is Nul
inline fun newNum(v: Double): Element =
Element(NUM, _num = v)
inline fun newBool(v: Boolean): Element =
Element(BOOL, _bool = v)
inline fun newNull(): Element =
Element(NULL)
inline fun newArr(v: RefVec<Element>): Element =
Element(ARR, _boxed = v)
inline fun newStr(v: String): Element =
Element(STR, _boxed = v)
inline fun newObj(v: Map<String, Element>): Element =
Element(OBJ, _boxed = v)
}
}
inline fun Element.uncheckedAsNum(): Double =
_num
inline fun Element.uncheckedAsBool(): Boolean =
_bool
inline fun Element.uncheckedAsArr(): RefVec<Element> =
_boxed as RefVec<Element>
inline fun Element.uncheckedAsStr(): String =
_boxed as String
inline fun Element.uncheckedAsObj(): Map<String, Element> =
_boxed as Map<String, Element>
inline fun Element.asNum(): Double {
require(kind == Element.NUM) { "Element is not a Number" }
return _num
}
data class Array(val value: List<Element>): Element {
override fun toString(): String =
value.joinToString(separator = ", ", prefix = "[", postfix = "]")
inline fun Element.asBool(): Boolean {
require(kind == Element.BOOL) { "Element is not a Boolean" }
return _bool
}
data class Number(val value: Double): Element {
override fun toString(): String =
value.toString()
inline fun Element.asArr(): RefVec<Element> {
require(kind == Element.ARR) { "Element is not an Array" }
return _boxed as RefVec<Element>
}
data class Str(val value: String): Element {
override fun toString(): String =
"\"$value\""
inline fun Element.asStr(): String {
require(kind == Element.STR) { "Element is not a String" }
return _boxed as String
}
data class Obj(val value: Map<String, Element>): Element {
override fun toString(): String =
value.map { (k, v) -> "\"$k\": $v" }.joinToString(separator = ", ", prefix = "{", postfix = "}")
inline fun Element.asObj(): Map<String, Element> {
require(kind == Element.OBJ) { "Element is not an Object" }
return _boxed as Map<String, Element>
}
data class Bool(val value: Boolean): Element {
override fun toString(): String =
value.toString()
fun parse(string: String): ParseResult<Element> {
val ctx = ParseCtx(string.toList(), 0)
val v = jsonElement(ctx)
return v
}
class Nul: Element
fun parse(string: String): ParseResult<Element> =
jsonElement(ParseCtx(string.toList(), 0))
}
fun main() {