feat(joinir): Phase 52-53 LoopFrontendBinding JSON + Statement Handlers
Phase 52: LoopFrontendBinding JSON generation fixes - Add receiver_to_json() for Field node structure (me.tokens) - Add needs_me_receiver() for instance method detection - Fix "condition" → "cond" key for JoinIR Frontend - Add me parameter propagation in loop_patterns.rs - Add JoinIR-compatible type fields in ast_json.rs - Variable → "type": "Var" - Literal → "type": "Int"/"Bool" (literal_to_joinir_json) - BinaryOp → "type": "Binary"/"Compare" (is_compare_op) - MethodCall → "type": "Method" Phase 53: Statement Handler module for loop body - NEW: stmt_handlers.rs with StatementEffect type - Support: Local, Assignment, Print, Method, If statements - If lowering: single variable update → Select instruction - Remove hardcoded assert in loop_patterns.rs - Replace with generic lower_statement() calls Test results: 56 JoinIR tests PASS, 7 loop_frontend_binding tests PASS 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -71,6 +71,16 @@ pub enum LoopPattern {
|
||||
}
|
||||
|
||||
impl LoopFrontendBinding {
|
||||
/// Phase 52: Check if `me` receiver is needed for this loop
|
||||
///
|
||||
/// Returns true if any external_ref starts with "me" (e.g., "me.tokens")
|
||||
/// This indicates an instance method that needs access to `me`.
|
||||
pub fn needs_me_receiver(&self) -> bool {
|
||||
self.external_refs
|
||||
.iter()
|
||||
.any(|r| r == "me" || r.starts_with("me."))
|
||||
}
|
||||
|
||||
/// print_tokens 専用のバインディングを生成
|
||||
///
|
||||
/// print_tokens の構造:
|
||||
@ -135,6 +145,44 @@ impl LoopFrontendBinding {
|
||||
None
|
||||
}
|
||||
|
||||
/// Phase 52: ドット区切りの変数名を Field ノード構造に変換
|
||||
///
|
||||
/// 例: "me.tokens" → {"type": "Field", "object": {"type": "Var", "name": "me"}, "field": "tokens"}
|
||||
/// 例: "arr" → {"type": "Var", "name": "arr"}
|
||||
fn receiver_to_json(receiver: &str) -> serde_json::Value {
|
||||
use serde_json::json;
|
||||
|
||||
if let Some(dot_pos) = receiver.find('.') {
|
||||
// ドット区切りがある場合 → Field ノードに分解
|
||||
let object_name = &receiver[..dot_pos];
|
||||
let field_name = &receiver[dot_pos + 1..];
|
||||
|
||||
// ネストしたフィールドアクセス (e.g., "a.b.c") は再帰的に処理
|
||||
if field_name.contains('.') {
|
||||
// "me.tokens.inner" → Field(Field(Var("me"), "tokens"), "inner")
|
||||
let inner_receiver = Self::receiver_to_json(field_name);
|
||||
json!({
|
||||
"type": "Field",
|
||||
"object": { "type": "Var", "name": object_name },
|
||||
"field": inner_receiver
|
||||
})
|
||||
} else {
|
||||
// 単一レベルのフィールドアクセス (e.g., "me.tokens")
|
||||
json!({
|
||||
"type": "Field",
|
||||
"object": { "type": "Var", "name": object_name },
|
||||
"field": field_name
|
||||
})
|
||||
}
|
||||
} else {
|
||||
// ドットなし → 単純な Var ノード
|
||||
json!({
|
||||
"type": "Var",
|
||||
"name": receiver
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// JoinIR Frontend 用の JSON v0 Local 宣言を生成
|
||||
///
|
||||
/// Returns: (i_local, acc_local, n_local) の JSON Value タプル
|
||||
@ -142,6 +190,7 @@ impl LoopFrontendBinding {
|
||||
/// Note: JoinIR Frontend expects specific type names:
|
||||
/// - "Int" for integer literals (with "value" field)
|
||||
/// - "Var" for variable references (with "name" field)
|
||||
/// - "Field" for field access (with "object", "field" fields) - Phase 52
|
||||
/// - "Method" for method calls (with "receiver", "method", "args" fields)
|
||||
/// - "NewBox" for box instantiation
|
||||
pub fn generate_local_declarations(
|
||||
@ -201,14 +250,15 @@ impl LoopFrontendBinding {
|
||||
})
|
||||
}
|
||||
BoundExpr::MethodCall { receiver, method } => {
|
||||
// メソッド呼び出しを評価(print_tokens の me.tokens.length() 等)
|
||||
// JoinIR Frontend expects "Method" type
|
||||
// Phase 52: メソッド呼び出しを評価(print_tokens の me.tokens.length() 等)
|
||||
// receiver が "me.tokens" のようにドット区切りの場合は Field ノードに分解
|
||||
let receiver_json = Self::receiver_to_json(receiver);
|
||||
json!({
|
||||
"type": "Local",
|
||||
"name": "n",
|
||||
"expr": {
|
||||
"type": "Method",
|
||||
"receiver": { "type": "Var", "name": receiver },
|
||||
"receiver": receiver_json,
|
||||
"method": method,
|
||||
"args": []
|
||||
}
|
||||
@ -349,4 +399,40 @@ mod tests {
|
||||
assert_eq!(n_local["expr"]["type"], "Var");
|
||||
assert_eq!(n_local["expr"]["name"], "n");
|
||||
}
|
||||
|
||||
// Phase 52: receiver_to_json のテスト
|
||||
#[test]
|
||||
fn test_receiver_to_json_simple_var() {
|
||||
let json = LoopFrontendBinding::receiver_to_json("arr");
|
||||
assert_eq!(json["type"], "Var");
|
||||
assert_eq!(json["name"], "arr");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_receiver_to_json_field_access() {
|
||||
let json = LoopFrontendBinding::receiver_to_json("me.tokens");
|
||||
assert_eq!(json["type"], "Field");
|
||||
assert_eq!(json["object"]["type"], "Var");
|
||||
assert_eq!(json["object"]["name"], "me");
|
||||
assert_eq!(json["field"], "tokens");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_print_tokens_n_local_has_field() {
|
||||
// Phase 52: print_tokens の n (me.tokens.length()) が Field ノードを使っているか確認
|
||||
let binding = LoopFrontendBinding::for_print_tokens();
|
||||
let (_i_local, _acc_local, n_local) = binding.generate_local_declarations();
|
||||
|
||||
// n = me.tokens.length() の構造を確認
|
||||
assert_eq!(n_local["name"], "n");
|
||||
assert_eq!(n_local["expr"]["type"], "Method");
|
||||
assert_eq!(n_local["expr"]["method"], "length");
|
||||
|
||||
// receiver が Field ノードであることを確認
|
||||
let receiver = &n_local["expr"]["receiver"];
|
||||
assert_eq!(receiver["type"], "Field");
|
||||
assert_eq!(receiver["object"]["type"], "Var");
|
||||
assert_eq!(receiver["object"]["name"], "me");
|
||||
assert_eq!(receiver["field"], "tokens");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user