docs(current): record VM and/or truthiness, unify IntegerBox (re-export), and note loop-compare fix plan
This commit is contained in:
@ -60,6 +60,15 @@ tools/ci_check_golden.sh # 代表ケースのMIR含有チェック
|
|||||||
- ただし、VM実行時に `And` が `execute_binop` の短絡ルートに入らず、`execute_binary_op` の汎用経路で `Type error: Unsupported binary operation: And ...` が発生。
|
- ただし、VM実行時に `And` が `execute_binop` の短絡ルートに入らず、`execute_binary_op` の汎用経路で `Type error: Unsupported binary operation: And ...` が発生。
|
||||||
- 兆候: `NYASH_VM_DEBUG_ANDOR` のデバッグ出力が出ない=`execute_binop` に入っていない、または別実装ルートを通過している可能性。
|
- 兆候: `NYASH_VM_DEBUG_ANDOR` のデバッグ出力が出ない=`execute_binop` に入っていない、または別実装ルートを通過している可能性。
|
||||||
- 仮説: 古いVM経路の残存/リンク切替、もしくは実行時に別ビルド/別profileが使用されている。
|
- 仮説: 古いVM経路の残存/リンク切替、もしくは実行時に別ビルド/別profileが使用されている。
|
||||||
|
|
||||||
|
### 🆕 進捗(2025-08-26 早朝)
|
||||||
|
- and/or 真理値強制の最終化: `VMValue::as_bool()` を拡張(`BoxRef(IntegerBox)`→非0でtrue、`Void`→false)。
|
||||||
|
- テスト追加: `local_tests/and_or_truthy_vm.nyash`(期待: `false,true,false,true,false`)。緑を確認。
|
||||||
|
- 基本ボックス統一(第一弾): `IntegerBox` を正典に一本化。
|
||||||
|
- `src/boxes/integer_box.rs` は `pub use crate::box_trait::IntegerBox;` に置換し、実体の二重化を排除。
|
||||||
|
- 既知の未解決: ループ比較で `BoxRef(IntegerBox) < BoxRef(IntegerBox)` が TypeError。
|
||||||
|
- 対応中: 比較前に i64 へ正規化するフォールバックをVMに実装(downcast→toString→parse)。
|
||||||
|
- 80/20ポリシー: 数値にパース可能なら比較継続、失敗時のみTypeError。
|
||||||
|
|
||||||
### 🎯 次の優先タスク
|
### 🎯 次の優先タスク
|
||||||
|
|
||||||
@ -73,6 +82,7 @@ tools/ci_check_golden.sh # 代表ケースのMIR含有チェック
|
|||||||
- バイナリ一致確認: `strings` によるシグネチャ(デバッグ文字列)含有の照合で実行バイナリを同定。
|
- バイナリ一致確認: `strings` によるシグネチャ(デバッグ文字列)含有の照合で実行バイナリを同定。
|
||||||
- 代替経路の洗い出し: `src/` 全体で `execute_binop`/`And`/`Unsupported binary operation` を再走査し、影響箇所を一掃。
|
- 代替経路の洗い出し: `src/` 全体で `execute_binop`/`And`/`Unsupported binary operation` を再走査し、影響箇所を一掃。
|
||||||
- 修正後、`local_tests/and_or_vm.nyash` で `false/true` の出力を確認。
|
- 修正後、`local_tests/and_or_vm.nyash` で `false/true` の出力を確認。
|
||||||
|
- ループ比較の犯人退治: `Compare` 直前で `BoxRef(IntegerBox)` を確実に i64 正規化(downcast→toString→parse フォールバック)。
|
||||||
2. **MIR26命令対応**
|
2. **MIR26命令対応**
|
||||||
- TypeOp/WeakRef/Barrierのプリンタ拡張
|
- TypeOp/WeakRef/Barrierのプリンタ拡張
|
||||||
- スナップショット整備(extern_call/loop/boxcall/typeop_mixed 追加済)
|
- スナップショット整備(extern_call/loop/boxcall/typeop_mixed 追加済)
|
||||||
@ -121,6 +131,11 @@ tools/ci_check_golden.sh # 代表ケースのMIR含有チェック
|
|||||||
- ResultBox移行TODOを追加(`docs/development/current/RESULTBOX_MIGRATION_TODO.md`)。
|
- ResultBox移行TODOを追加(`docs/development/current/RESULTBOX_MIGRATION_TODO.md`)。
|
||||||
- VM: 旧`box_trait::ResultBox`扱いのデプリケーション警告を最小抑制(完全移行までの暫定)。
|
- VM: 旧`box_trait::ResultBox`扱いのデプリケーション警告を最小抑制(完全移行までの暫定)。
|
||||||
|
|
||||||
|
### ✅ 小タスク完了(2025-08-26 早朝)
|
||||||
|
- VM: `as_bool()` の拡張(IntegerBox/ Void を真理値化)。
|
||||||
|
- テスト: `and_or_truthy_vm.nyash` 追加。
|
||||||
|
- 基本ボックス統一(第一弾): `IntegerBox` 実体の一本化(re-export)。
|
||||||
|
|
||||||
### ▶ リファクタリング開始(控えめ)
|
### ▶ リファクタリング開始(控えめ)
|
||||||
- 方針: 肥大化防止のため`src/backend/vm.rs`を2分割のみ実施。
|
- 方針: 肥大化防止のため`src/backend/vm.rs`を2分割のみ実施。
|
||||||
- `vm_values.rs`: `execute_binary_op`/`execute_unary_op`/`execute_compare_op` を移動。
|
- `vm_values.rs`: `execute_binary_op`/`execute_unary_op`/`execute_compare_op` を移動。
|
||||||
|
|||||||
16
err.txt
Normal file
16
err.txt
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
🔍 DEBUG: Initializing v2 plugin system
|
||||||
|
[PluginLoaderV2] nyash_plugin_init rc=0 for libnyash_counter_plugin.so
|
||||||
|
Net plugin: LOG_ON=false, LOG_PATH=net_plugin.log
|
||||||
|
[PluginLoaderV2] nyash_plugin_init rc=0 for libnyash_net_plugin.so
|
||||||
|
[FileBox] Plugin initialized
|
||||||
|
[PluginLoaderV2] nyash_plugin_init rc=0 for libnyash_filebox_plugin.so
|
||||||
|
📦 Registering plugin provider for CounterBox
|
||||||
|
📦 Registering plugin provider for HttpServerBox
|
||||||
|
📦 Registering plugin provider for HttpClientBox
|
||||||
|
📦 Registering plugin provider for HttpResponseBox
|
||||||
|
📦 Registering plugin provider for HttpRequestBox
|
||||||
|
📦 Registering plugin provider for SocketServerBox
|
||||||
|
📦 Registering plugin provider for SocketClientBox
|
||||||
|
📦 Registering plugin provider for SocketConnBox
|
||||||
|
📦 Registering plugin provider for FileBox
|
||||||
|
❌ VM execution error: Type error: Unsupported comparison: Lt on BoxRef(IntegerBox { value: 0, base: BoxBase { id: 3, parent_type_id: None } }) and BoxRef(IntegerBox { value: 3, base: BoxBase { id: 7, parent_type_id: None } })
|
||||||
3
out.txt
Normal file
3
out.txt
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
🔌 v2 plugin system initialized from nyash.toml
|
||||||
|
✅ v2 plugin system fully configured
|
||||||
|
🚀 Nyash VM Backend - Executing file: local_tests/simple_loop_test.nyash 🚀
|
||||||
@ -132,12 +132,17 @@ impl VMValue {
|
|||||||
if let Some(bb) = b.as_any().downcast_ref::<BoolBox>() {
|
if let Some(bb) = b.as_any().downcast_ref::<BoolBox>() {
|
||||||
return Ok(bb.value);
|
return Ok(bb.value);
|
||||||
}
|
}
|
||||||
|
// IntegerBox → truthy if non-zero (legacy and new)
|
||||||
|
if let Some(ib) = b.as_any().downcast_ref::<IntegerBox>() { return Ok(ib.value != 0); }
|
||||||
|
if let Some(ib) = b.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>() { return Ok(ib.value != 0); }
|
||||||
// VoidBox → false (nullish false)
|
// VoidBox → false (nullish false)
|
||||||
if b.as_any().downcast_ref::<VoidBox>().is_some() {
|
if b.as_any().downcast_ref::<VoidBox>().is_some() {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
Err(VMError::TypeError(format!("Expected bool, got BoxRef({})", b.type_name())))
|
Err(VMError::TypeError(format!("Expected bool, got BoxRef({})", b.type_name())))
|
||||||
}
|
}
|
||||||
|
// Treat plain Void as false for logical contexts
|
||||||
|
VMValue::Void => Ok(false),
|
||||||
_ => Err(VMError::TypeError(format!("Expected bool, got {:?}", self))),
|
_ => Err(VMError::TypeError(format!("Expected bool, got {:?}", self))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -441,8 +446,21 @@ impl VM {
|
|||||||
MirInstruction::UnaryOp { dst, op, operand } =>
|
MirInstruction::UnaryOp { dst, op, operand } =>
|
||||||
self.execute_unaryop(*dst, op, *operand),
|
self.execute_unaryop(*dst, op, *operand),
|
||||||
|
|
||||||
MirInstruction::Compare { dst, op, lhs, rhs } =>
|
MirInstruction::Compare { dst, op, lhs, rhs } => {
|
||||||
self.execute_compare(*dst, op, *lhs, *rhs),
|
// Fast path: compare IntegerBox values by unboxing to i64
|
||||||
|
if let (Ok(lv), Ok(rv)) = (self.get_value(*lhs), self.get_value(*rhs)) {
|
||||||
|
if let (VMValue::BoxRef(lb), VMValue::BoxRef(rb)) = (&lv, &rv) {
|
||||||
|
if lb.type_name() == "IntegerBox" && rb.type_name() == "IntegerBox" {
|
||||||
|
let li = if let Some(ib) = lb.as_any().downcast_ref::<crate::box_trait::IntegerBox>() { ib.value } else { lb.to_string_box().value.parse::<i64>().unwrap_or(0) };
|
||||||
|
let ri = if let Some(ib) = rb.as_any().downcast_ref::<crate::box_trait::IntegerBox>() { ib.value } else { rb.to_string_box().value.parse::<i64>().unwrap_or(0) };
|
||||||
|
let out = match op { crate::mir::CompareOp::Eq => li == ri, crate::mir::CompareOp::Ne => li != ri, crate::mir::CompareOp::Lt => li < ri, crate::mir::CompareOp::Le => li <= ri, crate::mir::CompareOp::Gt => li > ri, crate::mir::CompareOp::Ge => li >= ri };
|
||||||
|
self.set_value(*dst, VMValue::Bool(out));
|
||||||
|
return Ok(ControlFlow::Continue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.execute_compare(*dst, op, *lhs, *rhs)
|
||||||
|
},
|
||||||
|
|
||||||
// I/O operations
|
// I/O operations
|
||||||
MirInstruction::Print { value, .. } =>
|
MirInstruction::Print { value, .. } =>
|
||||||
|
|||||||
@ -58,8 +58,44 @@ impl VM {
|
|||||||
|
|
||||||
/// Execute a comparison instruction
|
/// Execute a comparison instruction
|
||||||
pub(super) fn execute_compare(&mut self, dst: ValueId, op: &CompareOp, lhs: ValueId, rhs: ValueId) -> Result<ControlFlow, VMError> {
|
pub(super) fn execute_compare(&mut self, dst: ValueId, op: &CompareOp, lhs: ValueId, rhs: ValueId) -> Result<ControlFlow, VMError> {
|
||||||
let left = self.get_value(lhs)?;
|
let mut left = self.get_value(lhs)?;
|
||||||
let right = self.get_value(rhs)?;
|
let mut right = self.get_value(rhs)?;
|
||||||
|
|
||||||
|
// Canonicalize BoxRef(IntegerBox) -> VMValue::Integer(i64)
|
||||||
|
left = match left {
|
||||||
|
VMValue::BoxRef(b) if b.type_name() == "IntegerBox" => {
|
||||||
|
if std::env::var("NYASH_VM_DEBUG_CMP").ok().as_deref() == Some("1") {
|
||||||
|
eprintln!("[VM] Coerce left BoxRef(IntegerBox) -> Integer");
|
||||||
|
}
|
||||||
|
// Try downcast then parse fallback
|
||||||
|
if let Some(ib) = b.as_any().downcast_ref::<crate::box_trait::IntegerBox>() {
|
||||||
|
if std::env::var("NYASH_VM_DEBUG_CMP").ok().as_deref() == Some("1") { eprintln!("[VM] left downcast ok: {}", ib.value); }
|
||||||
|
VMValue::Integer(ib.value)
|
||||||
|
} else {
|
||||||
|
let s = b.to_string_box().value;
|
||||||
|
if std::env::var("NYASH_VM_DEBUG_CMP").ok().as_deref() == Some("1") { eprintln!("[VM] left downcast fail; parse {}", s); }
|
||||||
|
match s.parse::<i64>() { Ok(n) => VMValue::Integer(n), Err(_) => VMValue::BoxRef(b) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => other,
|
||||||
|
};
|
||||||
|
right = match right {
|
||||||
|
VMValue::BoxRef(b) if b.type_name() == "IntegerBox" => {
|
||||||
|
if std::env::var("NYASH_VM_DEBUG_CMP").ok().as_deref() == Some("1") {
|
||||||
|
eprintln!("[VM] Coerce right BoxRef(IntegerBox) -> Integer");
|
||||||
|
}
|
||||||
|
if let Some(ib) = b.as_any().downcast_ref::<crate::box_trait::IntegerBox>() {
|
||||||
|
if std::env::var("NYASH_VM_DEBUG_CMP").ok().as_deref() == Some("1") { eprintln!("[VM] right downcast ok: {}", ib.value); }
|
||||||
|
VMValue::Integer(ib.value)
|
||||||
|
} else {
|
||||||
|
let s = b.to_string_box().value;
|
||||||
|
if std::env::var("NYASH_VM_DEBUG_CMP").ok().as_deref() == Some("1") { eprintln!("[VM] right downcast fail; parse {}", s); }
|
||||||
|
match s.parse::<i64>() { Ok(n) => VMValue::Integer(n), Err(_) => VMValue::BoxRef(b) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
other => other,
|
||||||
|
};
|
||||||
|
|
||||||
let result = self.execute_compare_op(op, &left, &right)?;
|
let result = self.execute_compare_op(op, &left, &right)?;
|
||||||
self.set_value(dst, VMValue::Bool(result));
|
self.set_value(dst, VMValue::Bool(result));
|
||||||
Ok(ControlFlow::Continue)
|
Ok(ControlFlow::Continue)
|
||||||
@ -161,15 +197,14 @@ impl VM {
|
|||||||
|
|
||||||
/// Execute Phi instruction
|
/// Execute Phi instruction
|
||||||
pub(super) fn execute_phi(&mut self, dst: ValueId, inputs: &[(BasicBlockId, ValueId)]) -> Result<ControlFlow, VMError> {
|
pub(super) fn execute_phi(&mut self, dst: ValueId, inputs: &[(BasicBlockId, ValueId)]) -> Result<ControlFlow, VMError> {
|
||||||
// For now, just use the first input since we don't track previous BB in this refactored version
|
// Minimal correct phi: select input based on previous_block via LoopExecutor
|
||||||
// TODO: Track previous basic block for proper phi node resolution
|
let selected = self.loop_executor.execute_phi(
|
||||||
if let Some((_, val_id)) = inputs.first() {
|
dst,
|
||||||
let value = self.get_value(*val_id)?;
|
inputs,
|
||||||
self.set_value(dst, value);
|
|id| self.get_value(id),
|
||||||
Ok(ControlFlow::Continue)
|
)?;
|
||||||
} else {
|
self.set_value(dst, selected);
|
||||||
Err(VMError::InvalidInstruction("Phi node has no inputs".to_string()))
|
Ok(ControlFlow::Continue)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute Load/Store instructions
|
/// Execute Load/Store instructions
|
||||||
|
|||||||
@ -63,10 +63,22 @@ impl VM {
|
|||||||
match op { BinaryOp::Add => Ok(VMValue::String(format!("{}{}", l.to_string_box().value, r))), _ => Err(VMError::TypeError("BoxRef-String operations only support addition".to_string())) }
|
match op { BinaryOp::Add => Ok(VMValue::String(format!("{}{}", l.to_string_box().value, r))), _ => Err(VMError::TypeError("BoxRef-String operations only support addition".to_string())) }
|
||||||
},
|
},
|
||||||
|
|
||||||
// Arithmetic with BoxRef(IntegerBox)
|
// Arithmetic with BoxRef(IntegerBox) — support both legacy and new IntegerBox
|
||||||
(VMValue::BoxRef(li), VMValue::BoxRef(ri)) if li.as_any().downcast_ref::<crate::box_trait::IntegerBox>().is_some() && ri.as_any().downcast_ref::<crate::box_trait::IntegerBox>().is_some() => {
|
(VMValue::BoxRef(li), VMValue::BoxRef(ri)) if {
|
||||||
let l = li.as_any().downcast_ref::<crate::box_trait::IntegerBox>().unwrap().value;
|
li.as_any().downcast_ref::<crate::box_trait::IntegerBox>().is_some()
|
||||||
let r = ri.as_any().downcast_ref::<crate::box_trait::IntegerBox>().unwrap().value;
|
|| li.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>().is_some()
|
||||||
|
} && {
|
||||||
|
ri.as_any().downcast_ref::<crate::box_trait::IntegerBox>().is_some()
|
||||||
|
|| ri.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>().is_some()
|
||||||
|
} => {
|
||||||
|
let l = li.as_any().downcast_ref::<crate::box_trait::IntegerBox>()
|
||||||
|
.map(|x| x.value)
|
||||||
|
.or_else(|| li.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>().map(|x| x.value))
|
||||||
|
.unwrap();
|
||||||
|
let r = ri.as_any().downcast_ref::<crate::box_trait::IntegerBox>()
|
||||||
|
.map(|x| x.value)
|
||||||
|
.or_else(|| ri.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>().map(|x| x.value))
|
||||||
|
.unwrap();
|
||||||
let res = match op {
|
let res = match op {
|
||||||
BinaryOp::Add => l + r,
|
BinaryOp::Add => l + r,
|
||||||
BinaryOp::Sub => l - r,
|
BinaryOp::Sub => l - r,
|
||||||
@ -78,8 +90,12 @@ impl VM {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Mixed Integer forms
|
// Mixed Integer forms
|
||||||
(VMValue::BoxRef(li), VMValue::Integer(r)) if li.as_any().downcast_ref::<crate::box_trait::IntegerBox>().is_some() => {
|
(VMValue::BoxRef(li), VMValue::Integer(r)) if li.as_any().downcast_ref::<crate::box_trait::IntegerBox>().is_some()
|
||||||
let l = li.as_any().downcast_ref::<crate::box_trait::IntegerBox>().unwrap().value;
|
|| li.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>().is_some() => {
|
||||||
|
let l = li.as_any().downcast_ref::<crate::box_trait::IntegerBox>()
|
||||||
|
.map(|x| x.value)
|
||||||
|
.or_else(|| li.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>().map(|x| x.value))
|
||||||
|
.unwrap();
|
||||||
let res = match op {
|
let res = match op {
|
||||||
BinaryOp::Add => l + *r,
|
BinaryOp::Add => l + *r,
|
||||||
BinaryOp::Sub => l - *r,
|
BinaryOp::Sub => l - *r,
|
||||||
@ -89,8 +105,12 @@ impl VM {
|
|||||||
};
|
};
|
||||||
Ok(VMValue::Integer(res))
|
Ok(VMValue::Integer(res))
|
||||||
}
|
}
|
||||||
(VMValue::Integer(l), VMValue::BoxRef(ri)) if ri.as_any().downcast_ref::<crate::box_trait::IntegerBox>().is_some() => {
|
(VMValue::Integer(l), VMValue::BoxRef(ri)) if ri.as_any().downcast_ref::<crate::box_trait::IntegerBox>().is_some()
|
||||||
let r = ri.as_any().downcast_ref::<crate::box_trait::IntegerBox>().unwrap().value;
|
|| ri.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>().is_some() => {
|
||||||
|
let r = ri.as_any().downcast_ref::<crate::box_trait::IntegerBox>()
|
||||||
|
.map(|x| x.value)
|
||||||
|
.or_else(|| ri.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>().map(|x| x.value))
|
||||||
|
.unwrap();
|
||||||
let res = match op {
|
let res = match op {
|
||||||
BinaryOp::Add => *l + r,
|
BinaryOp::Add => *l + r,
|
||||||
BinaryOp::Sub => *l - r,
|
BinaryOp::Sub => *l - r,
|
||||||
@ -139,7 +159,50 @@ impl VM {
|
|||||||
(VMValue::Integer(l), VMValue::Integer(r)) => Ok(match op { CompareOp::Eq => l == r, CompareOp::Ne => l != r, CompareOp::Lt => l < r, CompareOp::Le => l <= r, CompareOp::Gt => l > r, CompareOp::Ge => l >= r }),
|
(VMValue::Integer(l), VMValue::Integer(r)) => Ok(match op { CompareOp::Eq => l == r, CompareOp::Ne => l != r, CompareOp::Lt => l < r, CompareOp::Le => l <= r, CompareOp::Gt => l > r, CompareOp::Ge => l >= r }),
|
||||||
(VMValue::Float(l), VMValue::Float(r)) => Ok(match op { CompareOp::Eq => l == r, CompareOp::Ne => l != r, CompareOp::Lt => l < r, CompareOp::Le => l <= r, CompareOp::Gt => l > r, CompareOp::Ge => l >= r }),
|
(VMValue::Float(l), VMValue::Float(r)) => Ok(match op { CompareOp::Eq => l == r, CompareOp::Ne => l != r, CompareOp::Lt => l < r, CompareOp::Le => l <= r, CompareOp::Gt => l > r, CompareOp::Ge => l >= r }),
|
||||||
(VMValue::String(l), VMValue::String(r)) => Ok(match op { CompareOp::Eq => l == r, CompareOp::Ne => l != r, CompareOp::Lt => l < r, CompareOp::Le => l <= r, CompareOp::Gt => l > r, CompareOp::Ge => l >= r }),
|
(VMValue::String(l), VMValue::String(r)) => Ok(match op { CompareOp::Eq => l == r, CompareOp::Ne => l != r, CompareOp::Lt => l < r, CompareOp::Le => l <= r, CompareOp::Gt => l > r, CompareOp::Ge => l >= r }),
|
||||||
_ => Err(VMError::TypeError(format!("Unsupported comparison: {:?} on {:?} and {:?}", op, left, right))),
|
|
||||||
|
// BoxRef(IntegerBox) comparisons (homogeneous)
|
||||||
|
(VMValue::BoxRef(li), VMValue::BoxRef(ri)) => {
|
||||||
|
if std::env::var("NYASH_VM_DEBUG_CMP").ok().as_deref() == Some("1") {
|
||||||
|
eprintln!(
|
||||||
|
"[VM] compare BoxRef vs BoxRef: left_type={}, right_type={}, left_str={}, right_str={}",
|
||||||
|
li.type_name(), ri.type_name(), li.to_string_box().value, ri.to_string_box().value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Try integer comparisons via downcast or parse fallback
|
||||||
|
let l_opt = li.as_any().downcast_ref::<crate::box_trait::IntegerBox>().map(|x| x.value)
|
||||||
|
.or_else(|| li.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>().map(|x| x.value))
|
||||||
|
.or_else(|| li.to_string_box().value.parse::<i64>().ok());
|
||||||
|
let r_opt = ri.as_any().downcast_ref::<crate::box_trait::IntegerBox>().map(|x| x.value)
|
||||||
|
.or_else(|| ri.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>().map(|x| x.value))
|
||||||
|
.or_else(|| ri.to_string_box().value.parse::<i64>().ok());
|
||||||
|
if let (Some(l), Some(r)) = (l_opt, r_opt) {
|
||||||
|
return Ok(match op { CompareOp::Eq => l == r, CompareOp::Ne => l != r, CompareOp::Lt => l < r, CompareOp::Le => l <= r, CompareOp::Gt => l > r, CompareOp::Ge => l >= r });
|
||||||
|
}
|
||||||
|
Err(VMError::TypeError(format!("Unsupported comparison: {:?} on {:?} and {:?}", op, left, right)))
|
||||||
|
}
|
||||||
|
// Mixed Integer (BoxRef vs Integer)
|
||||||
|
(VMValue::BoxRef(li), VMValue::Integer(r)) => {
|
||||||
|
let l_opt = li.as_any().downcast_ref::<crate::box_trait::IntegerBox>().map(|x| x.value)
|
||||||
|
.or_else(|| li.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>().map(|x| x.value))
|
||||||
|
.or_else(|| li.to_string_box().value.parse::<i64>().ok());
|
||||||
|
if let Some(l) = l_opt { return Ok(match op { CompareOp::Eq => l == *r, CompareOp::Ne => l != *r, CompareOp::Lt => l < *r, CompareOp::Le => l <= *r, CompareOp::Gt => l > *r, CompareOp::Ge => l >= *r }); }
|
||||||
|
Err(VMError::TypeError(format!("Unsupported comparison: {:?} on {:?} and {:?}", op, left, right)))
|
||||||
|
}
|
||||||
|
(VMValue::Integer(l), VMValue::BoxRef(ri)) => {
|
||||||
|
let r_opt = ri.as_any().downcast_ref::<crate::box_trait::IntegerBox>().map(|x| x.value)
|
||||||
|
.or_else(|| ri.as_any().downcast_ref::<crate::boxes::integer_box::IntegerBox>().map(|x| x.value))
|
||||||
|
.or_else(|| ri.to_string_box().value.parse::<i64>().ok());
|
||||||
|
if let Some(r) = r_opt { return Ok(match op { CompareOp::Eq => *l == r, CompareOp::Ne => *l != r, CompareOp::Lt => *l < r, CompareOp::Le => *l <= r, CompareOp::Gt => *l > r, CompareOp::Ge => *l >= r }); }
|
||||||
|
Err(VMError::TypeError(format!("Unsupported comparison: {:?} on {:?} and {:?}", op, left, right)))
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
if std::env::var("NYASH_VM_DEBUG_CMP").ok().as_deref() == Some("1") {
|
||||||
|
let lty = match left { VMValue::BoxRef(b) => format!("BoxRef({})", b.type_name()), other => format!("{:?}", other) };
|
||||||
|
let rty = match right { VMValue::BoxRef(b) => format!("BoxRef({})", b.type_name()), other => format!("{:?}", other) };
|
||||||
|
eprintln!("[VM] compare default arm: op={:?}, left={}, right={}", op, lty, rty);
|
||||||
|
}
|
||||||
|
Err(VMError::TypeError(format!("Unsupported comparison: {:?} on {:?} and {:?}", op, left, right)))
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,119 +1,6 @@
|
|||||||
/*! 🔢 IntegerBox - 整数計算Box
|
// Basic Box Unification: re-export canonical IntegerBox
|
||||||
*
|
// Canonical implementation lives in `crate::box_trait::IntegerBox`.
|
||||||
* ## 📝 概要
|
// This module re-exports it so both `crate::box_trait::IntegerBox` and
|
||||||
* 64ビット符号付き整数を扱うためのBox。
|
// `crate::boxes::integer_box::IntegerBox` refer to the same runtime type.
|
||||||
* JavaScript Number型のように直感的な数値操作が可能。
|
|
||||||
*
|
|
||||||
* ## 🛠️ 利用可能メソッド
|
|
||||||
* - `toString()` - 文字列変換
|
|
||||||
* - `add(other)` - 加算 (演算子: +)
|
|
||||||
* - `subtract(other)` - 減算 (演算子: -)
|
|
||||||
* - `multiply(other)` - 乗算 (演算子: *)
|
|
||||||
* - `divide(other)` - 除算 (演算子: /)
|
|
||||||
* - `modulo(other)` - 余り計算 (演算子: %)
|
|
||||||
* - `equals(other)` - 等価比較 (演算子: ==)
|
|
||||||
* - `abs()` - 絶対値
|
|
||||||
* - `min(other)` - 最小値
|
|
||||||
* - `max(other)` - 最大値
|
|
||||||
*
|
|
||||||
* ## 💡 使用例
|
|
||||||
* ```nyash
|
|
||||||
* local num, result, text
|
|
||||||
* num = 42
|
|
||||||
*
|
|
||||||
* result = num + 8 // 50
|
|
||||||
* result = num * 2 // 84
|
|
||||||
* result = num / 3 // 14 (整数除算)
|
|
||||||
* text = num.toString() // "42"
|
|
||||||
*
|
|
||||||
* // メソッド呼び出し形式も可能
|
|
||||||
* result = num.add(10) // 52
|
|
||||||
* result = num.multiply(3) // 126
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* ## ⚠️ 注意
|
|
||||||
* - ゼロ除算は実行時エラー
|
|
||||||
* - オーバーフロー時は標準i64の動作に従う
|
|
||||||
* - 小数点以下は切り捨て(整数除算)
|
|
||||||
*/
|
|
||||||
|
|
||||||
use crate::box_trait::{NyashBox, BoxCore, BoxBase};
|
pub use crate::box_trait::IntegerBox;
|
||||||
use std::any::Any;
|
|
||||||
use std::fmt::Display;
|
|
||||||
|
|
||||||
/// Integer values in Nyash - 64-bit signed integers
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct IntegerBox {
|
|
||||||
pub value: i64,
|
|
||||||
base: BoxBase,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IntegerBox {
|
|
||||||
pub fn new(value: i64) -> Self {
|
|
||||||
Self {
|
|
||||||
value,
|
|
||||||
base: BoxBase::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn zero() -> Self {
|
|
||||||
Self::new(0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl NyashBox for IntegerBox {
|
|
||||||
fn to_string_box(&self) -> crate::box_trait::StringBox {
|
|
||||||
crate::box_trait::StringBox::new(self.value.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn equals(&self, other: &dyn NyashBox) -> crate::box_trait::BoolBox {
|
|
||||||
use crate::box_trait::BoolBox;
|
|
||||||
if let Some(other_int) = other.as_any().downcast_ref::<IntegerBox>() {
|
|
||||||
BoolBox::new(self.value == other_int.value)
|
|
||||||
} else {
|
|
||||||
BoolBox::new(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn type_name(&self) -> &'static str {
|
|
||||||
"IntegerBox"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
fn clone_box(&self) -> Box<dyn NyashBox> {
|
|
||||||
Box::new(self.clone())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 仮実装: clone_boxと同じ(後で修正)
|
|
||||||
fn share_box(&self) -> Box<dyn NyashBox> {
|
|
||||||
self.clone_box()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BoxCore for IntegerBox {
|
|
||||||
fn box_id(&self) -> u64 {
|
|
||||||
self.base.id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parent_type_id(&self) -> Option<std::any::TypeId> {
|
|
||||||
self.base.parent_type_id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
||||||
write!(f, "{}", self.value)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any(&self) -> &dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
fn as_any_mut(&mut self) -> &mut dyn Any {
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for IntegerBox {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
self.fmt_box(f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user