cleanup: 不要なレガシーファイルを削除

- src/interpreter/method_dispatch.rs.legacy: 旧実装を削除
- tests/e2e_plugin_net.rs: archiveディレクトリに移動済み

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Moe Charm
2025-09-04 20:16:48 +09:00
parent 9a1db62238
commit c45866073d
2 changed files with 0 additions and 894 deletions

View File

@ -1,539 +0,0 @@
/*!
* Method Dispatch Module
*
* Extracted from expressions.rs lines 383-900 (~517 lines)
* Handles method call dispatch for all Box types and static function calls
* Core philosophy: "Everything is Box" with unified method dispatch
*/
use super::*;
use crate::boxes::{buffer::BufferBox, JSONBox, HttpClientBox, StreamBox, RegexBox, IntentBox, SocketBox, HTTPServerBox, HTTPRequestBox, HTTPResponseBox};
use crate::boxes::{FloatBox, MathBox, ConsoleBox, TimeBox, DateTimeBox, RandomBox, SoundBox, DebugBox, file::FileBox, MapBox};
use crate::bid::plugin_box::PluginFileBox;
use crate::runtime::plugin_loader_v2::PluginBoxV2;
use std::sync::Arc;
impl NyashInterpreter {
/// メソッド呼び出しを実行 - 全Box型の統一ディスパッチ
pub(super) fn execute_method_call(&mut self, object: &ASTNode, method: &str, arguments: &[ASTNode])
-> Result<Box<dyn NyashBox>, RuntimeError> {
// 🔥 static関数のチェック
if let ASTNode::Variable { name, .. } = object {
// static関数が存在するかチェック
let static_func = {
let static_funcs = self.shared.static_functions.read().unwrap();
if let Some(box_statics) = static_funcs.get(name) {
if let Some(func) = box_statics.get(method) {
Some(func.clone())
} else {
None
}
} else {
None
}
};
if let Some(static_func) = static_func {
return self.execute_static_function(static_func, name, method, arguments);
}
// 📚 nyashstd標準ライブラリのメソッドチェック
if let Some(stdlib_result) = self.try_execute_stdlib_method(name, method, arguments)? {
return Ok(stdlib_result);
}
}
// オブジェクトを評価(通常のメソッド呼び出し)
let obj_value = self.execute_expression(object)?;
// Fallback: built-in type ops as instance methods: value.is("Type"), value.as("Type")
if (method == "is" || method == "as") && arguments.len() == 1 {
let ty_box = self.execute_expression(&arguments[0])?;
let type_name = if let Some(s) = ty_box.as_any().downcast_ref::<crate::box_trait::StringBox>() {
s.value.clone()
} else {
return Err(RuntimeError::InvalidOperation { message: "Type name must be a string".to_string() });
};
if method == "is" {
let matched = super::functions::NyashInterpreter::matches_type_name(&obj_value, &type_name);
return Ok(Box::new(crate::box_trait::BoolBox::new(matched)));
} else {
return super::functions::NyashInterpreter::cast_to_type(obj_value, &type_name);
}
}
eprintln!("🔍 DEBUG: execute_method_call - object evaluated to type_name='{}', box_id={}",
obj_value.type_name(), obj_value.box_id());
// 各Box型に対するメソッドディスパッチ
self.dispatch_builtin_method(&obj_value, method, arguments, object)
}
/// static関数を実行
fn execute_static_function(
&mut self,
static_func: ASTNode,
box_name: &str,
method: &str,
arguments: &[ASTNode]
) -> Result<Box<dyn NyashBox>, RuntimeError> {
if let ASTNode::FunctionDeclaration { params, body, .. } = static_func {
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// パラメータ数チェック
if arg_values.len() != params.len() {
return Err(RuntimeError::InvalidOperation {
message: format!("Static method {}.{} expects {} arguments, got {}",
box_name, method, params.len(), arg_values.len()),
});
}
// 🌍 local変数スタックを保存・クリアstatic関数呼び出し開始
let saved_locals = self.save_local_vars();
self.local_vars.clear();
// 📤 outbox変数スタックも保存・クリアstatic関数専用
let saved_outbox = self.save_outbox_vars();
self.outbox_vars.clear();
// 引数をlocal変数として設定
for (param, value) in params.iter().zip(arg_values.iter()) {
self.declare_local_variable(param, value.clone_box());
}
// static関数の本体を実行
let mut result = Box::new(VoidBox::new()) as Box<dyn NyashBox>;
for statement in &body {
result = self.execute_statement(statement)?;
// return文チェック
if let super::ControlFlow::Return(return_val) = &self.control_flow {
result = return_val.clone_box();
self.control_flow = super::ControlFlow::None;
break;
}
}
// local変数スタックを復元
self.restore_local_vars(saved_locals);
// outbox変数スタックを復元
self.restore_outbox_vars(saved_outbox);
Ok(result)
} else {
Err(RuntimeError::InvalidOperation {
message: format!("Invalid static function: {}.{}", box_name, method),
})
}
}
/// nyashstd標準ライブラリメソッド実行を試行
fn try_execute_stdlib_method(
&mut self,
box_name: &str,
method: &str,
arguments: &[ASTNode]
) -> Result<Option<Box<dyn NyashBox>>, RuntimeError> {
let stdlib_method = if let Some(ref stdlib) = self.stdlib {
if let Some(nyashstd_namespace) = stdlib.namespaces.get("nyashstd") {
if let Some(static_box) = nyashstd_namespace.static_boxes.get(box_name) {
if let Some(builtin_method) = static_box.methods.get(method) {
Some(*builtin_method) // Copyトレイトで関数ポインターをコピー
} else {
eprintln!("🔍 Method '{}' not found in nyashstd.{}", method, box_name);
None
}
} else {
eprintln!("🔍 Static box '{}' not found in nyashstd", box_name);
None
}
} else {
eprintln!("🔍 nyashstd namespace not found in stdlib");
None
}
} else {
eprintln!("🔍 stdlib not initialized for method call");
None
};
if let Some(builtin_method) = stdlib_method {
eprintln!("🌟 Calling nyashstd method: {}.{}", box_name, method);
// 引数を評価
let mut arg_values = Vec::new();
for arg in arguments {
arg_values.push(self.execute_expression(arg)?);
}
// 標準ライブラリのメソッドを実行
let result = builtin_method(&arg_values)?;
eprintln!("✅ nyashstd method completed: {}.{}", box_name, method);
return Ok(Some(result));
}
Ok(None)
}
/// ビルトインBox型メソッドディスパッチ
fn dispatch_builtin_method(
&mut self,
obj_value: &Box<dyn NyashBox>,
method: &str,
arguments: &[ASTNode],
object: &ASTNode
) -> Result<Box<dyn NyashBox>, RuntimeError> {
// Debug: Log the actual type
eprintln!("🔍 DEBUG: dispatch_builtin_method called for type_name='{}', method='{}'",
obj_value.type_name(), method);
eprintln!("🔍 DEBUG: obj_value box_id={}", obj_value.box_id());
// StringBox method calls
if let Some(string_box) = obj_value.as_any().downcast_ref::<StringBox>() {
eprintln!("🔍 DEBUG: Matched as StringBox!");
return self.execute_string_method(string_box, method, arguments);
}
// IntegerBox method calls
if let Some(integer_box) = obj_value.as_any().downcast_ref::<IntegerBox>() {
return self.execute_integer_method(integer_box, method, arguments);
}
// FloatBox method calls
if let Some(float_box) = obj_value.as_any().downcast_ref::<FloatBox>() {
return self.execute_float_method(float_box, method, arguments);
}
// BoolBox method calls
if let Some(bool_box) = obj_value.as_any().downcast_ref::<BoolBox>() {
return self.execute_bool_method(bool_box, method, arguments);
}
// ArrayBox method calls
if let Some(array_box) = obj_value.as_any().downcast_ref::<ArrayBox>() {
return self.execute_array_method(array_box, method, arguments);
}
// BufferBox method calls
if let Some(buffer_box) = obj_value.as_any().downcast_ref::<BufferBox>() {
return self.execute_buffer_method(buffer_box, method, arguments);
}
// FileBox method calls
if let Some(file_box) = obj_value.as_any().downcast_ref::<crate::boxes::file::FileBox>() {
return self.execute_file_method(file_box, method, arguments);
}
// Plugin-backed FileBox method calls
if let Some(pfile) = obj_value.as_any().downcast_ref::<PluginFileBox>() {
return self.execute_plugin_file_method(pfile, method, arguments);
}
// ResultBox method calls
if let Some(result_box) = obj_value.as_any().downcast_ref::<ResultBox>() {
return self.execute_result_method(result_box, method, arguments);
}
// FutureBox method calls
if let Some(future_box) = obj_value.as_any().downcast_ref::<FutureBox>() {
return self.execute_future_method(future_box, method, arguments);
}
// ChannelBox method calls
if let Some(channel_box) = obj_value.as_any().downcast_ref::<ChannelBox>() {
return self.execute_channel_method(channel_box, method, arguments);
}
// JSONBox method calls
if let Some(json_box) = obj_value.as_any().downcast_ref::<JSONBox>() {
return self.execute_json_method(json_box, method, arguments);
}
// HttpClientBox method calls
if let Some(http_box) = obj_value.as_any().downcast_ref::<HttpClientBox>() {
return self.execute_http_method(http_box, method, arguments);
}
// StreamBox method calls
if let Some(stream_box) = obj_value.as_any().downcast_ref::<StreamBox>() {
return self.execute_stream_method(stream_box, method, arguments);
}
// RegexBox method calls
if let Some(regex_box) = obj_value.as_any().downcast_ref::<RegexBox>() {
return self.execute_regex_method(regex_box, method, arguments);
}
// MathBox method calls
if let Some(math_box) = obj_value.as_any().downcast_ref::<MathBox>() {
return self.execute_math_method(math_box, method, arguments);
}
// NullBox method calls
if let Some(null_box) = obj_value.as_any().downcast_ref::<crate::boxes::null_box::NullBox>() {
return self.execute_null_method(null_box, method, arguments);
}
// TimeBox method calls
if let Some(time_box) = obj_value.as_any().downcast_ref::<TimeBox>() {
return self.execute_time_method(time_box, method, arguments);
}
// DateTimeBox method calls
if let Some(datetime_box) = obj_value.as_any().downcast_ref::<DateTimeBox>() {
return self.execute_datetime_method(datetime_box, method, arguments);
}
// TimerBox method calls
if let Some(timer_box) = obj_value.as_any().downcast_ref::<TimerBox>() {
return self.execute_timer_method(timer_box, method, arguments);
}
// MapBox method calls
if let Some(map_box) = obj_value.as_any().downcast_ref::<MapBox>() {
return self.execute_map_method(map_box, method, arguments);
}
// RandomBox method calls
if let Some(random_box) = obj_value.as_any().downcast_ref::<RandomBox>() {
return self.execute_random_method(random_box, method, arguments);
}
// SoundBox method calls
if let Some(sound_box) = obj_value.as_any().downcast_ref::<SoundBox>() {
return self.execute_sound_method(sound_box, method, arguments);
}
// DebugBox method calls
if let Some(debug_box) = obj_value.as_any().downcast_ref::<DebugBox>() {
return self.execute_debug_method(debug_box, method, arguments);
}
// ConsoleBox method calls
if let Some(console_box) = obj_value.as_any().downcast_ref::<crate::boxes::console_box::ConsoleBox>() {
return self.execute_console_method(console_box, method, arguments);
}
// IntentBox method calls
if let Some(intent_box) = obj_value.as_any().downcast_ref::<IntentBox>() {
return self.execute_intent_box_method(intent_box, method, arguments);
}
// SocketBox method calls
if let Some(socket_box) = obj_value.as_any().downcast_ref::<SocketBox>() {
let result = self.execute_socket_method(socket_box, method, arguments)?;
// 🔧 FIX: Update stored variable for stateful SocketBox methods
if matches!(method, "bind" | "connect" | "close") {
self.update_stateful_socket_box(object, socket_box)?;
}
return Ok(result);
}
// HTTPServerBox method calls
if let Some(http_server_box) = obj_value.as_any().downcast_ref::<HTTPServerBox>() {
return self.execute_http_server_method(http_server_box, method, arguments);
}
// HTTPRequestBox method calls
if let Some(http_request_box) = obj_value.as_any().downcast_ref::<HTTPRequestBox>() {
return self.execute_http_request_method(http_request_box, method, arguments);
}
// HTTPResponseBox method calls
if let Some(http_response_box) = obj_value.as_any().downcast_ref::<HTTPResponseBox>() {
return self.execute_http_response_method(http_response_box, method, arguments);
}
// P2PBox method calls - Temporarily disabled
// if let Some(p2p_box) = obj_value.as_any().downcast_ref::<P2PBox>() {
// return self.execute_p2p_box_method(p2p_box, method, arguments);
// }
// EguiBox method calls (非WASM環境のみ)
#[cfg(all(feature = "gui", not(target_arch = "wasm32")))]
if let Some(egui_box) = obj_value.as_any().downcast_ref::<crate::boxes::EguiBox>() {
return self.execute_egui_method(egui_box, method, arguments);
}
// WebDisplayBox method calls (WASM環境のみ)
#[cfg(target_arch = "wasm32")]
if let Some(web_display_box) = obj_value.as_any().downcast_ref::<crate::boxes::WebDisplayBox>() {
return self.execute_web_display_method(web_display_box, method, arguments);
}
// WebConsoleBox method calls (WASM環境のみ)
#[cfg(target_arch = "wasm32")]
if let Some(web_console_box) = obj_value.as_any().downcast_ref::<crate::boxes::WebConsoleBox>() {
return self.execute_web_console_method(web_console_box, method, arguments);
}
// WebCanvasBox method calls (WASM環境のみ)
#[cfg(target_arch = "wasm32")]
if let Some(web_canvas_box) = obj_value.as_any().downcast_ref::<crate::boxes::WebCanvasBox>() {
return self.execute_web_canvas_method(web_canvas_box, method, arguments);
}
// PluginBoxV2 method calls
eprintln!("🔍 DEBUG: Checking for PluginBoxV2...");
if let Some(plugin_box) = obj_value.as_any().downcast_ref::<PluginBoxV2>() {
eprintln!("🔍 DEBUG: Matched as PluginBoxV2! box_type={}, instance_id={}",
plugin_box.box_type, plugin_box.instance_id);
return self.execute_plugin_box_v2_method(plugin_box, method, arguments);
}
eprintln!("🔍 DEBUG: Not matched as PluginBoxV2")
// ユーザー定義Boxのメソッド呼び出し
self.execute_user_defined_method(obj_value, method, arguments)
}
fn execute_plugin_file_method(
&mut self,
pfile: &PluginFileBox,
method: &str,
arguments: &[ASTNode],
) -> Result<Box<dyn NyashBox>, RuntimeError> {
match method {
"write" => {
if arguments.len() != 1 {
return Err(RuntimeError::InvalidOperation { message: "FileBox.write expects 1 argument".into() });
}
let arg0 = self.execute_expression(&arguments[0])?;
let data = arg0.to_string_box().value;
pfile.write_bytes(data.as_bytes()).map_err(|e| RuntimeError::RuntimeFailure { message: format!("plugin write error: {:?}", e) })?;
Ok(Box::new(StringBox::new("ok")))
}
"read" => {
// Default read size
let size = 1_048_576usize; // 1MB max
let bytes = pfile.read_bytes(size).map_err(|e| RuntimeError::RuntimeFailure { message: format!("plugin read error: {:?}", e) })?;
let s = String::from_utf8_lossy(&bytes).to_string();
Ok(Box::new(StringBox::new(s)))
}
"close" => {
pfile.close().map_err(|e| RuntimeError::RuntimeFailure { message: format!("plugin close error: {:?}", e) })?;
Ok(Box::new(StringBox::new("ok")))
}
_ => Err(RuntimeError::InvalidOperation { message: format!("Unknown method FileBox.{} (plugin)", method) })
}
}
fn execute_plugin_box_v2_method(
&mut self,
plugin_box: &PluginBoxV2,
method: &str,
arguments: &[ASTNode],
) -> Result<Box<dyn NyashBox>, RuntimeError> {
// Delegate to unified facade for correct TLV typing and config resolution
self.call_plugin_method(plugin_box, method, arguments)
}
/// SocketBoxの状態変更を反映
fn update_stateful_socket_box(
&mut self,
object: &ASTNode,
socket_box: &SocketBox
) -> Result<(), RuntimeError> {
eprintln!("🔧 DEBUG: Stateful method called, updating stored instance");
let updated_instance = socket_box.clone();
eprintln!("🔧 DEBUG: Updated instance created with ID={}", updated_instance.box_id());
match object {
ASTNode::Variable { name, .. } => {
eprintln!("🔧 DEBUG: Updating local variable '{}'", name);
if let Some(stored_var) = self.local_vars.get_mut(name) {
eprintln!("🔧 DEBUG: Found local variable '{}', updating from id={} to id={}",
name, stored_var.box_id(), updated_instance.box_id());
*stored_var = Arc::new(updated_instance);
} else {
eprintln!("🔧 DEBUG: Local variable '{}' not found", name);
}
},
ASTNode::FieldAccess { object: field_obj, field, .. } => {
eprintln!("🔧 DEBUG: Updating field access '{}'", field);
self.update_field_with_socket_box(field_obj, field, updated_instance)?;
},
_ => {
eprintln!("🔧 DEBUG: Object type not handled: {:?}", object);
}
}
Ok(())
}
/// フィールドアクセスでのSocketBox更新
fn update_field_with_socket_box(
&mut self,
field_obj: &ASTNode,
field: &str,
updated_instance: SocketBox
) -> Result<(), RuntimeError> {
match field_obj {
ASTNode::Variable { name, .. } => {
eprintln!("🔧 DEBUG: Field object is variable '{}'", name);
if name == "me" {
eprintln!("🔧 DEBUG: Updating me.{} (via variable)", field);
if let Ok(me_instance) = self.resolve_variable("me") {
eprintln!("🔧 DEBUG: Resolved 'me' instance id={}", me_instance.box_id());
if let Some(instance) = (*me_instance).as_any().downcast_ref::<InstanceBox>() {
eprintln!("🔧 DEBUG: me is InstanceBox, setting field '{}' to updated instance id={}", field, updated_instance.box_id());
let result = instance.set_field(field, Arc::new(updated_instance));
eprintln!("🔧 DEBUG: set_field result: {:?}", result);
} else {
eprintln!("🔧 DEBUG: me is not an InstanceBox, type: {}", me_instance.type_name());
}
} else {
eprintln!("🔧 DEBUG: Failed to resolve 'me'");
}
} else {
eprintln!("🔧 DEBUG: Field object is not 'me', it's '{}'", name);
}
},
ASTNode::Me { .. } => {
eprintln!("🔧 DEBUG: Field object is Me node, updating me.{}", field);
if let Ok(me_instance) = self.resolve_variable("me") {
eprintln!("🔧 DEBUG: Resolved 'me' instance id={}", me_instance.box_id());
if let Some(instance) = (*me_instance).as_any().downcast_ref::<InstanceBox>() {
eprintln!("🔧 DEBUG: me is InstanceBox, setting field '{}' to updated instance id={}", field, updated_instance.box_id());
let result = instance.set_field(field, Arc::new(updated_instance));
eprintln!("🔧 DEBUG: set_field result: {:?}", result);
} else {
eprintln!("🔧 DEBUG: me is not an InstanceBox, type: {}", me_instance.type_name());
}
} else {
eprintln!("🔧 DEBUG: Failed to resolve 'me'");
}
},
_ => {
eprintln!("🔧 DEBUG: Field object is not a variable or me, type: {:?}", field_obj);
}
}
Ok(())
}
/// ユーザー定義Boxメソッド実行
fn execute_user_defined_method(
&mut self,
obj_value: &Box<dyn NyashBox>,
method: &str,
arguments: &[ASTNode]
) -> Result<Box<dyn NyashBox>, RuntimeError> {
// InstanceBox method calls (user-defined methods)
if let Some(instance) = obj_value.as_any().downcast_ref::<InstanceBox>() {
return self.execute_instance_method(instance, method, arguments);
}
// Static box method calls would be handled here if implemented
// (Currently handled via different mechanism in static function dispatch)
Err(RuntimeError::InvalidOperation {
message: format!("Method '{}' not found on type '{}'", method, obj_value.type_name()),
})
}
}

