feat(joinir): Phase 54 AST→JSON JoinIR-compatible statement fields

Add JoinIR-compatible fields to statement JSON output in ast_json.rs:
- Assignment: "type": "Assignment", "target" (string), "expr" alias
- Print: "type": "Print", "expr" alias
- Local: "type": "Local", "name", "expr" (for single-variable case)
- If: "type": "If", "cond" alias
- Loop: "type": "Loop", "cond" alias
- Return: "type": "Return"

This enables the stmt_handlers.rs (Phase 53) to correctly parse
statements from control_flow.rs loop body JSON.

Test results: JoinIR 56 PASS, loop_frontend_binding 7 PASS

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
nyash-codex
2025-11-29 04:49:27 +09:00
parent e27934d91a
commit ee6e95b164

View File

@ -7,37 +7,78 @@ pub fn ast_to_json(ast: &ASTNode) -> Value {
"kind": "Program",
"statements": statements.into_iter().map(|s| ast_to_json(&s)).collect::<Vec<_>>()
}),
// Phase 54: Loop with JoinIR-compatible fields
ASTNode::Loop {
condition, body, ..
} => json!({
"kind": "Loop",
"type": "Loop", // JoinIR Frontend expects "type"
"condition": ast_to_json(&condition),
"cond": ast_to_json(&condition), // JoinIR expects "cond"
"body": body.into_iter().map(|s| ast_to_json(&s)).collect::<Vec<_>>()
}),
// Phase 54: Print with JoinIR-compatible fields
ASTNode::Print { expression, .. } => json!({
"kind": "Print",
"type": "Print", // JoinIR Frontend expects "type"
"expression": ast_to_json(&expression),
"expr": ast_to_json(&expression), // JoinIR expects "expr"
}),
// Phase 54: Return with JoinIR-compatible fields
ASTNode::Return { value, .. } => json!({
"kind": "Return",
"type": "Return", // JoinIR Frontend expects "type"
"value": value.as_ref().map(|v| ast_to_json(v)),
}),
ASTNode::Break { .. } => json!({"kind":"Break"}),
ASTNode::Continue { .. } => json!({"kind":"Continue"}),
ASTNode::Assignment { target, value, .. } => json!({
"kind": "Assignment",
"target": ast_to_json(&target),
"value": ast_to_json(&value),
}),
// Phase 54: Assignment with JoinIR-compatible fields
ASTNode::Assignment { target, value, .. } => {
// Extract variable name if target is a simple Variable
let target_str = match target.as_ref() {
ASTNode::Variable { name, .. } => name.clone(),
_ => "complex".to_string(), // FieldAccess or other complex target
};
json!({
"kind": "Assignment",
"type": "Assignment", // JoinIR Frontend expects "type"
"target": target_str, // JoinIR expects string variable name
"lhs": ast_to_json(&target), // Keep full AST for complex cases
"value": ast_to_json(&value),
"expr": ast_to_json(&value), // JoinIR expects "expr"
})
}
// Phase 54: Local with JoinIR-compatible fields
ASTNode::Local {
variables,
initial_values,
..
} => json!({
"kind": "Local",
"variables": variables,
"inits": initial_values.into_iter().map(|opt| opt.map(|v| ast_to_json(&v))).collect::<Vec<_>>()
}),
} => {
// For single-variable declarations, add "name" and "expr" for JoinIR compatibility
let (name, expr) = if variables.len() == 1 {
let n = variables[0].clone();
let e = initial_values.get(0)
.and_then(|opt| opt.as_ref())
.map(|v| ast_to_json(v));
(Some(n), e)
} else {
(None, None)
};
let inits: Vec<_> = initial_values.into_iter()
.map(|opt| opt.map(|v| ast_to_json(&v)))
.collect();
json!({
"kind": "Local",
"type": "Local", // JoinIR Frontend expects "type"
"name": name, // Single variable name for JoinIR (null if multiple)
"expr": expr, // Single variable init for JoinIR (null if multiple)
"variables": variables,
"inits": inits
})
}
// Phase 54: If with JoinIR-compatible fields
ASTNode::If {
condition,
then_body,
@ -45,7 +86,9 @@ pub fn ast_to_json(ast: &ASTNode) -> Value {
..
} => json!({
"kind": "If",
"type": "If", // JoinIR Frontend expects "type"
"condition": ast_to_json(&condition),
"cond": ast_to_json(&condition), // JoinIR expects "cond"
"then": then_body.into_iter().map(|s| ast_to_json(&s)).collect::<Vec<_>>(),
"else": else_body.map(|v| v.into_iter().map(|s| ast_to_json(&s)).collect::<Vec<_>>()),
}),