欢迎!请参阅关于页面以了解更多关于这是如何工作的信息。
Dirac DevTools REPL依赖于正确的源映射(链接:1)。当我将"#js {}"输入REPL提示符时,评估工作正常,但生成的javascript代码片段有错误的源映射。关联的source-map的sourcesContent类似于#object(链接:cljs.tagged_literals.JSValue 0x34d692f3 "cljs.tagged_literals.JSValue@34d692f3")。而且这并不是用户输入的。这不是我可以再次解析的有效的cljs源,用于代码补全。
这个问题有些微妙。当生成源映射信息时,REPL代码尝试查看:source元数据(链接:2),如果没有提供,它就简单地使用pr打印表单。因为我们得到了Clojure风格的打印,因为JSValue没有像CLJS-733报告中那样实现ClojureScript打印。
我专注于实现CLJS-733中拒绝的想法。我关注了带有:source元数据的第一个代码路径。结果是,如果给定的表单支持元数据协议, 会添加:source。最简单的方法是更改JSValue从deftype到defrecord。
我确认这修复了Dirac中的REPL问题。现在我能得到用户输入的原始源代码。
注意,与 #uuid 和 #inst 标签也存在类似的问题。它们大多数工作是因为它们的打印机与Clojure和ClojureScript都兼容。但基本上,用户可能得到的源映射源与在REPL中输入的源不同。例如,可能缺少空白字符。这可能会引起混淆,因为由reader报告的行/列信息可能与由打印生成的这个人工源映射内容不匹配。
我相信修复方法是将由标签字面量创建的UUID和Date表单包装成类似于JSValue的东西,并使用这个包装值进行操作。这也适用于 #queue。这使得cljs.tagged-literal代码一致,因为所有来自数据读取器的表单都会在一个包装器中。这将允许在包装器上使用任意元数据。
作为旁注我注意到reader的元数据丢失了。它们没有被从reader产生的表单移植到生成的标签字面量表单中。我的第二个目标是复制reader的元数据。不幸的是,这不可能用当前tools.reader的实现来做到。我可以从传递的表单中获取reader元数据,但这不是全部情况,它仅描述了在标签已消耗之后的内容。我需要从标签本身获取元数据,某种方式传递到data-reader调用中(链接:3)。
我不知道标签字面量上缺失reader元数据在实际应用中引起的任何真正的问题,但我认为理想情况下应该修复。例如,在实现cljs-oops的错误报告时,我必须处理这个边缘情况(链接:4),因为在一些边缘情况下缺少行/列元数据。
(链接:1) https://github.com/binaryage/dirac/releases/tag/v0.8.0(链接:2) https://github.com/clojure/clojurescript/blob/960bb9b778190aa7359acb2f74cc61d452CEF2AE/src/main/clojure/cljs/repl.cljc#L476(链接:3) https://github.com/clojure/tools.reader/blob/3F36A18A6C5D53A4FC718822131EE75625FD44DC/src/main/cljs/cljs/tools/reader.cljs#L834(链接:4) https://github.com/binaryage/cljs-oops/blob/d530a3CDF8CBAB39BD2699C36CAD4414224C50/src/lib/oops/reporting.clj#L29
评论由:darwin 发表
我刚刚注意到,由于 defrecord 的变化,一些测试失败了。我的原始实现是使用 deftype 与 clojure.lang.IObj 实现。但它有一个缺陷,即重复使用 val 作为保存元数据的 target,这在一般情况下可能不是 IObj。而且还需要为 bootstrapped 实现一个单独的实现。我还不想将另一个字段添加到 deftype 中。我将把它留给你来提出如何正确实现的方法。
这一次我试试这个 - 这次我依赖于这样一个事实,即在 val 字段必须是向量或映射。所以它可以为 JSValue 承载元数据,而无需在 deftype 中添加新字段。
测试通过。