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

欢迎!请查看关于页面了解有关此操作的一些更多信息。

+1
错误

定义不存在的 ns 中的 var 会产生此错误

user> (def foo/bar 1) 语法错误:在编译 def 时出错 (REPL:1:1)。不能在当前 ns 之外创建定义

原因: 编译器查找变量 lookupVar() 如果在限定变量中的 ns 还不存在,将返回 null。

建议: 通过命名符号并抛出带有文件/行/列信息的 CompilerException,可以改进错误消息。虽然不是显而易见,但这种情况可能是唯一一种会引起此类错误的情况。如果是这样,错误消息可以更具体地指出 ns 是不存在的部分。

补丁: clj-1400-4.diff

审核人员: Alex Miller

14 个答案

0

由:scottbale 发布的评论

在我看来,这似乎是一条相对容易的道路,除非我在某处忽略了什么,我将自行处理。

0

由:scottbale 发布的评论

将补丁 {{clj-1400-1.diff}} 应用到 {{Compiler.java}}。

使用此补丁后,示例将现在看起来像这样

user> (def foo/bar 1) CompilerException java.lang.RuntimeException: Qualified symbol foo/bar refers to nonexistent namespace: foo, compiling:(NO_SOURCE_PATH:1:1)

我不确定 {{if(namesStaticMember(sym))}}(链接:见下文),以及第二个分支,是否有必要。光凭检查,我怀疑它们可能没有必要。

(链接:脚注)

`
public static boolean namesStaticMember(Symbol sym){

return sym.ns != null && namespaceFor(sym) == null;

}
`

0

由:scottbale 发布的评论

补丁:代码和测试

0

由:scottbale 发布的评论

我在实际的源文件上进行了测试,出现的异常信息包含了所需的文件/行/列信息

user=> CompilerException java.lang.RuntimeException: Qualified symbol goo/bar refers to nonexistent namespace: goo, compiling:(/home/scott/dev/foo.clj:3:1)

0

评论者:jafingerhut

在Clojure于2014年8月29日提交一些版本后,补丁“clj-1400-1.diff”在最新的master上不再干净地应用。在此之前,它可以干净地应用。

我尚未检查更新此补丁的可能性和难度。有关更新补丁的提示,请参阅本维基页面上的“更新过时的补丁”部分: http://dev.clojure.org/display/community/Developing Patches

0

由:scottbale 发布的评论

附上了更新后的补丁:“clj-1400-2.diff”。我已删除过时的补丁。

0

评论者:alexmiller

只有少量评论需要处理
- 编译器diff使用的是空格而不是制表符,这使diff更困难。我附上了-3.diff,它可以解决这个问题。
- namesStaticMember的调用看起来很奇怪。该方法名称对此用途来说很令人困惑。除此之外,我认为它做的事情比需要的更多。该方法将尝试以当前ns的形式解析合格名称,但我觉得您甚至不需要这样做。相反,您只需要知道sym是否有ns(sym.ns != null)——难道不是这样吗?
- 在什么情况下将发生其他错误“变量不存在”?换句话说,在什么情况下lookupVar在这里无法成功创建新的变量?如果没有这种情况,请删除该情况。如果有这种情况,请添加测试。

0

由:scottbale 发布的评论

同意你列举的所有三个要点。附上了更新后的补丁,clj-1400-4.diff。
我在 Compiler.java 中使用了制表符
在仔细检查调用了 lookupVar(...) 后,我相信 null 只有在正好是这个票据的情况下才会返回(符号有一个尚未加载的非空命名空间)。因此,我已经移除了条件和第二个分支。
* (测试未更改)

0

由:scottbale 发布的评论

(补丁命名正确)

0

评论者:alexmiller

你可以抛出一个带有问题位置的 CompilerException(正如票据描述中提到的)。

0

由:scottbale 发布的评论

抱歉,我应该提到的(因为这也并非对我来说显而易见,并且事实上直到刚才我才想起):RuntimeException 已经被捕获并封装在一个 CompilerException 中。

我不确定这发生在 Compiler.java 中的哪个 try-catch 块中,因为有很多。但是在输出中你可以看到异常是一个 CompilerException,并且文件|行|列信息都在那里

在 Repl...

user> (def foo/bar 1) CompilerException java.lang.RuntimeException: Qualified symbol foo/bar refers to nonexistent namespace: foo, compiling:(NO_SOURCE_PATH:1:1)

...或在一个源文件中

user=> CompilerException java.lang.RuntimeException: Qualified symbol goo/bar refers to nonexistent namespace: goo, compiling:(/home/scott/dev/foo.clj:3:1)

此外,在这个补丁的 RuntimeException 正在被抛出的点,CompilerException 的 {{source}} {{line}} 和 {{col}} 参数不可用,或者至少不是 afaict。

0

评论者:alexmiller

我稍后会跟进这个补丁 - Rich 认为它假设太多。我认为我们已经验证了许多这些假设,但需要再次检查。

0

评论者:alexmiller

从Clojure 1.10开始更新错误结果。现在它会因为文件/行/列异常抛出编译语法错误阶段异常。

0
参考:https://clojure.atlassian.net/browse/CLJ-1400(由 hlewisship 报告)
...