/tmp/duangsuse.sock
23 subscribers
303 photos
3 videos
92 files
337 links
从 duangsuse::Echo (@dsuse) 跟进出来的分支,将在作者恢复原帐号访问的时候合并删除。
Download Telegram
Calc.kt
15.4 KB
#Kotlin #code 简化了一下字典树
其实对缩进布局的解析根本不需要抛 exception,子布局返回的数据里放终止嵌套层次就可以做到级联收尾了。
忍不住想起之前的 NumEqualize.kt
不知道现在的 seq, or, repeat 相对于之前函数+then contextual 的版本是简单了还是复杂了
Repeat 现在需要 override fun show(write: Consumer<T>, item: R?)
因为 Fold 只能完成 from,并不能完成 to。

至于现在的 Tuple+read/show 和之前的 Fold+then/contextual 孰优孰劣,还没有定数
但现在规范化了解析失败的时候有 clamUntil,还是比较好的

其实 Seq, Or, Repeat 也完全可以在 read 的时候 try catch 一下,给异常添加更多信息传下去,不过我觉得镇静模式就很好。
有了关键的 TriePattern 和 InfixPattern,加上 LayoutPattern 就可以实现 Python 解析器了(跑)
Literate Kotlin 可以教小白了解自己的实现,但写起来很冗长,emmm……
回看那篇
为了输入数据结构兼容性,每次要弄什么 Input("", SliceFeeder(slice("emmm")))
/tmp/duangsuse.sock
Calc.kt
提问!如何编写一个十进制解析器?

我们先来看看上一个版本怎么做:
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,
]

修好了 InputStreamFeed
Parser.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 #code
#Kotlin #code #bug 我实在受不了了,现在这个 Parser.kt 必须再次重写!
kotlinc 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 啥鬼样子,不男不女的还造成了很严重的相等性判断问题,简直不是人写的
/tmp/duangsuse.sock
Calc.kt
看完这样的屑B代码,我整个灵魂都升华了,原来个计算器都可以这么麻烦,服气。
/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
}