/tmp/duangsuse.sock
23 subscribers
303 photos
3 videos
92 files
337 links
从 duangsuse::Echo (@dsuse) 跟进出来的分支,将在作者恢复原帐号访问的时候合并删除。
Download Telegram
>>> 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
}
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)
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)
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()
}
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
}
/tmp/duangsuse.sock
Parser.kt 现在有最大的问题就是 Input,不支持我之前说的镇静解析策略的 ErrorHandler,反而去兼容了 MarkReset —— 其实 MarkReset 完全不应该首要兼容的,它只会解决一些非常不容易出现的问题,还影响性能 Input 和 Feed 的层次也容易让人糊涂,Input 的魔法一点都不好玩,只是让人开心那么一会而已,很快实践时就会造成大问题,过度设计。 最重要的是 object: Pat 和 val name = Pat() 这种区别不应该再支持了,再支持势必要出大问题…
rt 此外是 SOR 模式不规范,不容易让人记住,我给起了个简化名 "SURD",Seq, Until, Repeat, Decide
然后对 atom patterns 进行规范,只有 deferred, satisfy, item, elem
扩展 pattern 有 TriePattern, InfixPattern, SurroundBy, JoinBy

InfixPattern 对 join operator 的抽象也有很严重的问题,之前是 enum class 都容易声明的,现在变成什么 from/to 啥鬼样子,不男不女的还造成了很严重的相等性判断问题,简直不是人写的

open class Deferred<T, R>(private val pat: Producer<Pattern<T, R>>): Pattern<T, R>
abstract class SatisfyTest<T>: Pattern<T, T> {
abstract fun test(item: T): Boolean
}
open class Satisfy<T>(val predicate: Predicate<T>): SatisfyTest<T>()

class AnyItem<T>: Satisfy<T>({ true })
open class Item<T>(val x: T): SatisfyTest<T>()

open class Element<T>(vararg val xs: T): AbstractSatisfy<T>() {
override fun test(item: T) = item in xs
override fun toString() = "(${xs.joinToString("|", transform = ::showRawString)})"
}
open class RangeElement(val xs: CharRange): AbstractSatisfy<Char>() {
override fun test(item: Char) = item in xs
override fun toString() = "$xs"
}

open class Seq<IN, T, TUP: Tuple<T>>(val allocator: Producer<TUP>, vararg val items: Pattern<IN, T>): Pattern<IN, TUP> {
override fun toString() = items.joinToString(" ").surround("(", ")")
}
abstract class Repeat<IN, T, R>(val fold: Fold<T, R>, val item: Pattern<IN, T>): Pattern<IN, R> {
open val countBound: Predicate<Cnt> = {true}
override fun toString() = "{$item}"
}
abstract class Decide<T, R>(vararg val cases: Pattern<T, R>): Pattern<T, R> {
override fun toString() = cases.joinToString("|").surround("(", ")")
}

open class Convert<T, R, R1>(val item: Pattern<T, R>, val from: (R) -> R1, val to: (R1) -> R): Pattern<T, R1>
override fun toString() = item.toString()
}

open class SurroundBy<T, R>(val lr: Pair<T, T>, val item: Pattern<T, R>): Pattern<T, R>

class TriePattern<K, V>: Trie<K, V>(), Pattern<K, V>

abstract class InfixPattern<IN, ATOM>(val atom: Pattern<IN, ATOM>, val op: Pattern<IN, Join<ATOM>>): Pattern<IN, ATOM> {
abstract fun onError(base: ATOM, op1: Join<ATOM>): Nothing
}
deferred(pat)
SatisyTest
satisfy
anyItem, item(value)
element(vararg xs)
range(CharRange)

Seq(data, items)
Until(fold, item)
Repeat(fold, item)
Decide(cases)

Convert(item, from, to)
Contextual(head, body)

SurroundBy(lr, item)
JoinBy(seprator, item)

TriePattern()
InfixPattern(atom, op)
satisfy(predicate)

anyItem item(value)

elementIn(vararg xs)
elementIn(CharRange)

Seq(data, items)
Until(fold, item, terminate)
Repeat(fold, item) { open val countBound: Preciate<Cnt> }
Decide(cases)

SatisfyTest { abstract fun test(value: IN): Boolean }
SurroundBy(lr, item)
JoinBy(seprator, item)

Deferred(item)
Convert(item, from, to)
Contextual(head, body)

TriePattern()
InfixPattern(seprator, item)
/tmp/duangsuse.sock
satisfy(predicate) anyItem item(value) elementIn(vararg xs) elementIn(CharRange) Seq(data, items) Until(fold, item, terminate) Repeat(fold, item) { open val countBound: Preciate<Cnt> } Decide(cases) SatisfyTest { abstract fun test(value: IN): Boolean }…
SURD — Seq, Until, Repeat, Decide
IES — Item, ElementIn, Satisfy

合起来重写的版本不叫 Parser.kt 了,叫 Surdies 吧(迫真)

Seq(data, items)
Until(fold, terminate, item)
Repeat(fold, item) { open val countBound: Preciate<Cnt> }
Decide(cases)

item() item(value)
elementIn(vararg xs) elementIn(CharRange)
satisfy(predicate)

Deferred(item)
JoinBy(seprator, item)
SurroundBy(surround, item)

Convert(item, from, to)
Contextual(head, body)

TriePattern()
InfixPattern(seprator, item)

SatisfyTest 还要加一个逆命题 not() operator。
这样我们就可以 Until(ignore(), !elementIn(whiteSpaces), char)

Pattern<IN, T> 要有 toDefault(defaultValue: T): PositivePattern<IN, T>

需要用到的辅助模型:
Seq — Tuple
Repeat — Fold
TriePattern — Trie, Iterable.toMap, reverseMap, EnumMap
InfixPattern — InfixOp

typealias Producer<T> = () -> T
typealias Consumer<T> = (T) -> Unit
typealias Predicate<T> = (T) -> Boolean

Tuple 要 get/set, Index, toArray, equals, ext:toList
Tuple2

typealias AsList<T> = EffectFold<T, MutableList<T>, List<T>>
typealias BuildStr = ConvertFold<Char, StringBuilder, String>
class JoinFold<T>(initial: T, private val append: T.(T) -> T): Fold<T, T>

输入模型:
interface Feed<out T> {
val peek: T; fun consume(): T
class End: NoSuchElementException("no more")
}
interface Input<T>: Feed<T>, ErrorHandler<T>

abstract class SliceFeed
abstract class StreamFeed

open class CharInput: Input<Char>, SourceLocated
class CharInputCRLF

辅助:
fun <IN> Feed<IN>.consumeIf(predicate: Predicate<IN>): IN
fun <IN> Feed<IN>.takeWhile(predicate: Predicate<IN>): Sequence<IN>
fun <IN> Feed<IN>.take(n: Cnt): Sequence<IN>

fun impossible(): Nothing = error("impossible")
fun <T> MutableList<T>.removeLast() = removeAt(lastIndex)
分成 Extensions Slice Tuple Fold Input SURD IES MiscPattern TriePattern 这些部分实现?
class SliceFeed<T>(private val slice: Slice<T>): Feed<T> {
private var position = 0
private var tailConsumed = false
override val peek get() = slice[position] // v check for getPeek() v
override fun consume() = try { val got = peek; slice[++position]; got }
catch (_: IndexOutOfBoundsException) {
--position
if (!tailConsumed) peek.also { tailConsumed = true }
else throw Feed.End()
}
override fun toString() = "Slice(${peek}...${slice})"
}

不好看,只是可以加一个 noexcept,弃了弃了。 #Kotlin #code