From 4aea27891ddc03943e9d139e9fd009d14d66685f Mon Sep 17 00:00:00 2001 From: nyash-codex Date: Tue, 18 Nov 2025 02:32:43 +0900 Subject: [PATCH] =?UTF-8?q?fix(mir):=20SSA=E9=81=95=E5=8F=8D=E4=BF=AE?= =?UTF-8?q?=E6=AD=A3=20&=20StringBox=20is=5Fspace/starts=5Fwith=E5=AE=9F?= =?UTF-8?q?=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Task A: ローカル変数SSA違反修正 - src/mir/builder/stmts.rs: Copy命令で一意ValueId割り当て - 元のエラー "Invalid value: use of undefined value" 解決 - using_resolver_box.hako が正常動作確認 Task B: StringBox新メソッド実装 - plugins/nyash-string-plugin: is_space/starts_with追加 - M_IS_SPACE (7), M_STARTS_WITH (8) 実装 - string_helpers.hako仕様に準拠 残存問題: do_break()のunreachableブロック生成 → 次のコミットで修正予定 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- plugins/nyash-string-plugin/src/lib.rs | 50 ++++++++++++++++++++++++++ src/mir/builder/stmts.rs | 20 +++++++++-- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/plugins/nyash-string-plugin/src/lib.rs b/plugins/nyash-string-plugin/src/lib.rs index fafaddf4..25d5ecbe 100644 --- a/plugins/nyash-string-plugin/src/lib.rs +++ b/plugins/nyash-string-plugin/src/lib.rs @@ -25,6 +25,8 @@ const M_CHAR_CODE_AT: u32 = 3; const M_CONCAT: u32 = 4; // concat(other: String|Handle) -> Handle(new) const M_FROM_UTF8: u32 = 5; // fromUtf8(data: String|Bytes) -> Handle(new) const M_TO_UTF8: u32 = 6; // toUtf8() -> String +const M_IS_SPACE: u32 = 7; // is_space(ch: String) -> bool +const M_STARTS_WITH: u32 = 8; // starts_with(src: String, i: i64, pat: String) -> bool const M_FINI: u32 = u32::MAX; const TYPE_ID_STRING: u32 = 10; // Match nyash.toml type_id @@ -223,6 +225,8 @@ extern "C" fn string_resolve(name: *const c_char) -> u32 { "concat" => M_CONCAT, "fromUtf8" => M_FROM_UTF8, "toUtf8" | "toString" => M_TO_UTF8, // Map toString to toUtf8 + "is_space" => M_IS_SPACE, + "starts_with" => M_STARTS_WITH, _ => 0, } } @@ -331,6 +335,52 @@ extern "C" fn string_invoke_id( return E_PLUGIN; } } + M_IS_SPACE => { + // is_space(ch: String) -> bool + // Check if single character is whitespace: " ", "\t", "\n", "\r" + let ch = match read_arg_string(args, args_len, 0) { + Some(s) => s, + None => return E_ARGS, + }; + let is_space = ch == " " || ch == "\t" || ch == "\n" || ch == "\r"; + return write_tlv_bool(is_space, result, result_len); + } + M_STARTS_WITH => { + // starts_with(src: String, i: i64, pat: String) -> bool + // Check if 'src' starts with 'pat' at position 'i' + // Args: [0] = src (String), [1] = i (i64), [2] = pat (String) + let src = match read_arg_string(args, args_len, 0) { + Some(s) => s, + None => return E_ARGS, + }; + let i = match read_arg_i64(args, args_len, 1) { + Some(v) if v >= 0 => v as usize, + _ => return E_ARGS, + }; + let pat = match read_arg_string(args, args_len, 2) { + Some(s) => s, + None => return E_ARGS, + }; + + let src_len = src.len(); + let pat_len = pat.len(); + + // Check bounds: i + pat.length() > src.length() → false + if i + pat_len > src_len { + return write_tlv_bool(false, result, result_len); + } + + // Character-by-character comparison + let src_bytes = src.as_bytes(); + let pat_bytes = pat.as_bytes(); + for k in 0..pat_len { + if src_bytes[i + k] != pat_bytes[k] { + return write_tlv_bool(false, result, result_len); + } + } + + return write_tlv_bool(true, result, result_len); + } _ => E_METHOD, } } diff --git a/src/mir/builder/stmts.rs b/src/mir/builder/stmts.rs index 30c6e75a..99f9947b 100644 --- a/src/mir/builder/stmts.rs +++ b/src/mir/builder/stmts.rs @@ -193,18 +193,32 @@ impl super::MirBuilder { let mut last_value = None; for (i, var_name) in variables.iter().enumerate() { let var_id = if i < initial_values.len() && initial_values[i].is_some() { - // Use initializer's ValueId directly to avoid SSA aliasing/undefined use + // Evaluate the initializer expression let init_expr = initial_values[i].as_ref().unwrap(); let init_val = self.build_expression(*init_expr.clone())?; - init_val + + // FIX: Allocate a new ValueId for this local variable + // and emit a Copy instruction to establish SSA form + let var_id = self.value_gen.next(); + + self.emit_instruction(crate::mir::MirInstruction::Copy { + dst: var_id, + src: init_val + })?; + + // Propagate metadata (type/origin) from initializer to variable + crate::mir::builder::metadata::propagate::propagate(self, init_val, var_id); + + var_id } else { // Create a concrete register for uninitialized locals (Void) crate::mir::builder::emission::constant::emit_void(self) }; + self.variable_map.insert(var_name.clone(), var_id); last_value = Some(var_id); } - Ok(last_value.unwrap_or_else(|| self.next_value_id())) + Ok(last_value.unwrap_or_else(|| self.value_gen.next())) } // Return statement