Repeat 现在需要 override fun show(write: Consumer<T>, item: R?)
因为 Fold 只能完成 from,并不能完成 to。
至于现在的 Tuple+read/show 和之前的 Fold+then/contextual 孰优孰劣,还没有定数
但现在规范化了解析失败的时候有
其实 Seq, Or, Repeat 也完全可以在 read 的时候 try catch 一下,给异常添加更多信息传下去,不过我觉得镇静模式就很好。
因为 Fold 只能完成 from,并不能完成 to。
至于现在的 Tuple+read/show 和之前的 Fold+then/contextual 孰优孰劣,还没有定数
但现在规范化了解析失败的时候有
clamUntil,还是比较好的其实 Seq, Or, Repeat 也完全可以在 read 的时候 try catch 一下,给异常添加更多信息传下去,不过我觉得镇静模式就很好。
Literate Kotlin 可以教小白了解自己的实现,但写起来很冗长,emmm……
回看那篇
回看那篇
Share
看完这段 Kotlin 代码后我哭了
🐕 duangsuse’s shared files(e.g. productive software projects, documents)
/tmp/duangsuse.sock
Calc.kt
提问!如何编写一个十进制解析器?
我们先来看看上一个版本怎么做:
不知道,好像不得不引入 contextual 解析器…… 其实也不一定需要…… 但是最好要有……
我们先来看看上一个版本怎么做:
class DecimalRead(mzero: Int): Monoid<Int>(mzero, { i -> this*10 + i })
object HexRead: Monoid<Int>(0, { i -> this*16 + i })
private val oneNine = element('1'..'9') then { it-'0' }
private val zero = item('0') const 0
private val digit = or(oneNine, zero)
private fun digitsCtx(zero: Int, optional: Boolean): CParser<Int>
= repeat(DecimalRead(zero), digit, if (optional) MAYBE else SOME)
val digits = digitsCtx(0, optional = false)
val digitsNoLeadingZero: CParser<Int> = or(digit.single(), oneNine contextual { digitsCtx(it, optional = true) })
private val hexDigit: CParser<Int> = or(digit, element('A'..'F') then { it-'A'+10 }, element('a'..'f') then { it-'a'+10 })
那么, 如何不允许前置 '0'?不知道,好像不得不引入 contextual 解析器…… 其实也不一定需要…… 但是最好要有……
class DecimalRead(zero: Int): Monoid<Int>(zero, { this*10 + it })
object Digit: Convert<Char, Char, Int>(RangeElement('0'..'9'), {it-'0'}, {'0'+it})
object Decimal: Repeat<Char, Int, Int>(DecimalRead(0), Digit) {
override fun show(write: Consumer<Char>, item: Int?) { item?.toString()?.forEach(write) }
}>>> val s=CharInput("",InputStreamFeed(System.`in`))
>>> s.takeWhile { it in '0'..'9' || it == '\n' }.toList()
12313
432
res17: kotlin.collections.List<kotlin.Char> = [
, 1, 2, 3, 1, 3,
, 4, 3, 2,
]
修好了 InputStreamFeedParser.kt
17.7 KB
class DecimalRead(zero: Int): Monoid<Int>(zero, { this*10 + it })
object Digit: Convert<Char, Char, Int>(RangeElement('0'..'9'), {it-'0'}, {'0'+it})
object Decimal: Repeat<Char, Int, Int>(DecimalRead(0), Digit) {
override fun show(write: Consumer<Char>, item: Int?) { item?.toString()?.forEach(write) }
}
总之就是可以用,但怎么用呢…… 明天再看 #Kotlin #codekotlinc Parser.kt
kotlinc -cp . Calc.kt
kotlinc -cp .
>>> Kalc.read(CharInput("",SliceFeed(slice("12* 31")) )) 结果又找出 TrieParser 里面一个 bug,那么好一个 pattern。
/tmp/duangsuse.sock
Calc.kt
这次算是告一段落了,我最讨厌完全依赖编译器的检查的那种感觉,每次都战战兢兢的害怕不通过。
Parser.kt 现在有最大的问题就是 Input,不支持我之前说的镇静解析策略的 ErrorHandler,反而去兼容了 MarkReset —— 其实 MarkReset 完全不应该首要兼容的,它只会解决一些非常不容易出现的问题,还影响性能
Input 和 Feed 的层次也容易让人糊涂,Input 的魔法一点都不好玩,只是让人开心那么一会而已,很快实践时就会造成大问题,过度设计。
最重要的是 object: Pat 和 val name = Pat() 这种区别不应该再支持了,再支持势必要出大问题
此外是 SOR 模式不规范,不容易让人记住,我给起了个简化名 "SURD",Seq, Until, Repeat, Decide
然后对 atom patterns 进行规范,只有 deferred, satisfy, item, elem
扩展 pattern 有 TriePattern, InfixPattern, SurroundBy, JoinBy
InfixPattern 对 join operator 的抽象也有很严重的问题,之前是 enum class 都容易声明的,现在变成什么 from/to 啥鬼样子,不男不女的还造成了很严重的相等性判断问题,简直不是人写的
Input 和 Feed 的层次也容易让人糊涂,Input 的魔法一点都不好玩,只是让人开心那么一会而已,很快实践时就会造成大问题,过度设计。
最重要的是 object: Pat 和 val name = Pat() 这种区别不应该再支持了,再支持势必要出大问题
此外是 SOR 模式不规范,不容易让人记住,我给起了个简化名 "SURD",Seq, Until, Repeat, Decide
然后对 atom patterns 进行规范,只有 deferred, satisfy, item, elem
扩展 pattern 有 TriePattern, InfixPattern, SurroundBy, JoinBy
InfixPattern 对 join operator 的抽象也有很严重的问题,之前是 enum class 都容易声明的,现在变成什么 from/to 啥鬼样子,不男不女的还造成了很严重的相等性判断问题,简直不是人写的
/tmp/duangsuse.sock
看完这样的屑B代码,我整个灵魂都升华了,原来个计算器都可以这么麻烦,服气。
interface Feed<out T> {
val peek: T; fun consume(): T
class End: Exception("no more")
}
interface ErrorHandler<IN> {
fun handleError(input: Input<IN>)
}
interface Input<IN>: Feed<IN>, ErrorHandler<IN>
interface SourceLocated {
val sourceLoc: SourceLocation
}
data class SourceLocation(val file: String, var line: Cnt, var column: Cnt, var position: Cnt) {
constructor(file: String): this(file, 1, 1, 0)
val tag get() = "$file:$line:$column"
override fun toString() = "$tag #$position"
}
interface CharInput: Input<Char>, SourceLocated
abstract class StreamFeed<T, STREAM>(private val stream: STREAM): Feed<T> {
protected abstract fun toIterator(stream: STREAM): Iterator<T>
protected var nextOne: T
override fun toString() = "Stream(${nextOne.rawString()}...${stream})"
}
class IteratorFeed<T>(private val iterator: Iterator<T>): StreamFeed<T, Iterator<T>>()
open class InputStreamFeed(private val reader: InputStreamReader): StreamFeed<Char, InputStramReader>() {
constructor(stream_in: InputStream, charset: Charset = StandardCharsets.UTF_8): this(InputStreamReader(stream_in, charset))
open val endTransaction = '\u0004'
}
//Side B
interface Sized {
val size: Cnt
}
val Sized.lastIndex get() = size.dec()
val Sized.indices get() = 0..lastIndex
val Sized.isEmpty get() = size == 0
val Sized.isNotEmpty get() = !isEmpty
interface Slice<out T>: Sized {
operator fun get(index: Idx): T
}
abstract class AnyBy(val obj: Any) {
override fun equals(other: Any?) =
if (other !is AnyBy) obj == other
else obj == other.obj
override fun hashCode() = obj.hashCode()
override fun toString() = obj.toString()
}
fun <T> slice(ary: Array<T>): Slice<T> = object: Slice<T>, AnyBy(ary) {
override val size get() = ary.size
override fun get(index: Idx) = ary[index]
}
fun <T> slice(list: List<T>): Slice<T> = object: Slice<T>, AnyBy(list) {
override val size get() = list.size
override fun get(index: Idx) = list[index]
}
fun slice(str: CharSequence): Slice<Char> = object: Slice<Char>, AnyBy(str) {
override val size get() = str.length
override fun get(index: Idx) = str[index]
}
class SliceFeed<T>(private val slice: Slice<T>): Feed<T>, StackMarkReset<Idx>() {
override var saved = 0
override val peek get() = try { slice[saved] }
catch (_: IndexOutOfBoundsException) { throw Feed.End() }
override fun consume() = try { slice[saved++] }
catch (_: IndexOutOfBoundsException) { throw Feed.End() }
override fun toString() = "$showPeek@$saved...$slice"
private val showPeek get() = runCatching{peek}.getOrNull()?.rawString() ?: "?>${slice.lastIndex}"
}fun <T> showRawString(value: T) = value.rawString()
fun <T> T.rawString() = toString().prefixTranslate(KOTLIN_ESCAPE, "\\").let {
if (it.length == 1) it.surround("'", "'")
else it.surround("\"", "\"")
}
val KOTLIN_ESCAPE = mapOf( // \"\'\t\b\n\r\$\\
'"' to '"', '\'' to '\'',
'\t' to 't', '\b' to 'b',
'\n' to 'n', '\r' to 'r',
'$' to '$', '\\' to '\\'
)
fun String.surround(prefix: String, suffix: String): String = prefix+this+suffix
fun String.prefixTranslate(map: Map<Char, Char>, prefix: String): String = fold (StringBuilder()) { sb, c ->
map[c]?.let { sb.append(prefix).append(it) } ?: sb.append(c) }.toString()
fun impossible(): Nothing = error("impossible")
fun <T> MutableList<T>.removeLast() = removeAt(lastIndex)
fun <T, R> Iterable<T>.mapToSet(transform: (T) -> R) = mapTo(mutableSetOf(), transform)
fun <K, V> Map<K, V>.reversedMap(): Map<V, K> = entries.kvMap { kv -> kv.value to kv.key }
fun <A, B> Iterable<A>.toMap(transform: (A) -> Pair<A, B>): Map<A, B> {
val map: MutableMap<A, B> = mutableMapOf()
for (item in this) {
val (k, v) = transform(item)
map[k] = v
}
return map
}
fun <K, V, K1, V1> Iterable<Map.Entry<K, V>>.kvMap(transform: (Map.Entry<K, V>) -> Pair<K1, V1>): Map<K1, V1> {
val map: MutableMap<K1, V1> = mutableMapOf()
for (kv in this) {
val (k1, v1) = transform(kv)
map[k1] = v1
}
return map
}
fun <T> T.rawString() = toString().prefixTranslate(KOTLIN_ESCAPE, "\\").let {
if (it.length == 1) it.surround("'", "'")
else it.surround("\"", "\"")
}
val KOTLIN_ESCAPE = mapOf( // \"\'\t\b\n\r\$\\
'"' to '"', '\'' to '\'',
'\t' to 't', '\b' to 'b',
'\n' to 'n', '\r' to 'r',
'$' to '$', '\\' to '\\'
)
fun String.surround(prefix: String, suffix: String): String = prefix+this+suffix
fun String.prefixTranslate(map: Map<Char, Char>, prefix: String): String = fold (StringBuilder()) { sb, c ->
map[c]?.let { sb.append(prefix).append(it) } ?: sb.append(c) }.toString()
fun impossible(): Nothing = error("impossible")
fun <T> MutableList<T>.removeLast() = removeAt(lastIndex)
fun <T, R> Iterable<T>.mapToSet(transform: (T) -> R) = mapTo(mutableSetOf(), transform)
fun <K, V> Map<K, V>.reversedMap(): Map<V, K> = entries.kvMap { kv -> kv.value to kv.key }
fun <A, B> Iterable<A>.toMap(transform: (A) -> Pair<A, B>): Map<A, B> {
val map: MutableMap<A, B> = mutableMapOf()
for (item in this) {
val (k, v) = transform(item)
map[k] = v
}
return map
}
fun <K, V, K1, V1> Iterable<Map.Entry<K, V>>.kvMap(transform: (Map.Entry<K, V>) -> Pair<K1, V1>): Map<K1, V1> {
val map: MutableMap<K1, V1> = mutableMapOf()
for (kv in this) {
val (k1, v1) = transform(kv)
map[k1] = v1
}
return map
}
fun <T> Feed<T>.consumeIf(predicate: Predicate<T>): T? =
peek.takeIf(predicate)?.let { runCatching(::consume).getOrNull() }
fun <T> Feed<T>.takeWhile(predicate: Predicate<T>): Sequence<T> = sequence {
while (true) {
val item = consumeIf(predicate)
yield(item ?: break)
}
}
fun <T> Feed<T>.take(n: Cnt): Sequence<T> {
var count = 0; return takeWhile { count++ != n }
}
open class CharInput(feed: Feed<Char>, file: String, protected val eol: Char): Input<Char>(feed), SourceLocated
open class CharInputCRLF(feed: Feed<Char>, file: String, eol: Char): CharInput(feed, file, eol)
peek.takeIf(predicate)?.let { runCatching(::consume).getOrNull() }
fun <T> Feed<T>.takeWhile(predicate: Predicate<T>): Sequence<T> = sequence {
while (true) {
val item = consumeIf(predicate)
yield(item ?: break)
}
}
fun <T> Feed<T>.take(n: Cnt): Sequence<T> {
var count = 0; return takeWhile { count++ != n }
}
open class CharInput(feed: Feed<Char>, file: String, protected val eol: Char): Input<Char>(feed), SourceLocated
open class CharInputCRLF(feed: Feed<Char>, file: String, eol: Char): CharInput(feed, file, eol)
abstract class Tuple<E>(override val size: Cnt): Sized {
protected abstract val items: Array<E>
operator fun get(index: Idx) = items[index]
operator fun set(index: Idx, value: E) { items[index] = value }
fun toArray(): Array<E> = items
protected class Index<T>(private val idx: Idx) {
operator fun getValue(self: Tuple<out T>, _p: KProperty<*>): T = self[idx]
operator fun setValue(self: Tuple<in T>, _p: KProperty<*>, value: T) { self[idx] = value }
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
return if (other !is Tuple<*>) false
else (size == other.size) && items.contentEquals(other.items)
}
override fun hashCode(): Int = items.contentHashCode()
override fun toString(): String = "(${items.joinToString(", ")})"
}
data class Tuple2<A, B>(var first: A, var second: B)
protected abstract val items: Array<E>
operator fun get(index: Idx) = items[index]
operator fun set(index: Idx, value: E) { items[index] = value }
fun toArray(): Array<E> = items
protected class Index<T>(private val idx: Idx) {
operator fun getValue(self: Tuple<out T>, _p: KProperty<*>): T = self[idx]
operator fun setValue(self: Tuple<in T>, _p: KProperty<*>, value: T) { self[idx] = value }
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
return if (other !is Tuple<*>) false
else (size == other.size) && items.contentEquals(other.items)
}
override fun hashCode(): Int = items.contentHashCode()
override fun toString(): String = "(${items.joinToString(", ")})"
}
data class Tuple2<A, B>(var first: A, var second: B)
typealias Producer<T> = () -> T
typealias Consumer<T> = (T) -> Unit
typealias Predicate<T> = (T) -> Boolean
typealias Fold<T, R> = FoldOp<T, *, R>
interface Reducer<in T, out R> {
fun accept(item: T)
fun finish(): R
}
abstract class FoldOp<in A, B, out C> {
protected abstract val initial: B
protected abstract fun join(base: B, item: A): B
protected abstract fun convert(base: B): C
fun reducer() = object: Reducer<A, C> {
private var base: B = initial
override fun accept(item: A) { base = join(base, item) }
override fun finish(): C = convert(base)
}
}
////////
abstract class Effect<A, B, C>: FoldOp<A, B, C>() {
protected abstract fun accept(base: B, item: A)
final override fun join(base: B, item: A): B = base.also { accept(base, item) }
}
abstract class Monoid<T>(mzero: T, private val mplus: T.(T) -> T): FoldOp<T, T, T>() {
override val initial: T = mzero
final override fun join(base: T, item: T): T = base.mplus(item)
final override fun convert(base: T): T = base
}
typealias AsList<T> = Effect<T, MutableList<T>, List<T>>
fun <T> asList() = object: AsList<T>() {
override val initial: MutableList<T> get() = mutableListOf()
override fun accept(base: MutableList<T>, item: T) { base.add(item) }
override fun convert(base: MutableList<T>): List<T> = base
}
fun buildStr() = object: FoldOp<Char, StringBuilder, String>() {
override val initial get() = StringBuilder()
override fun join(base: StringBuilder, item: Char) = base.append(item)
override fun convert(base: StringBuilder) = base.toString()
}
typealias Consumer<T> = (T) -> Unit
typealias Predicate<T> = (T) -> Boolean
typealias Fold<T, R> = FoldOp<T, *, R>
interface Reducer<in T, out R> {
fun accept(item: T)
fun finish(): R
}
abstract class FoldOp<in A, B, out C> {
protected abstract val initial: B
protected abstract fun join(base: B, item: A): B
protected abstract fun convert(base: B): C
fun reducer() = object: Reducer<A, C> {
private var base: B = initial
override fun accept(item: A) { base = join(base, item) }
override fun finish(): C = convert(base)
}
}
////////
abstract class Effect<A, B, C>: FoldOp<A, B, C>() {
protected abstract fun accept(base: B, item: A)
final override fun join(base: B, item: A): B = base.also { accept(base, item) }
}
abstract class Monoid<T>(mzero: T, private val mplus: T.(T) -> T): FoldOp<T, T, T>() {
override val initial: T = mzero
final override fun join(base: T, item: T): T = base.mplus(item)
final override fun convert(base: T): T = base
}
typealias AsList<T> = Effect<T, MutableList<T>, List<T>>
fun <T> asList() = object: AsList<T>() {
override val initial: MutableList<T> get() = mutableListOf()
override fun accept(base: MutableList<T>, item: T) { base.add(item) }
override fun convert(base: MutableList<T>): List<T> = base
}
fun buildStr() = object: FoldOp<Char, StringBuilder, String>() {
override val initial get() = StringBuilder()
override fun join(base: StringBuilder, item: Char) = base.append(item)
override fun convert(base: StringBuilder) = base.toString()
}
interface Pattern<T, R> {
fun read(s: Input<T>): R?
fun show(write: Consumer<T>, item: R?)
}
interface PositivePattern<T, R>: Pattern<T, R> {
override fun read(s: Input<T>): R
}
inline val notParsed: Nothing? get() = null
fun <T, R> Pattern<T, R>.toDefault(defaultValue: R) = object: PositivePattern<T, R> {
override fun read(s: Input<T>): R = this@toDefault.read(s) ?: defaultValue
override fun show(write: Consumer<T>, item: R?) { this@toDefault.show(write, item!!) }
}
fun <T, R> Pattern<T, R>.tryRead(s: Input<T>): R? {
fun read(): R? = try { this.read(s) }
catch (_: Feed.End) { notParsed }
val parsed: R?
s.mark(); parsed = read()
s.run { if (parsed == notParsed) reset() else unmark() }
return parsed
}