【设想】为木兰编写基于语言服务协议(LSP)的 VSC 插件

之前的讨论 ,希望用较小代价对 LSP 进行实践以理解其架构。

向冰封咨询后,打算将此功能作为第一步:仅基于木兰现有的类型相关功能,支持 str 类型的方法补全。

即实现像Python的 VSC 插件这样的补全:

当前木兰实现可获得类型名如下:

Screenshot 2023-04-07 at 8.50.50 AM

如咨询中所言,打算将此第一步通过gitee悬赏实现。欢迎意见建议。

1 个赞

关注一下,有issue链接么

2 个赞

暂还没。主要对 LSP 不了解,还不确定这第一步的功能是否明确恰当、相应预算多少。
之前在木兰重现项目里预算较高的子任务像 这个这个,还没尝试过更复杂的任务。
希望探讨一下敲定细节和期望再发布悬赏。

你这个例子是通过运行实现的, 不能通过这种方式在 IDE 里面实现补全. 假设用户有这样的代码:

os.system("rm -rf ~/*")

你去对它调用一下 type, 就当场去世了.

2 个赞

同意此方法存在的问题。

因为目的是了解 LSP,实现类型检查的额外功能不在计划范围内。即仅打算直接使用木兰实现的现有功能。

作为原型的第一步,使用 typeof 或者更简易安全的方法都可以接受。

简单回答一下这个问题:

LSP 本质就是一个服务端和一个客户端通过 JSON 交换编译器内部数据。你需要实现的内容都可以在 LSP 文档中找到:

实现一个功能只有 3 步:

  1. 检查 ServerCapabilities,用于在服务端告诉客户端:“我支持这个功能”。
  2. 检查 ClientCapabilities,用于在客户端告诉服务端:“请通过怎样的格式告诉我代码里的信息”。
  3. 在服务端实现相关的函数(request 或者 notification)。

可以看出,LSP 的重点并不在于怎么写服务端或者客户端,而是如何设计编译器,让内部数据合理地暴露给外界

2 个赞

感谢。
听起来,如果仅做个 pretotype 达成之前所述的第一步效果,工作量应该不会太大?
悬赏金额多少比较合适呢?

并不一定,你可能没有理解我说的

可以看出,LSP 的重点并不在于怎么写服务端或者客户端,而是如何设计编译器,让内部数据合理地暴露给外界

工作量取决于编译器的设计水平。如果只有一个粗糙设计的编译器,那么在其上实现 LSP 需要的东西可能需要大量重构。这应该也计算到“第一步效果”的内容之中。

至于需要多少具体的重构,需要你根据该语言目前的实现评估,我不好妄下结论。


我曾经尝试为一个玩具语言实现类似的 LSP,那个语言缺乏对编译流程的抽象,导致我在将某些中间阶段产生的数据导出到 LSP 时遇到了不少问题。私以为,一个“不粗糙设计”的编译器至少应该有这些内容:

  • 对源代码文件、文件中的位置、报错信息等等具有相关数据结构。例如:编译器报错的时候不应该直接输出到 stdout/stderr。
  • 对编译流程具有相关抽象,可以自由控制某些内部状态。例如:LSP 往往需要支持增量编译。
  • AST 结构上有可能需要为 LSP “开洞”,或者保留某些内部状态,但这个应该是最容易解决的部分。
  • 可能需要为语法糖保留特定信息。

一般来说,上面这些东东在编译器里都是标配。

1 个赞

感谢分享心得体会!

如之前提到,此任务的主要目标是了解 LSP。作为原型的第一步,仅打算在 LSP 框架下实现顶楼的“效果”即可。为任务可控性考虑,打算尽量减少甚至避免对现有语言实现的修改。

因此,如果不方便利用现有木兰实现,可以使用包括对任何请求都返回静态值在内的任何方法实现该项“效果”。

对编译器的重构和改进等,可在这第一步完成之后考虑。

赞同 :+1:,我们搞 KCL 语言的 language server 的时候,第一步也是 compiler 架构设计和代码重构,也包含了错误整理,AST 调整等具体实操内容

1 个赞