## 🎉 Step 2: peek→match完全統一アーキテクチャクリーンアップ完了 - ✅ 15ファイルで PeekExpr → MatchExpr 一括置換完了 - ✅ lowering/peek.rs → match_expr.rs 完全移行 - ✅ AI理解性・コードベース一貫性・保守性大幅向上 ## 🔍 Step 3: 複数行パース問題調査完了 - ✅ Task先生による根本原因特定完了 - 原因: オブジェクトリテラルパーサーの改行スキップ不足 - 修正: src/parser/expr/primary.rs の skip_newlines() 追加 ## 🚨 重大発見: PHI命令処理バグ - 問題: gemini_test_case.nyash で期待値2→実際0 - 原因: フェーズM+M.2のPHI統一作業でループ後変数マージに回帰バグ - 詳細: PHI命令は正常だが、print時に間違ったPHI参照 - 影響: Phase 15セルフホスティング基盤の重大バグ ## 📝 CLAUDE.md更新 - 全進捗状況の詳細記録 - 次のアクション: ChatGPT相談でMIRビルダー修正戦略立案 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
78 lines
2.8 KiB
Rust
78 lines
2.8 KiB
Rust
use crate::ast::ASTNode;
|
|
use crate::parser::entry_sugar::parse_with_sugar_level;
|
|
use crate::syntax::sugar_config::SugarLevel;
|
|
|
|
#[test]
|
|
fn safe_access_field_and_method() {
|
|
let code = "a = user?.profile\nb = user?.m(1)\n";
|
|
let ast = parse_with_sugar_level(code, SugarLevel::Basic).expect("parse ok");
|
|
|
|
let program = match ast {
|
|
ASTNode::Program { statements, .. } => statements,
|
|
other => panic!("expected program, got {:?}", other),
|
|
};
|
|
assert_eq!(program.len(), 2);
|
|
|
|
// a = user?.profile
|
|
match &program[0] {
|
|
ASTNode::Assignment { value, .. } => match value.as_ref() {
|
|
ASTNode::MatchExpr {
|
|
scrutinee,
|
|
else_expr,
|
|
..
|
|
} => {
|
|
match scrutinee.as_ref() {
|
|
ASTNode::Variable { name, .. } => assert_eq!(name, "user"),
|
|
_ => panic!("scrutinee not user"),
|
|
}
|
|
match else_expr.as_ref() {
|
|
ASTNode::FieldAccess { object, field, .. } => {
|
|
match object.as_ref() {
|
|
ASTNode::Variable { name, .. } => assert_eq!(name, "user"),
|
|
_ => panic!("object not user"),
|
|
}
|
|
assert_eq!(field, "profile");
|
|
}
|
|
other => panic!("else not field access, got {:?}", other),
|
|
}
|
|
}
|
|
other => panic!("expected MatchExpr, got {:?}", other),
|
|
},
|
|
other => panic!("expected assignment, got {:?}", other),
|
|
}
|
|
|
|
// b = user?.m(1)
|
|
match &program[1] {
|
|
ASTNode::Assignment { value, .. } => match value.as_ref() {
|
|
ASTNode::MatchExpr {
|
|
scrutinee,
|
|
else_expr,
|
|
..
|
|
} => {
|
|
match scrutinee.as_ref() {
|
|
ASTNode::Variable { name, .. } => assert_eq!(name, "user"),
|
|
_ => panic!("scrutinee not user"),
|
|
}
|
|
match else_expr.as_ref() {
|
|
ASTNode::MethodCall {
|
|
object,
|
|
method,
|
|
arguments,
|
|
..
|
|
} => {
|
|
match object.as_ref() {
|
|
ASTNode::Variable { name, .. } => assert_eq!(name, "user"),
|
|
_ => panic!("object not user"),
|
|
}
|
|
assert_eq!(method, "m");
|
|
assert_eq!(arguments.len(), 1);
|
|
}
|
|
other => panic!("else not method call, got {:?}", other),
|
|
}
|
|
}
|
|
other => panic!("expected MatchExpr, got {:?}", other),
|
|
},
|
|
other => panic!("expected assignment, got {:?}", other),
|
|
}
|
|
}
|