使用antlr4-c3实现代码补全:如何获取递归作用域中的函数名?
使用ANTLR4-C3获取嵌套函数名称实现代码补全
需求说明
需要基于ANTLR4-C3实现代码补全,要求获取当前上下文的函数名称列表。例如在表达式foo(bar(...))的省略号位置,希望得到候选列表["foo", "bar"]。
语法定义
grammar Scope; expression: function | INT ; function: NAME '(' expression ')' ; NAME: [a-z]+; INT: [0-9]+; WS: [ \n\r\t] -> channel(HIDDEN);
尝试代码
const inputStream = CharStreams.fromString("foo(bar(123))"); const lexer = new ScopeLexer(inputStream); const tokenStream = new CommonTokenStream(lexer); const parser = new ScopeParser(tokenStream); const errorListener = new ErrorListener(); parser.addErrorListener(errorListener); parser.expression(); const core = new c3.CodeCompletionCore(parser); core.preferredRules = new Set([ScopeParser.RULE_function]); const candidates = core.collectCandidates(5); console.log("=================== rules ======================"); for (const [key, value] of candidates.rules) { console.log(key, value); let functions = candidates.rules.get(ScopeParser.RULE_function)?.ruleList; console.log(functions); }
问题现象
执行代码后仅返回规则相关信息,无法获取函数名称列表:
=================== rules ====================== 1 { startTokenIndex: 0, ruleList: [ 0 ] } [ 0 ]
开启调试信息后,可见内部已生成函数调用栈,但未保留到候选结果中。
解决方案
ANTLR4-C3默认仅收集当前位置可匹配的补全候选(规则/令牌),不会主动提取已解析的历史函数名称。要获取目标列表,需主动遍历解析树收集已匹配的NAME令牌:
保存解析树
修改解析代码,保存生成的解析树节点:const parseTree = parser.expression(); // 保存解析树遍历解析树收集函数名称
编写递归遍历函数,提取所有function节点下的NAME令牌:function collectFunctionNames(node) { const names = []; // 判断当前节点是否为函数节点 if (node instanceof ScopeParser.FunctionContext) { // 提取函数名称令牌 const nameToken = node.NAME(); if (nameToken) { names.push(nameToken.getText()); } // 递归遍历子表达式中的函数 const exprNode = node.expression(); if (exprNode) { names.push(...collectFunctionNames(exprNode)); } } else if (node.children) { // 遍历所有子节点 for (const child of node.children) { names.push(...collectFunctionNames(child)); } } return names; } // 调用函数获取名称列表 const functionNames = collectFunctionNames(parseTree); console.log("函数名称列表:", functionNames); // 输出 ["foo", "bar"]结合补全场景扩展
针对JSONPath过滤器的绝对路径需求,可扩展遍历逻辑:维护一个路径栈,进入函数时将名称压入栈,离开时弹出,这样在补全位置就能获取当前的绝对路径名称列表。
内容的提问来源于stack exchange,提问作者Pavel Ganelin
相关产品推荐
相关产品推荐

