欢迎!请见 关于 页面,了解更多关于如何使用本站的信息。
Dirac DevTools REPL 依赖于合适的 source-maps(链接:1)。当我将 "#js {}" 输入到 REPL 提示符时,评估会正常工作,但生成的 JavaScript 代码段具有错误的 source map。相关的 source-map 的 sourcesContent 类似于 #object(link: cljs.tagged_literals.JSValue 0x34d692f3 "cljs.tagged_literals.JSValue@34d692f3")。这并不是用户输入的内容。此外,这也不是一个有效的 cljs,我可以再次用于代码补全的源。
问题有点微妙。在生成 source-map 信息时,REPL 代码试图查看 :source 元数据(链接:2),如果没有提供,它就会简单地使用 pr 打印形式。我们看到了 Clojure 风格的打印输出,因为 JSValue 没有实施 ClojureScript 打印,如您在 CLJS-733 所报道的那样。
而不是实施从 CLJS-733 指出的想法。我专注于带 :source 元数据的第一个代码路径。结果发现,如果给定形式支持元数据协议,就会添加 :source。最简单的方法是将 JSValue 从 deftype 改为 defrecord。
我确认这修复了 Dirac 中的 REPL 问题。现在,我可以得到用户输入的原始源代码。
请注意,类似的问题也存在于 #uuid 和 #inst 标签中。这些大部分工作是因为它们的打印机既兼容 Clojure 也兼容 ClojureScript。但本质上用户可能得到与在 REPL 中输入不同的 source-map 源。例如,可能会缺少空格。这可能会造成困惑,因为由读取器报告的行/列信息可能不匹配由打印产生的这个人工 source-map 内容。
我相信修复方法是将由标记字面量创建的 UUID 和 Date 形式包裹成与 JSValue 类似的东西,并使用这个包裹值进行操作。与 #queue 也是如此。这将使 cljs.tagged-literal 代码保持一致,因为每个来自数据读取器起源的形式都会在一个包装器内部。它将允许在包装器上设置任意元数据。
作为附注我注意到读取器的元数据丢失了。它们没有从由读取器产生的形式传输到生成的标记字面量形式。我的第二个目标是复制读取器的元数据。不幸的是,这不可能与当前 tools.reader 的实现。我可以从传递给形式的读取器元数据,但这并不全面,它只描述了在标签已经被消耗后的内容。我需要从标签本身获得元数据,以某种方式传递给数据读取器调用(链接:3)。
我不知道有任何现实世界的问题是由带标签字面量中缺少的读者元数据引起的,但是我认为理想情况下应该解决这个问题。例如,在实现 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/d530a3cdf8cbab39bd2699c36caded4414224c50/src/lib/oops/reporting.clj#L29
评论者:darwin
我刚刚注意到,由于 defrecord 的更改,某些测试失败了。我的原始实现是使用带有 clojure.lang.IObj 实现的 deftype。但它有一个缺点是使用 val 作为保存元数据的目标,这在一般情况下可能不是 IObj。还必须为启动执行进行单独的实现。我也不想向 deftype 添加另一个字段。我将留给你建议如何正确实现它。
我又试了一次——这次我依赖于 val 字段必须是向量或映射的事实。因此,它可以在不向 deftype 添加新字段的情况下为 JSValue 携带元数据。
测试通过。