View File

@ -1,355 +0,0 @@
#![cfg(all(feature = "plugins", not(target_arch = "wasm32")))]
use nyash_rust::parser::NyashParser;
use nyash_rust::runtime::plugin_loader_v2::{init_global_loader_v2, get_global_loader_v2};
use nyash_rust::runtime::box_registry::get_global_registry;
use nyash_rust::runtime::PluginConfig;
use nyash_rust::runtime::NyashRuntime;
use nyash_rust::backend::VM;
fn try_init_plugins() -> bool {
if !std::path::Path::new("nyash.toml").exists() { return false; }
if let Err(e) = init_global_loader_v2("nyash.toml") { eprintln!("init failed: {:?}", e); return false; }
let loader = get_global_loader_v2();
let loader = loader.read().unwrap();
if let Some(conf) = &loader.config {
let mut map = std::collections::HashMap::new();
for (lib, def) in &conf.libraries { for b in &def.boxes { map.insert(b.clone(), lib.clone()); } }
get_global_registry().apply_plugin_config(&PluginConfig { plugins: map });
true
} else { false }
}
#[test]
fn e2e_http_stub_end_to_end() {
std::env::set_var("NYASH_NET_LOG", "1");
std::env::set_var("NYASH_NET_LOG_FILE", "net_plugin.log");
if !try_init_plugins() { return; }
let code = r#"
local srv, cli, r, resp, req, body
srv = new HttpServerBox()
srv.start(8080)
cli = new HttpClientBox()
r = cli.get("http://localhost:8080/hello")
req = srv.accept().get_value()
resp = new HttpResponseBox()
resp.setStatus(200)
resp.write("OK")
req.respond(resp)
resp = r.get_value()
body = resp.readBody()
body
"#;
let ast = NyashParser::parse_from_string(code).expect("parse failed");
let mut interpreter = nyash_rust::interpreter::NyashInterpreter::new();
let result = interpreter.execute(ast).expect("exec failed");
assert_eq!(result.to_string_box().value, "OK");
}
#[test]
fn e2e_vm_http_get_basic() {
std::env::set_var("NYASH_NET_LOG", "1");
std::env::set_var("NYASH_NET_LOG_FILE", "net_plugin3.log");
if !try_init_plugins() { return; }
let code = r#"
local srv, cli, r, resp, req, body
srv = new HttpServerBox()
srv.start(8085)
cli = new HttpClientBox()
r = cli.get("http://localhost:8085/hello")
req = srv.accept().get_value()
resp = new HttpResponseBox()
resp.write("OK")
req.respond(resp)
resp = r.get_value()
body = resp.readBody()
body
"#;
let ast = NyashParser::parse_from_string(code).expect("parse failed");
let runtime = NyashRuntime::new();
let mut compiler = nyash_rust::mir::MirCompiler::new();
let compile_result = compiler.compile(ast).expect("mir compile failed");
let mut vm = VM::with_runtime(runtime);
let result = vm.execute_module(&compile_result.module).expect("vm exec failed");
assert_eq!(result.to_string_box().value, "OK");
}
#[test]
fn e2e_vm_http_status_404() {
std::env::set_var("NYASH_NET_LOG", "1");
std::env::set_var("NYASH_NET_LOG_FILE", "net_plugin3.log");
if !try_init_plugins() { return; }
let code = r#"
local srv, cli, r, resp, req, body, st
srv = new HttpServerBox()
srv.start(8086)
cli = new HttpClientBox()
r = cli.get("http://localhost:8086/notfound")
req = srv.accept().get_value()
resp = new HttpResponseBox()
resp.setStatus(404)
resp.write("NF")
req.respond(resp)
resp = r.get_value()
st = resp.getStatus()
body = resp.readBody()
st.toString() + ":" + body
"#;
let ast = NyashParser::parse_from_string(code).expect("parse failed");
let runtime = NyashRuntime::new();
let mut compiler = nyash_rust::mir::MirCompiler::new();
let compile_result = compiler.compile(ast).expect("mir compile failed");
let mut vm = VM::with_runtime(runtime);
let result = vm.execute_module(&compile_result.module).expect("vm exec failed");
assert_eq!(result.to_string_box().value, "404:NF");
}
#[test]
fn e2e_vm_http_status_500() {
std::env::set_var("NYASH_NET_LOG", "1");
std::env::set_var("NYASH_NET_LOG_FILE", "net_plugin3.log");
if !try_init_plugins() { return; }
let code = r#"
local srv, cli, r, resp, req, body, st
srv = new HttpServerBox()
srv.start(8084)
cli = new HttpClientBox()
r = cli.get("http://localhost:8084/error")
req = srv.accept().get_value()
resp = new HttpResponseBox()
resp.setStatus(500)
resp.write("ERR")
req.respond(resp)
resp = r.get_value()
st = resp.getStatus()
body = resp.readBody()
st.toString() + ":" + body
"#;
let ast = NyashParser::parse_from_string(code).expect("parse failed");
let runtime = NyashRuntime::new();
let mut compiler = nyash_rust::mir::MirCompiler::new();
let compile_result = compiler.compile(ast).expect("mir compile failed");
let mut vm = VM::with_runtime(runtime);
let result = vm.execute_module(&compile_result.module).expect("vm exec failed");
assert_eq!(result.to_string_box().value, "500:ERR");
}
#[test]
fn e2e_vm_http_post_and_headers() {
std::env::set_var("NYASH_NET_LOG", "1");
std::env::set_var("NYASH_NET_LOG_FILE", "net_plugin3.log");
if !try_init_plugins() { return; }
let code = r#"
local srv, cli, r, resp, req, body, st, hv
srv = new HttpServerBox()
srv.start(8086)
cli = new HttpClientBox()
r = cli.post("http://localhost:8086/api", "DATA")
req = srv.accept().get_value()
// check server saw body
body = req.readBody()
// prepare response
resp = new HttpResponseBox()
resp.setStatus(201)
resp.setHeader("X-Test", "V")
resp.write("R")
req.respond(resp)
// client reads status, header, body
resp = r.get_value()
st = resp.getStatus()
hv = resp.getHeader("X-Test")
body = resp.readBody()
st.toString() + ":" + hv + ":" + body
"#;
let ast = NyashParser::parse_from_string(code).expect("parse failed");
let runtime = NyashRuntime::new();
let mut compiler = nyash_rust::mir::MirCompiler::new();
let compile_result = compiler.compile(ast).expect("mir compile failed");
let mut vm = VM::with_runtime(runtime);
let result = vm.execute_module(&compile_result.module).expect("vm exec failed");
assert_eq!(result.to_string_box().value, "201:V:R");
}
#[test]
fn e2e_http_server_restart() {
std::env::set_var("NYASH_NET_LOG", "1");
std::env::set_var("NYASH_NET_LOG_FILE", "net_plugin.log");
if !try_init_plugins() { return; }
let code = r#"
local srv, cli, r, resp, req, body
srv = new HttpServerBox()
srv.start(8081)
cli = new HttpClientBox()
r = cli.get("http://localhost:8081/test1")
req = srv.accept().get_value()
resp = new HttpResponseBox()
resp.write("A")
req.respond(resp)
srv.stop()
srv.start(8081)
resp = r.get_value()
_ = resp.readBody() # consume first response (optional)
r = cli.get("http://localhost:8081/test2")
req = srv.accept().get_value()
resp = new HttpResponseBox()
resp.write("B")
req.respond(resp)
resp = r.get_value()
body = resp.readBody()
body
"#;
let ast = NyashParser::parse_from_string(code).expect("parse failed");
let mut interpreter = nyash_rust::interpreter::NyashInterpreter::new();
let result = interpreter.execute(ast).expect("exec failed");
assert_eq!(result.to_string_box().value, "B");
}
#[test]
fn e2e_http_server_shutdown_and_restart() {
std::env::set_var("NYASH_NET_LOG", "1");
std::env::set_var("NYASH_NET_LOG_FILE", "net_plugin.log");
if !try_init_plugins() { return; }
// First run: start and respond
let code1 = r#"
local srv, cli, r, resp, req
srv = new HttpServerBox()
srv.start(8082)
cli = new HttpClientBox()
r = cli.get("http://localhost:8082/first")
req = srv.accept().get_value()
resp = new HttpResponseBox()
resp.write("X")
req.respond(resp)
"#;
let ast1 = NyashParser::parse_from_string(code1).expect("parse1");
let mut i1 = nyash_rust::interpreter::NyashInterpreter::new();
i1.execute(ast1).expect("exec1");
// Shutdown plugins (finalize singleton) and re-init
nyash_rust::runtime::plugin_loader_v2::shutdown_plugins_v2().expect("shutdown ok");
assert!(try_init_plugins());
// Second run: ensure fresh instance works
let code2 = r#"
local srv, cli, r, req, resp, body
srv = new HttpServerBox()
srv.start(8083)
cli = new HttpClientBox()
r = cli.get("http://localhost:8083/second")
req = srv.accept().get_value()
resp = new HttpResponseBox()
resp.write("Y")
req.respond(resp)
resp = r.get_value()
body = resp.readBody()
body
"#;
let ast2 = NyashParser::parse_from_string(code2).expect("parse2");
let mut i2 = nyash_rust::interpreter::NyashInterpreter::new();
let result = i2.execute(ast2).expect("exec2");
assert_eq!(result.to_string_box().value, "Y");
}
#[test]
fn e2e_http_post_and_headers() {
std::env::set_var("NYASH_NET_LOG", "1");
std::env::set_var("NYASH_NET_LOG_FILE", "net_plugin.log");
if !try_init_plugins() { return; }
let code = r#"
local srv, cli, r, resp, req, body, st, hv
srv = new HttpServerBox()
srv.start(8090)
cli = new HttpClientBox()
r = cli.post("http://localhost:8090/api", "DATA")
req = srv.accept().get_value()
// check server saw body
body = req.readBody()
// prepare response
resp = new HttpResponseBox()
resp.setStatus(201)
resp.setHeader("X-Test", "V")
resp.write("R")
req.respond(resp)
// client reads status, header, body
resp = r.get_value()
st = resp.getStatus()
hv = resp.getHeader("X-Test")
body = resp.readBody()
st.toString() + ":" + hv + ":" + body
"#;
let ast = NyashParser::parse_from_string(code).expect("parse failed");
let mut interpreter = nyash_rust::interpreter::NyashInterpreter::new();
let result = interpreter.execute(ast).expect("exec failed");
assert_eq!(result.to_string_box().value, "201:V:R");
}
#[test]
fn e2e_http_multiple_requests_order() {
std::env::set_var("NYASH_NET_LOG", "1");
std::env::set_var("NYASH_NET_LOG_FILE", "net_plugin.log");
if !try_init_plugins() { return; }
let code = r#"
local srv, cli, r1, r2, r3, req1, req2, req3, q1, q2, q3
srv = new HttpServerBox()
srv.start(8091)
cli = new HttpClientBox()
r1 = cli.get("http://localhost:8091/a")
r2 = cli.get("http://localhost:8091/b")
r3 = cli.get("http://localhost:8091/c")
req1 = srv.accept().get_value()
q1 = req1.path()
req2 = srv.accept().get_value()
q2 = req2.path()
req3 = srv.accept().get_value()
q3 = req3.path()
q1 + "," + q2 + "," + q3
"#;
let ast = NyashParser::parse_from_string(code).expect("parse failed");
let mut interpreter = nyash_rust::interpreter::NyashInterpreter::new();
let result = interpreter.execute(ast).expect("exec failed");
assert_eq!(result.to_string_box().value, "/a,/b,/c");
}