A1.4: Add sugar syntax `public weak parent` ≡ `public { weak parent }`
A1.5: Fix parser hang on unsupported `param: Type` syntax
Key changes:
- A1.4: Extend visibility parser to handle weak modifier (fields.rs)
- A1.5: Shared helper `parse_param_name_list()` with progress-zero detection
- A1.5: Fix 6 vulnerable parameter parsing loops (methods, constructors, functions)
- Tests: Sugar syntax (OK/NG), parser hang (timeout-based)
- Docs: lifecycle.md, EBNF.md, phase-285a1-boxification.md
Additional changes:
- weak() builtin implementation (handlers/weak.rs)
- Leak tracking improvements (leak_tracker.rs)
- Documentation updates (lifecycle, types, memory-finalization, etc.)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
128 lines
4.9 KiB
Rust
128 lines
4.9 KiB
Rust
/*!
|
|
* Backend ABI/utility consolidation (minimal)
|
|
*
|
|
* Shared helpers for handle/ptr/to_bool/compare/tag/invoke scaffolding.
|
|
* Initial scope focuses on value coercions used by the MIR interpreter and JIT.
|
|
*/
|
|
|
|
use crate::backend::vm::VMValue;
|
|
use crate::box_trait::{BoolBox, IntegerBox, NyashBox, StringBox, VoidBox};
|
|
use std::sync::Arc;
|
|
|
|
/// Opaque handle type used by JIT/runtime bridges.
|
|
pub type Handle = u64;
|
|
|
|
/// Convert a VMValue to boolean using unified, fail-fast semantics (Phase 275 A1).
|
|
pub fn to_bool_vm(v: &VMValue) -> Result<bool, String> {
|
|
match v {
|
|
VMValue::Bool(b) => Ok(*b),
|
|
VMValue::Integer(i) => Ok(*i != 0),
|
|
VMValue::Void => Err("Void in boolean context".to_string()),
|
|
VMValue::String(s) => Ok(!s.is_empty()),
|
|
VMValue::Float(f) => Ok(*f != 0.0),
|
|
VMValue::BoxRef(b) => {
|
|
// Bridge boxes: allow unboxing to primitive for truthiness
|
|
if let Some(bb) = b.as_any().downcast_ref::<BoolBox>() {
|
|
return Ok(bb.value);
|
|
}
|
|
if let Some(ib) = b.as_any().downcast_ref::<IntegerBox>() {
|
|
return Ok(ib.value != 0);
|
|
}
|
|
if let Some(sb) = b.as_any().downcast_ref::<StringBox>() {
|
|
return Ok(!sb.value.is_empty());
|
|
}
|
|
// VoidBox treated as Void → TypeError
|
|
if b.as_any().downcast_ref::<VoidBox>().is_some() {
|
|
return Err("VoidBox in boolean context".to_string());
|
|
}
|
|
Err(format!("cannot coerce BoxRef({}) to bool", b.type_name()))
|
|
}
|
|
VMValue::Future(_) => Err("cannot coerce Future to bool".to_string()),
|
|
// Phase 285A0: WeakRef in boolean context is TypeError
|
|
VMValue::WeakBox(_) => Err("WeakRef in boolean context - use upgrade() first".to_string()),
|
|
}
|
|
}
|
|
|
|
/// Nyash-style equality on VMValue with precise number-only coercion (Phase 275 B2).
|
|
pub fn eq_vm(a: &VMValue, b: &VMValue) -> bool {
|
|
use VMValue::*;
|
|
match (a, b) {
|
|
(Integer(x), Integer(y)) => x == y,
|
|
(Float(x), Float(y)) => x == y,
|
|
(Bool(x), Bool(y)) => x == y,
|
|
(String(x), String(y)) => x == y,
|
|
(Void, Void) => true,
|
|
// Precise Int↔Float equality (avoid accidental true via float rounding)
|
|
(Integer(x), Float(y)) | (Float(y), Integer(x)) => {
|
|
if y.is_nan() {
|
|
return false;
|
|
}
|
|
if y.is_finite() && y.fract() == 0.0 {
|
|
// Float is integral - check exact representability
|
|
let y_int = *y as i64;
|
|
if (y_int as f64) == *y {
|
|
return x == &y_int;
|
|
}
|
|
}
|
|
false
|
|
}
|
|
(BoxRef(ax), BoxRef(by)) => Arc::ptr_eq(ax, by),
|
|
// Treat BoxRef(VoidBox/MissingBox) as equal to Void (null) for backward compatibility
|
|
(BoxRef(bx), Void) => {
|
|
bx.as_any().downcast_ref::<VoidBox>().is_some()
|
|
|| bx
|
|
.as_any()
|
|
.downcast_ref::<crate::boxes::missing_box::MissingBox>()
|
|
.is_some()
|
|
}
|
|
(Void, BoxRef(bx)) => {
|
|
bx.as_any().downcast_ref::<VoidBox>().is_some()
|
|
|| bx
|
|
.as_any()
|
|
.downcast_ref::<crate::boxes::missing_box::MissingBox>()
|
|
.is_some()
|
|
}
|
|
// Phase 285A0: WeakBox equality
|
|
(WeakBox(wa), WeakBox(wb)) => {
|
|
match (wa.upgrade(), wb.upgrade()) {
|
|
(Some(arc_a), Some(arc_b)) => Arc::ptr_eq(&arc_a, &arc_b),
|
|
(None, None) => true, // Both dropped
|
|
_ => false,
|
|
}
|
|
}
|
|
// WeakBox == Void when dropped
|
|
(WeakBox(w), Void) | (Void, WeakBox(w)) => w.upgrade().is_none(),
|
|
_ => false,
|
|
}
|
|
}
|
|
|
|
/// Obtain a human-readable tag/type name for a VMValue.
|
|
pub fn tag_of_vm(v: &VMValue) -> &'static str {
|
|
match v {
|
|
VMValue::Integer(_) => "Integer",
|
|
VMValue::Float(_) => "Float",
|
|
VMValue::Bool(_) => "Bool",
|
|
VMValue::String(_) => "String",
|
|
VMValue::Future(_) => "Future",
|
|
VMValue::Void => "Void",
|
|
VMValue::BoxRef(_) => "BoxRef",
|
|
VMValue::WeakBox(_) => "WeakRef", // Phase 285A0
|
|
}
|
|
}
|
|
|
|
/// Wrap a NyashBox object into a handle using runtime handle registry.
|
|
/// This keeps a single handle mechanism across backends.
|
|
/// ARCHIVED: JIT handle implementation moved to archive/jit-cranelift/ during Phase 15
|
|
pub fn handle_of(_boxref: Arc<dyn NyashBox>) -> Handle {
|
|
// TODO: Implement handle registry for Phase 15 VM/LLVM backends
|
|
// For now, use a simple 0-handle placeholder
|
|
0
|
|
}
|
|
|
|
/// Try to resolve a handle back to a Box object.
|
|
/// ARCHIVED: JIT handle implementation moved to archive/jit-cranelift/ during Phase 15
|
|
pub fn handle_get(_h: Handle) -> Option<Arc<dyn NyashBox>> {
|
|
// TODO: Implement handle registry for Phase 15 VM/LLVM backends
|
|
None
|
|
}
|