Issue with Parent Condition Context in Else Block During AST Traversal
I’m working on a JavaScript code analysis tool that traverses the Abstract Syntax Tree (AST) to analyze function calls and their conditions. The goal is to dynamically generate a condition chain for each function call based on nested if
, else if
, and else
statements.
Problem Description
When processing an else
block, I’m unable to correctly access the parent condition (parent.condition
) to generate the negation of the preceding if
condition. This results in incorrect condition chains for function calls inside the else
block.
Here’s a simplified version of the code I’m analyzing:
javascript
复制
function foo(a, b) {
var c = 100;
if (c > a) {
if (a > 200) {
alert(1);
} else if (a > 100) {
alert(2);
} else {
alert(3); // Condition here is incorrect
}
}
}
Expected Output
For the else
block (alert(3)
), the condition should be:
复制
100 > a 并且 非(a > 200) 且 非(a > 100)
However, the current implementation generates incorrect conditions because the parent condition context is not properly maintained.
Current Implementation
Here’s the relevant part of my code:
javascript
复制
if (
node.type === 'BlockStatement' &&
parent.type === 'IfStatement' &&
parent.alternate === node
) {
// Attempt to get the parent condition
const parentCondition = currentConditionContext.parent.condition; // ❌ Fails here
currentConditionContext = {
type: 'else',
condition: `非(${parentCondition})`,
parent: currentConditionContext.parent.parent, // Incorrect parent reference
siblingNegation: null
};
}
Issue
The problem occurs because:
-
The else
block incorrectly skips a level when referencing the parent context (parent.parent
).
-
The parent condition is not accessible due to the incorrect parent reference.
Question
How can I properly maintain the parent condition context for else
blocks to generate the correct negation of the preceding if
condition?
Desired Solution
I need a way to:
-
Correctly reference the parent condition context for else
blocks.
-
Generate the negation of the preceding if
condition dynamically.
-
Ensure the condition chain is accurate for nested if-else
structures.
Additional Context
-
I’m using esprima
for parsing, estraverse
for traversal, and escodegen
for code generation.
-
The condition chain should support arbitrary levels of nesting.
Here’s the full code for reference:
javascript
复制
// Full code implementation
Any guidance or suggestions would be greatly appreciated!
This question is clear, concise, and provides all the necessary context for someone to understand and help with your issue. You can replace the // Full code implementation
comment with your actual code if needed.
this is my code, The following code does not achieve the desired effect
import esprima from 'esprima';
import estraverse from 'estraverse';
import escodegen from 'escodegen';
export function analyzeFunctionCalls(code, functionName, methods) {
try {
const ast = esprima.parseScript(code, { range: true, tokens: true, comment: true });
const functionCalls = [];
const variableMap = {};
// 树形条件链管理(使用根节点初始化)
let currentConditionNode = {
condition: null,
parent: null,
children: []
};
estraverse.traverse(ast, {
enter: (node, parent) => {
// 变量声明处理
if (node.type === 'VariableDeclaration') {
node.declarations.forEach(declaration => {
if (declaration.init) {
variableMap[declaration.id.name] = escodegen.generate(declaration.init);
}
});
}
// 处理 if 语句
if (node.type === 'IfStatement') {
const condition = processCondition(node.test, variableMap);
// 创建新的条件节点并链接到当前节点
const newNode = {
condition: condition,
parent: currentConditionNode,
children: []
};
currentConditionNode.children.push(newNode);
currentConditionNode = newNode;
}
// 处理 else if
if (
node.type === 'IfStatement' &&
parent.type === 'IfStatement' &&
parent.alternate === node
) {
// 获取父 if 的条件
const parentIfCondition = currentConditionNode.parent.condition;
const currentCondition = processCondition(node.test, variableMap);
// 创建 else if 节点
const newNode = {
condition: `非(${parentIfCondition}) 且 ${currentCondition}`,
parent: currentConditionNode.parent, // 关键修正:父节点指向原 if 的父级
children: []
};
currentConditionNode.parent.children.push(newNode);
currentConditionNode = newNode;
}
// 处理 else 块
if (
node.type === 'BlockStatement' &&
parent.type === 'IfStatement' &&
parent.alternate === node
) {
// 获取父 if 的条件
const parentIfCondition = currentConditionNode.parent.condition;
// 创建 else 节点
const newNode = {
condition: `非(${parentIfCondition})`,
parent: currentConditionNode.parent, // 关键修正:父节点指向原 if 的父级
children: []
};
currentConditionNode.parent.children.push(newNode);
currentConditionNode = newNode;
}
// 收集函数调用
if (node.type === 'CallExpression') {
const callee = node.callee;
const fullCondition = getFullConditionChain(currentConditionNode);
if (
(callee.type === 'Identifier' && methods.includes(callee.name)) ||
(callee.type === 'MemberExpression' &&
callee.object.name === functionName &&
methods.includes(callee.property.name))
) {
functionCalls.push({
call: escodegen.generate(node),
condition: fullCondition
});
}
}
},
leave: (node) => {
// 离开 if 语句时回溯到父节点
if (node.type === 'IfStatement') {
currentConditionNode = currentConditionNode.parent;
}
}
});
return functionCalls;
} catch (error) {
console.error('Error parsing code:', error);
return [];
}
}
// 生成完整条件链(从根到当前节点)
function getFullConditionChain(node) {
const path = [];
let current = node;
while (current && current.condition !== null) {
path.unshift(current.condition);
current = current.parent;
}
return path.join(' 并且 ');
}
// 优化后的条件处理
function processCondition(testNode, variableMap) {
return escodegen.generate(testNode)
.replace(/bw+b/g, m => variableMap[m] || m)
.replace(/>=/g, '≥')
.replace(/<=/g, '≤')
.replace(/===/g, '等于')
.replace(/==/g, '等于')
.replace(/!=/g, '≠')
.replace(/>/g, '>')
.replace(/</g, '<')
.replace(/||/g, ' 或 ')
.replace(/&&/g, ' 且 ')
.replace(/!/g, '非');
}
console.log(analyzeFunctionCalls(`
function foo(a, b) {
var c = 100
if(c > a){
if( a > 200){
alert(1)
alert(4)
}else if(a > 100){
alert(2)
if(b > 200){
alert(5)
}else{
alert(6)
}
alert(7)
}else{
alert(3)
if(b > 200){
alert(8)
}else{
alert(9)
}
alert(10)
}
}
}
`, "DV",["alert"]));
expected result
[
{ call: 'alert(1)', condition: '100>a 并且 a>200' },
{ call: 'alert(4)', condition: '100>a 并且 a>200' },
{ call: 'alert(2)', condition: '100>a 并且 非(a>200) 且 a>100' },
{ call: 'alert(5)', condition: '100>a 并且 非(a>200) 且 a>100 并且 b>200' },
{ call: 'alert(6)', condition: '100>a 并且 非(a>200) 且 a>100 并且 非(b>200)' },
{ call: 'alert(7)', condition: '100>a 并且 非(a>200) 且 a>100' },
{ call: 'alert(3)', condition: '100>a 并且 非(a>200) 且 非(a>100)' }, // ✅ 正确
{ call: 'alert(8)', condition: '100>a 并且 非(a>200) 且 非(a>100) 并且 b>200' }, // ✅
{ call: 'alert(9)', condition: '100>a 并且 非(a>200) 且 非(a>100) 并且 非(b>200)' }, // ✅
{ call: 'alert(10)', condition: '100>a 并且 非(a>200) 且 非(a>100)' } // ✅
]
actual result
[
{ call: 'alert(1)', condition: '100 > a 并且 a > 200' },
{ call: 'alert(4)', condition: '100 > a 并且 a > 200' },
{
call: 'alert(2)',
condition: '100 > a 并且 a > 200 并且 非(a > 200) 且 a > 100'
},
{
call: 'alert(5)',
condition: '100 > a 并且 a > 200 并且 非(a > 200) 且 a > 100 并且 b > 200'
},
{
call: 'alert(6)',
condition: '100 > a 并且 a > 200 并且 非(a > 200) 且 a > 100 并且 非(非(a > 200) 且 a > 100)'
},
{
call: 'alert(7)',
condition: '100 > a 并且 a > 200 并且 非(a > 200) 且 a > 100'
},
{ call: 'alert(3)', condition: '100 > a 并且 a > 200 并且 非(a > 200)' },
{
call: 'alert(8)',
condition: '100 > a 并且 a > 200 并且 非(a > 200) 并且 b > 200'
},
{
call: 'alert(9)',
condition: '100 > a 并且 a > 200 并且 非(a > 200) 并且 非(非(a > 200))'
},
{ call: 'alert(10)', condition: '100 > a 并且 a > 200 并且 非(a > 200)' }
]
Is there a god to help me
thank you