parsing - 从具有隐含节点和无序子节点的 ASTNode 创建 PsiElement
问题描述
使用 IntelliJ 的插件 SDK 生成PSIElement树的自定义语言插件是否可以?
- 一些PSIElement没有关联的ASTNode,所以在哪里
myPsiElement.getNode() == null
- 一些PSIElement的孩子有问题,例如
myPsiElement.children()[0].getStartOffsetInParent() > myPsiElement.children()[1].getStartOffsetInParent()
- 一些PSIElement对应于源中的零个字符:
myPsiElement.getTextLength() == 0
这些属性中的任何一个是否会使利用语言插件 SDK 功能变得更加困难?
背景:
我正在根据“实现解析器和 PSI ”为 IntelliJ 创建一个自定义语言插件。
文档中图表的底部显示了ASTNode和PsiElement之间的关系。
IIUC,首先,词法分析器将文本分割成标记。然后解析器在标记之间删除节点开始和结束标记以指定解析树结构。Intellij 内部将带有标记的令牌流提升到(不是非常抽象的)ASTNode树中。最后,特定语言的插件代码从 AST 构建 PSI 树。
从该图中看起来,Psi 树中的每个节点都与一个ASTElement相关联。
这种关系似乎是双向的PsiElement.getNode()
。该图没有显示MyPsiFile和MyElementType.FILE ASTNode之间的箭头,但
PsiFile.getNode()
表明必须有一个。
由于特定于语言的原因,我现有的解析器生成的树并不明显适合此模型。
- 节点可能出现乱序。表达式
a + b
解析为类似 的节点(call + a b)
。请注意,中缀和后缀运算符左移到它们的第一个操作数之前。 解析器合成了一些不对应token的节点,因此它们与AST节点之间的关系尚不清楚。例如,我需要为
for (x;;) body
for (;x;) body
for (;;x) body
因此解析器插入符号,例如for
init=
的(for init= x body)
定义可以用来决定如何处理。x
有一个“非物理” PSIElement的概念:
/** * Checks if an actual source or class file corresponds to the element. Non-physical elements include, * for example, PSI elements created for the watch expressions in the debugger. * Non-physical elements do not generate tree change events. * Also, {@link PsiDocumentManager#getDocument(PsiFile)} returns null for non-physical elements.
但我不清楚这些是否与ASTNode相关联,或者这是否适用于程序文本暗示的节点。
解决方案
推荐阅读
- python - Python中的模板设计模式关于覆盖模板方法的问题
- java - 从具有重复性的排序数组创建未排序集时
- javascript - 用空对象反应原生 setState 更新数组
- go - 尝试初始化 2D 切片,但元素引用更改了切片中的所有行
- regex - 匹配两个或多个不相同的字符
- java - 如何使用 Mockito 或 PowerMockito 在 JUnit 中模拟包含文件和 BufferedReader 的方法
- c# - 两个类库都需要相互引用
- python - 如何在 Django 中使用自定义模型扩展自用户模型?
- mongodb - 我想使用日期范围“utc_timestamp”字段从 mongodb 集合中获取结果?
- laravel - 调用未定义的方法 onlyTrashed()