欢迎!请查看 关于 页面,了解更多关于该怎么做。
Dirac DevTools REPL 依赖于正确的源映射(链接:1)。当我在 REPL 提示符中输入 "#js {}" 时,评估工作正常,但生成的 JavaScript 代码片段源映射错误。关联的源映射的 sourcesContent 看起来像是 #object(link: cljs.tagged_literals.JSValue 0x34d692f3 "cljs.tagged_literals.JSValue@34d692f3")。而这并非用户输入的内容。这不是我能够再次解析以进行代码补全的有效 cljs 源代码。
问题有些微妙。当生成源映射信息时,REPL 代码尝试查看 :source 元数据(链接:2),如果不存在,则简单地使用 pr 打印形式。我们得到 Clojure 风格的打印输出,因为 JSValue 没有实现 ClojureScript 的打印,如 CLJS-733 中所述。
而不是实现 CLJS-733 中拒绝的想法。我专注于带有关联元数据的第一个代码路径。结果发现,如果给定形式支持元数据协议,则会添加 :source。最容易的想法是将 JSValue 从 deftype 修改为 defrecord。
我确认这修复了 Dirac 中的 REPL 问题。现在我正在获取用户输入的原始源代码。
请注意,类似的问题也存在于 #uuid 和 #inst 标签中。它们主要是因为它们的打印机与 Clojure 和 ClojureScript 都兼容而大多工作。但从本质上讲,用户可能得到的源映射源代码与在 REPL 中输入的不一样。例如,空格可能会丢失。这可能会引起混淆,因为由读取器报告的行/列信息可能不匹配此通过打印生成的人工源映射内容。
我认为修复方法是将标签 literals 创建的 UUID 和 Date 形式包裹起来,类似于 JSValue,并针对此包裹值进行处理。同样适用于 #queue。这将使 cljs.tagged-literal 代码保持一致,因为每个从数据读取器产生的形式的起源都会在包装器内。它将使包装器上的任意元数据成为可能。
作为备注我注意到读取器的元数据丢失了。它们没有被从读者产生的表单移植到生成的标签 literals 形式。我的第二个目标是复制读者元数据。不幸的是,目前在 tools.reader 的实现中无法实现这一点。我可以从传递的表单中获取读取器元数据,但这并不是全貌,它只描述了在标签已被消费之后的内容。我需要从标签本身获取元数据,以某种方式传递给数据读取器调用(链接:3)。
我不知道在标记字面量中缺少读者元数据会导致任何现实世界的问题,但我认为 ideally 应该修复它。例如,在实现 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。而且还需要为 bootstrapped 实现单独的实现。此外,我不想在 deftype 中添加另一个字段。我将留出空间供你提出如何正确实现这个的建议。
再次尝试 - 这次我依靠 val 字段必须是向量或映射的事实。因此,可以从不添加新字段到 deftype 开始,为 JSValue 带来元数据。
测试通过。