2024 年 Clojure 状态调查中分享您的想法!

欢迎!请查看关于页面以获取更多关于这个网站如何工作的信息。

0
语法和读取器

可复现的测试案例

(ns bug)
(require '[clojure.data.xml :as xml] #?@(:cljs [[clojure.data.xml.js.dom :as dom]]))
(def opts {:features #{:clj} :read-cond :allow})
(read-string opts "#?(:cljs {:a ::dom/Element})")
; Execution error at bug/eval30984 (REPL:534).
; Invalid token: ::dom/Element

堆栈跟踪

clojure.lang.Util/runtimeException (Util.java:221)
clojure.lang.LispReader/interpretToken (LispReader.java:412)
clojure.lang.LispReader/read (LispReader.java:305)
clojure.lang.LispReader/readDelimitedList (LispReader.java:1398)
clojure.lang.LispReader$MapReader/invoke (LispReader.java:1355)
clojure.lang.LispReader/read (LispReader.java:285)
clojure.lang.LispReader/access$900 (LispReader.java:41)
clojure.lang.LispReader$ConditionalReader/readCondDelimited (LispReader.java:1584)
clojure.lang.LispReader$ConditionalReader/invoke (LispReader.java:1659)
clojure.lang.LispReader$DispatchReader/invoke (LispReader.java:853)
clojure.lang.LispReader/read (LispReader.java:285)
clojure.lang.RT/readString (RT.java:1876)
clojure.core/read-string (core.clj:3817)
clojure.core/read-string (core.clj:3806)
bug/eval30984 (NO_SOURCE_FILE:534)
clojure.lang.Compiler/eval (Compiler.java:7194)

实际场景

读取 data.xml-0.2.0-alpha8/clojure/data/xml/spec.cljc 在第 45 行错误:[https://github.com/clojure/data.xml/blob/v0.2.0-alpha8/src/main/resources/clojure/data/xml/spec.cljc#L45](https://github.com/clojure/data.xml/blob/v0.2.0-alpha8/src/main/resources/clojure/data/xml/spec.cljc#L45)

注意那里堆栈跟踪是不同的

; Caused by: clojure.lang.ExceptionInfo: [line 45, col 28] Invalid keyword: ::dom/Element. {:type :reader-exception, :ex-kind :reader-error, :file nil, :line 45, :col 28}
; 	at clojure.tools.reader.impl.errors$throw_ex.invokeStatic(errors.clj:34)
; 	at clojure.tools.reader.impl.errors$throw_ex.doInvoke(errors.clj:24)
; 	at clojure.lang.RestFn.invoke(RestFn.java:442)
; 	at clojure.tools.reader.impl.errors$reader_error.invokeStatic(errors.clj:40)
; 	at clojure.tools.reader.impl.errors$reader_error.doInvoke(errors.clj:36)
; 	at clojure.lang.RestFn.invoke(RestFn.java:516)
; 	at clojure.tools.reader.impl.errors$throw_invalid.invokeStatic(errors.clj:97)
; 	at clojure.tools.reader.impl.errors$throw_invalid.invoke(errors.clj:96)
; 	at clojure.tools.reader$read_keyword.invokeStatic(reader.clj:358)
; 	at clojure.tools.reader$read_keyword.invoke(reader.clj:344)
; 	at clojure.tools.reader$read_STAR_.invokeStatic(reader.clj:935)
; 	at clojure.tools.reader$read_STAR_.invoke(reader.clj:917)
; 	at clojure.tools.reader$read_delimited.invokeStatic(reader.clj:198)
; 	at clojure.tools.reader$read_delimited.invoke(reader.clj:191)
; 	at clojure.tools.reader$read_list.invokeStatic(reader.clj:209)
; 	at clojure.tools.reader$read_list.invoke(reader.clj:205)
; 	at clojure.tools.reader$read_STAR_.invokeStatic(reader.clj:935)
; 	at clojure.tools.reader$read_STAR_.invoke(reader.clj:917)
; 	at clojure.tools.reader$read_delimited.invokeStatic(reader.clj:198)
; 	at clojure.tools.reader$read_delimited.invoke(reader.clj:191)
; 	at clojure.tools.reader$read_list.invokeStatic(reader.clj:209)
; 	at clojure.tools.reader$read_list.invoke(reader.clj:205)
; 	at clojure.tools.reader$read_STAR_.invokeStatic(reader.clj:935)
; 	at clojure.tools.reader$read_STAR_.invoke(reader.clj:917)
; 	at clojure.tools.reader$read_suppress.invokeStatic(reader.clj:451)
; 	at clojure.tools.reader$read_suppress.invoke(reader.clj:447)
; 	at clojure.tools.reader$match_feature.invokeStatic(reader.clj:474)
; 	at clojure.tools.reader$match_feature.invoke(reader.clj:458)
; 	at clojure.tools.reader$read_cond_delimited$fn__8556.invoke(reader.clj:485)
; 	at clojure.tools.reader$read_cond_delimited.invokeStatic(reader.clj:480)
; 	at clojure.tools.reader$read_cond_delimited.invoke(reader.clj:477)
; 	at clojure.tools.reader$read_cond.invokeStatic(reader.clj:522)
; 	at clojure.tools.reader$read_cond.invoke(reader.clj:506)
; 	at clojure.tools.reader$read_dispatch.invokeStatic(reader.clj:72)
; 	at clojure.tools.reader$read_dispatch.invoke(reader.clj:68)
; 	at clojure.tools.reader$read_STAR_.invokeStatic(reader.clj:935)
; 	at clojure.tools.reader$read_STAR_.invoke(reader.clj:917)
; 	at clojure.tools.reader$read.invokeStatic(reader.clj:988)
; 	at clojure.tools.reader$read.invoke(reader.clj:961)

1 个答案

0

自动解析的符号需要命名空间解析(读取器需要外部环境的主体功能)。

由于读取器条件“读取”条件中的所有部分,因此任何在条件中的内容都必须可在每个平台上读取,因此读取器条件中的自动解析符号不应依赖于条件命名空间。

这应该是期望的行为,因此请不要这么做。

我们已经考虑是否有可能在读取器条件上下文中暂停自动解析符号的解析,但这有点棘手,我不认为我们很快会这么做。

我创建了一个jira数据.xml来停止这样做。https://clojure.atlassian.net/browse/DXML-72
很有趣,谢谢你的解释。有没有办法暂时解决这个问题呢?

我们能否让clojure解释器在不受支持时引发错误或警告?或者也许clj-kondo和其他linters应该将其突出显示为错误?

另一方面,为什么我们不能简单地忽略所有被抑制的内容呢?
我们可以忽略它,但我们必须读取它来了解要忽略什么。你可以通过不在阅读器条件中使用自动解析的关键字来解决这个问题。
谢谢!我指的是我在想读取包含它们的第三方代码时的解决方案。
不,我认为没有解决方案,除非你首先创建命名空间,然后在加载之前为不同的(现有)命名空间创建别名。
...