docs: Add field visibility analysis and MIR BoxCall documentation

## Field Visibility Analysis Results
- Confirmed init{} fields are **public** in current Nyash implementation
- No access modifier (private/public) system currently implemented
- All fields accessible via me.fieldname syntax
- Documented findings for future reference

## MIR Documentation Enhancements
- Created comprehensive mir-dumper-guide.md for reading MIR dumps
- Enhanced mir-26-specification.md with BoxCall vs regular Call examples
- Added clear identification patterns:
  * BoxCall: `call %value.method(args)` (plugins/builtins)
  * Regular Call: `call %func(%me, args)` (user-defined boxes)

## VM Backend BoxRef Handling Improvements
- Fixed BoxRef method dispatch using share_box() instead of clone_box()
- Prevents unintended constructor calls during method resolution
- Maintains proper instance identity throughout VM execution

## MIR Builder User-Defined Box Tracking
- Added user_defined_boxes HashSet to track declared user boxes
- Improved method lowering decisions for user-defined vs builtin boxes
- Enhanced AST→MIR conversion accuracy for method calls

## Plugin Tester Lifecycle Enhancements
- Added comprehensive FileBox lifecycle testing (open/write/close)
- Enhanced cloneSelf() and copyFrom() testing with proper Handle parsing
- Added TLV encoding helpers for strings and bytes
- Improved error reporting and step-by-step validation

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm
2025-08-21 01:18:25 +09:00
parent cc2a820af7
commit 2200312f09
5 changed files with 183 additions and 49 deletions

View File

@ -11,6 +11,7 @@ use super::{
};
use crate::ast::{ASTNode, LiteralValue, BinaryOperator};
use std::collections::HashMap;
use std::collections::HashSet;
/// MIR builder for converting AST to SSA form
pub struct MirBuilder {
@ -39,6 +40,9 @@ pub struct MirBuilder {
/// Origin tracking for simple optimizations (e.g., object.method after new)
/// Maps a ValueId to the class name if it was produced by NewBox of that class
pub(super) value_origin_newbox: HashMap<ValueId, String>,
/// Names of user-defined boxes declared in the current module
pub(super) user_defined_boxes: HashSet<String>,
}
impl MirBuilder {
@ -53,6 +57,7 @@ impl MirBuilder {
variable_map: HashMap::new(),
pending_phis: Vec::new(),
value_origin_newbox: HashMap::new(),
user_defined_boxes: HashSet::new(),
}
}
@ -299,6 +304,8 @@ impl MirBuilder {
self.build_static_main_box(methods.clone())
} else {
// Support user-defined boxes - handle as statement, return void
// Track as user-defined (eligible for method lowering)
self.user_defined_boxes.insert(name.clone());
self.build_box_declaration(name.clone(), methods.clone(), fields.clone())?;
// Phase 2: Lower constructors (birth/N) into MIR functions
@ -993,7 +1000,8 @@ impl MirBuilder {
if let ASTNode::New { class, .. } = object {
// Build function name and only lower to Call if the function exists (user-defined)
let func_name = format!("{}.{}{}", class, method, format!("/{}", arg_values.len()));
let can_lower = if let Some(ref module) = self.current_module { module.functions.contains_key(&func_name) } else { false };
let can_lower = self.user_defined_boxes.contains(&class)
&& if let Some(ref module) = self.current_module { module.functions.contains_key(&func_name) } else { false };
if can_lower {
let func_val = self.value_gen.next();
self.emit_instruction(MirInstruction::Const { dst: func_val, value: ConstValue::String(func_name) })?;
@ -1013,7 +1021,8 @@ impl MirBuilder {
// If the object originates from a NewBox in this function, we can lower to Call as well
if let Some(class_name) = self.value_origin_newbox.get(&object_value).cloned() {
let func_name = format!("{}.{}{}", class_name, method, format!("/{}", arg_values.len()));
let can_lower = if let Some(ref module) = self.current_module { module.functions.contains_key(&func_name) } else { false };
let can_lower = self.user_defined_boxes.contains(&class_name)
&& if let Some(ref module) = self.current_module { module.functions.contains_key(&func_name) } else { false };
if can_lower {
let func_val = self.value_gen.next();
self.emit_instruction(MirInstruction::Const { dst: func_val, value: ConstValue::String(func_name) })?;