Kotlin 说的对,要“改良”我的确是还没那个经历、没那个资格呢
还是 Kotlin 厉害,我很服,先以适配 Kotlin 为主要目标,看着办吧。
异常的确是个好问题,如果以 coroutine 的思路思考问题我的确是在说笑了,所以主动减负是个明智的选择,先做点边缘工作看看行不行吧。
还是 Kotlin 厉害,我很服,先以适配 Kotlin 为主要目标,看着办吧。
异常的确是个好问题,如果以 coroutine 的思路思考问题我的确是在说笑了,所以主动减负是个明智的选择,先做点边缘工作看看行不行吧。
我们的 ParserKt 也能用了,解决 literal int/string 读写的问题不是大问题、中缀表达式也不成问题
可是单单就语法前端层面来看,大的结构也是没有实践过,还是没经验、没自信,毕竟咱的框架是 from scratch,靠的都是咱比较片面的老经验。但新的东西到底是要有的,路,走的人多了不也就能用了么?
咱的解析器框架是少有的,完全依靠 Kotlin 标准库的基本抽象数据构造的库,没有什么栈啊状态机的,完全泛型化、可组织化,包含对 error handling 和 rebuild——或许还是头一次呢!——的解决方案
整个框架 700 行,还提供了 Tuple 和 Fold 这两个复用性相当高的抽象,每个文件都有专门的注释纲领,是相当概括和克制的。
ParserKt 提供了相当概括的接口——Tuple/Fold,Pattern 是可 read 可 show,都是基于 Feed/Input 流的
常用的是 SURDIES—Seq/Until/Repeat/Decide 、item/elementIn/satisfy
现在想让它先继续试着去实践一下那个 JSON 解析器,再来解决 MiniScheme 的问题,但是这个 MiniScheme 的语法和语义得先规范定义一点……
可是单单就语法前端层面来看,大的结构也是没有实践过,还是没经验、没自信,毕竟咱的框架是 from scratch,靠的都是咱比较片面的老经验。但新的东西到底是要有的,路,走的人多了不也就能用了么?
咱的解析器框架是少有的,完全依靠 Kotlin 标准库的基本抽象数据构造的库,没有什么栈啊状态机的,完全泛型化、可组织化,包含对 error handling 和 rebuild——或许还是头一次呢!——的解决方案
整个框架 700 行,还提供了 Tuple 和 Fold 这两个复用性相当高的抽象,每个文件都有专门的注释纲领,是相当概括和克制的。
ParserKt 提供了相当概括的接口——Tuple/Fold,Pattern 是可 read 可 show,都是基于 Feed/Input 流的
常用的是 SURDIES—Seq/Until/Repeat/Decide 、item/elementIn/satisfy
现在想让它先继续试着去实践一下那个 JSON 解析器,再来解决 MiniScheme 的问题,但是这个 MiniScheme 的语法和语义得先规范定义一点……
/tmp/duangsuse.sock
#math #Java #Kotiln #gui
这张是原来的设计。
就先这么规定,字面数据类型 bool, int, long, float, double, char, string, (null)
我们的数组和“对象”,没有专门的文本表达
数字呢,首先拒绝
浮点还是 Kotlin 那种
字符串得支持
名字,暂时就是 [_A-Za-z] {[_A-Za-z0-9]},若只有 _ 构成则不可用
空格" \t\f"、换行"\n\r"、可嵌套注释“”
好,那么先解决这些的读取问题, 再来谈更高层的结构读取。
就先这么规定,字面数据类型 bool, int, long, float, double, char, string, (null)
我们的数组和“对象”,没有专门的文本表达
数字呢,首先拒绝
0(digit) 这种表示法,其次是要支持 0x, 0b浮点还是 Kotlin 那种
int.fraction 模式,但是暂不支持 exponents字符串得支持
\"\'\t\b\n\r\$\\ 和 \uXXXX 以及 inline string名字,暂时就是 [_A-Za-z] {[_A-Za-z0-9]},若只有 _ 构成则不可用
空格" \t\f"、换行"\n\r"、可嵌套注释“”
好,那么先解决这些的读取问题, 再来谈更高层的结构读取。
/tmp/duangsuse.sock
这张是原来的设计。 就先这么规定,字面数据类型 bool, int, long, float, double, char, string, (null) 我们的数组和“对象”,没有专门的文本表达 数字呢,首先拒绝 0(digit) 这种表示法,其次是要支持 0x, 0b 浮点还是 Kotlin 那种 int.fraction 模式,但是暂不支持 exponents 字符串得支持 \"\'\t\b\n\r\$\\ 和 \uXXXX 以及 inline string 名字,暂时就是 [_A-Za-z] {[_A…
我来发表下看法哈。
这个 0x 0b 的数值,以及对 01 这种的检查,是昨天解决了的
至于 true 和 null 这些关键字怎么解决呢,它们是和 apples, list 这类的名字一起出现的
可以用字典树,我们为了解析这个专门弄了 TrieReplace<V>,可以实现 true 和 Name 的。
至于关键字和空格呢,有
其实我们的 MiniScheme 的语言表达式设计是很克制的,连函数调用和结构定义的空格都用 () [] 区分开了,所以不存在 keyword 和动态生成值的问题,大胆干吧
至于递归解析拿不到引用的问题,不是有 Deferred 么
这个 0x 0b 的数值,以及对 01 这种的检查,是昨天解决了的
// 0x / 0b / 123
val zeroNotation = Decide(
hexPart prefix item('x'),
binPart prefix item('b'),
Peek(!digit) { if (peek == '0') takeIfStickyEnd(-1) else 0 }.clamWhile(digit, 0, "no octal notations")
) 至于 true 和 null 这些关键字怎么解决呢,它们是和 apples, list 这类的名字一起出现的
可以用字典树,我们为了解析这个专门弄了 TrieReplace<V>,可以实现 true 和 Name 的。
至于关键字和空格呢,有
ws 定义的先例嘛,关键字也可以用 KeywordPattern其实我们的 MiniScheme 的语言表达式设计是很克制的,连函数调用和结构定义的空格都用 () [] 区分开了,所以不存在 keyword 和动态生成值的问题,大胆干吧
至于递归解析拿不到引用的问题,不是有 Deferred 么
ParserKt 唯一的好处可能就是代码复用了,PKT 的代码复用真是相当优秀,而且没有性能问题
比其它递归下降组合子又多了 rebuild 和 clam 和 tuple 什么的
比其它递归下降组合子又多了 rebuild 和 clam 和 tuple 什么的
fun digitsIn(range: CharRange, padding: Int = 0)
= Convert(elementIn(range), { it-range.first+padding }, { range.first+(it - padding) })
val binDigit = digitsIn('0'..'1')
val decDigit = digitsIn('0'..'9')
val hexDigitLo = digitsIn('a'..'f', padding = 10)
val hexDigitUp = digitsIn('A'..'F', padding = 10)
val hexDigit = DecideUn(decDigit, hexDigitUp, hexDigitLo) { if (it in 0..9) 0 else 1 }
fun asLong(radix: Int, initial: Long = 0L) = JoinFold(initial) { this*radix + it }
fun integralFor(digit: Pattern<Char, Int>, repr: IRepr): Pattern<Char, Integral>
= Convert(Repeat(asLong(repr.radix), Convert(digit, Int::toLong))) { Integral(it, repr) }
val binPart = integralFor(binDigit, IRepr.Bin)
val decPart = integralFor(decDigit, IRepr.Dec)
val hexPart = integralFor(hexDigit, IRepr.Hex)又失败了,但是获得了一点经验和进步……
ParserKt 的 rebuild,即便现在有特别的兼容单向 read-only patterns,真的对设计来说有很大的影响啊
因为就创作者我来说,设计的时候会自觉地实现 unfold, undecide,即便那是没有意义的,一旦失败会对心情有很大的影响
ParserKt 的 rebuild,即便现在有特别的兼容单向 read-only patterns,真的对设计来说有很大的影响啊
因为就创作者我来说,设计的时候会自觉地实现 unfold, undecide,即便那是没有意义的,一旦失败会对心情有很大的影响
Forwarded from Deleted Account
sealed class Sexp { data class Term(val name: String): Sexp(); data class Nest(val list: List<Sexp>): Sexp() }
lateinit var sexp: Pattern<Char, Sexp>
val str = Until(elementIn(' ', *parens.items()), asString(), anyChar)
val atom = Convert(str) { Sexp.Term(it) }
val nestItems = SurroundBy(parens.asPat(), JoinBy(item(' '), Deferred{sexp}).ignoreSecond())
val nest = Convert(nestItems) { Sexp.Nest(it) }
sexp = Decide(nest, atom)Forwarded from Deleted Account
就这一点代码我居然写了半个小时还面向 REPL 编程,还发现了框架 toString 的一个 bug……
('('{('('{(recursive)...' '}')'|(anyItem)~(' '|'('|')'))...' '}')'|(anyItem)~(' '|'('|')'))
Deleted Account
sealed class Sexp { data class Term(val name: String): Sexp(); data class Nest(val list: List<Sexp>): Sexp() } lateinit var sexp: Pattern<Char, Sexp> val str = Until(elementIn(' ', *parens.items()), asString(), anyChar) val atom = Convert(str) { Sexp.Term(it)…
今天晚上,我还会完成文法布局的 Pattern 编写
可以认为,ParserKt 现在对 read-only pattern 和序列 validate 的支持已经比较完备了
对于文法布局的支持应该会像对 infix chain 的一样,不会有问题
可以认为,ParserKt 现在对 read-only pattern 和序列 validate 的支持已经比较完备了
对于文法布局的支持应该会像对 infix chain 的一样,不会有问题
/tmp/duangsuse.sock
今天晚上,我还会完成文法布局的 Pattern 编写 可以认为,ParserKt 现在对 read-only pattern 和序列 validate 的支持已经比较完备了 对于文法布局的支持应该会像对 infix chain 的一样,不会有问题
不是特别顺利,对级联收尾的理解有偏差
之前的知识是,不能用异常。但现在我也看了 Pattern<IN, Tuple2<List<T>, Int>>,那个方案不可行
ParserKt 是 one-pass 的解析器,绝对没有 MarkReset 的机会,所以对布局解析器来说,
h1
h2
h3
h3
h1
这里面最后一个 h1 的位置,实际上调用栈最顶端的最后一个 h3 负责读取它,但如果读取消耗了,解析来的 h2 就又不知道往哪里关了。
(如果支持 mark/reset 的话,只要预取 indent 判等后决定是否消耗即可,其他情况都是输入序列错误)
所以说每次要收尾所有 > indent 的层次,然后才能实现这个解析器。
这一点也不说特别难,但 ParserKt 里不是很好解决,因为我们的设计是
而且它不仅仅要做到级联,还不能暴露出框架的流结构的这个 one-pass……
我希望不要把它做成一个 abstract class,简单一点,不能让它管理这个递归的 nesting tree 数据结构,要不然至少对用户会很麻烦。
现在好像是只能用异常了,因为它就是一个 Pattern,可以被任何其他 pattern 使用…… 要做到级联收尾必须这么做,而且这么做我们就可以用上 FoldPattern 的 API,更规范一些
如何 show 这又是另外一个问题,不过我现在的意见是,无法支持,因为布局的输出,只能存那么一点信息(没法多存布局的信息进去,顶多可能被扩展嵌套结构,但就不是我们的事了),的确没法弄好,Pattern 的使用是动态的。
之前的知识是,不能用异常。但现在我也看了 Pattern<IN, Tuple2<List<T>, Int>>,那个方案不可行
ParserKt 是 one-pass 的解析器,绝对没有 MarkReset 的机会,所以对布局解析器来说,
h1
h2
h3
h3
h1
这里面最后一个 h1 的位置,实际上调用栈最顶端的最后一个 h3 负责读取它,但如果读取消耗了,解析来的 h2 就又不知道往哪里关了。
(如果支持 mark/reset 的话,只要预取 indent 判等后决定是否消耗即可,其他情况都是输入序列错误)
所以说每次要收尾所有 > indent 的层次,然后才能实现这个解析器。
这一点也不说特别难,但 ParserKt 里不是很好解决,因为我们的设计是
function where 像这个这个 where 是我们放这个 pattern 的地方而且它不仅仅要做到级联,还不能暴露出框架的流结构的这个 one-pass……
我希望不要把它做成一个 abstract class,简单一点,不能让它管理这个递归的 nesting tree 数据结构,要不然至少对用户会很麻烦。
现在好像是只能用异常了,因为它就是一个 Pattern,可以被任何其他 pattern 使用…… 要做到级联收尾必须这么做,而且这么做我们就可以用上 FoldPattern 的 API,更规范一些
如何 show 这又是另外一个问题,不过我现在的意见是,无法支持,因为布局的输出,只能存那么一点信息(没法多存布局的信息进去,顶多可能被扩展嵌套结构,但就不是我们的事了),的确没法弄好,Pattern 的使用是动态的。
/tmp/duangsuse.sock
不是特别顺利,对级联收尾的理解有偏差 之前的知识是,不能用异常。但现在我也看了 Pattern<IN, Tuple2<List<T>, Int>>,那个方案不可行 ParserKt 是 one-pass 的解析器,绝对没有 MarkReset 的机会,所以对布局解析器来说, h1 h2 h3 h3 h1 这里面最后一个 h1 的位置,实际上调用栈最顶端的最后一个 h3 负责读取它,但如果读取消耗了,解析来的 h2 就又不知道往哪里关了。 (如果支持 mark/reset 的话,只要预取…
大意就是,除了异常以外没有办法在两层
除非使用 abstract class 硬性建模何时开启新 pattern,否则这个信息没法通过返回值传递出去,即便能手写起来复杂性也不可接受。
LayoutPattern 注定是递归结构,所以 caller 必须去 handle 它的 closing indent level 返回值,对应用来说那必须手写模板代码,我觉得比起那样还是异常靠谱一些(虽然不可能有泛型,要强制转换了……)
这个和 infix pattern 不一样,它毕竟得是一个 unstable feature……
LayoutPattern.read 之间传递控制权,因为使用处是不确定的除非使用 abstract class 硬性建模何时开启新 pattern,否则这个信息没法通过返回值传递出去,即便能手写起来复杂性也不可接受。
LayoutPattern 注定是递归结构,所以 caller 必须去 handle 它的 closing indent level 返回值,对应用来说那必须手写模板代码,我觉得比起那样还是异常靠谱一些(虽然不可能有泛型,要强制转换了……)
这个和 infix pattern 不一样,它毕竟得是一个 unstable feature……
现在这么实现最主要的问题是得有一个 level 0,不能让异常漏处 Pattern 模型的范畴……
好像不必了,因为每层都是
好像不必了,因为每层都是
if (baseLevel > indent) return reducer.finish() 的嘛
/tmp/duangsuse.sock
大意就是,除了异常以外没有办法在两层 LayoutPattern.read 之间传递控制权,因为使用处是不确定的 除非使用 abstract class 硬性建模何时开启新 pattern,否则这个信息没法通过返回值传递出去,即便能手写起来复杂性也不可接受。 LayoutPattern 注定是递归结构,所以 caller 必须去 handle 它的 closing indent level 返回值,对应用来说那必须手写模板代码,我觉得比起那样还是异常靠谱一些(虽然不可能有泛型,要强制转换了……) 这个和…
最终我决定还是采取内部递归数据结构的方法来解决,因为异常会打断所有没有特别支持 LayoutPattern read 的子 Pattern read,不能把已经解析到的数据收集回来