From 9041edeb131bb519045892ada7093faaa3a133b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E7=89=B9=E6=AF=8F=E7=BE=8A=E9=98=9F?= Date: Sun, 7 Jun 2026 23:47:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20CLI=20=E6=94=AF=E6=8C=81=20JSON=20?= =?UTF-8?q?=E5=AF=B9=E8=B1=A1=E8=BE=93=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 1 + crates/oxide_cli/Cargo.toml | 1 + crates/oxide_cli/src/main.rs | 90 +++++++++++++++++++++++------------- 3 files changed, 61 insertions(+), 31 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fcb730f..6eac61c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -773,6 +773,7 @@ dependencies = [ "oxide_compiler", "oxide_kernel", "oxide_parser", + "oxide_types", "oxide_vm", "rustyline", ] diff --git a/crates/oxide_cli/Cargo.toml b/crates/oxide_cli/Cargo.toml index 59892fa..19f8ff3 100644 --- a/crates/oxide_cli/Cargo.toml +++ b/crates/oxide_cli/Cargo.toml @@ -12,6 +12,7 @@ path = "src/main.rs" [dependencies] oxide_parser = { path = "../oxide_parser" } +oxide_types = { path = "../oxide_types" } oxide_compiler = { path = "../oxide_compiler" } oxide_vm = { path = "../oxide_vm" } oxide_kernel = { path = "../oxide_kernel" } diff --git a/crates/oxide_cli/src/main.rs b/crates/oxide_cli/src/main.rs index 65027ea..3260767 100644 --- a/crates/oxide_cli/src/main.rs +++ b/crates/oxide_cli/src/main.rs @@ -8,8 +8,10 @@ use ansi_term::Colour::Red; use clap::{Parser, Subcommand}; use oxide_compiler::compiler::Compiler; use oxide_kernel::kernel::{KernelConfig, OxideKernel}; +use oxide_kernel::shape_forge::{ShapeForge, EMPTY_SHAPE_ID}; use oxide_kernel::string_forge::StringForge; use oxide_parser::Allocator; +use oxide_types::object::JsObject; use oxide_vm::vm_pool::VmPool; use oxide_vm::JsValue; @@ -106,7 +108,7 @@ fn eval(code: &str, kernel: &Arc, pool: &Arc) -> ExitCode { let mut guard = pool.spawn(); match guard.vm_mut().run(&module) { Ok(result) => { - format_result(kernel.string_forge().as_ref(), result); + format_result(kernel.string_forge().as_ref(), kernel.shape_forge().as_ref(), result); ExitCode::SUCCESS } Err(err) => { @@ -116,52 +118,78 @@ fn eval(code: &str, kernel: &Arc, pool: &Arc) -> ExitCode { } } -fn format_result(string_forge: &StringForge, val: JsValue) { +fn format_result(string_forge: &StringForge, shape_forge: &ShapeForge, val: JsValue) { + println!("{}", format_js_value(string_forge, shape_forge, val)); +} + +fn format_js_value(string_forge: &StringForge, shape_forge: &ShapeForge, val: JsValue) -> String { if val.is_string() { if let Some(s) = string_forge.lookup(val.as_string_index()) { - println!("\"{s}\""); + format!("\"{s}\"") } else { - println!("{val}"); + format!("{val}") } } else if val.is_object() { let obj = unsafe { &*val.as_js_object_ptr() }; if obj.is_function() { - println!("[Function]"); + "[Function]".to_string() + } else if obj.is_array() { + format_array(string_forge, shape_forge, obj) } else { - print!("{{"); - let count = obj.prop_count() as usize; - let mut first = true; - for i in 0..count.min(4) { - let prop_val = obj.get_prop_at(i as u8); - if prop_val.is_undefined() { - continue; - } - if !first { - print!(", "); - } - first = false; - print!("{:?}: ", i); - print_value(string_forge, prop_val); - } - println!("}}"); + format_object(string_forge, shape_forge, obj) } } else if val.is_undefined() { - println!("undefined"); + "undefined".to_string() } else { - println!("{val}"); + format!("{val}") } } -fn print_value(string_forge: &StringForge, val: JsValue) { - if val.is_string() { - if let Some(s) = string_forge.lookup(val.as_string_index()) { - print!("\"{s}\""); - } else { - print!("{val}"); +fn format_object(string_forge: &StringForge, shape_forge: &ShapeForge, obj: &JsObject) -> String { + let mut entries = Vec::new(); + let shape_id = obj.shape_id(); + let mut shape_ids = Vec::new(); + let mut cursor = Some(shape_id); + while let Some(id) = cursor { + if id == EMPTY_SHAPE_ID { + break; + } + if let Some(shape) = shape_forge.get_shape(id) { + cursor = shape.parent; + if shape.property_name != u32::MAX { + shape_ids.push(id); + } + } else { + break; } - } else { - print!("{val}"); } + let mut pos: u8 = 0; + for id in shape_ids.iter().rev() { + if let Some(shape) = shape_forge.get_shape(*id) { + if shape.property_name != 0 { + let prop_val = obj.get_prop_at(pos); + if prop_val.is_undefined() { + pos += 1; + continue; + } + let name = string_forge.lookup(shape.property_name).unwrap_or_default(); + let val_str = format_js_value(string_forge, shape_forge, prop_val); + entries.push(format!("\"{name}\": {val_str}")); + } + } + pos += 1; + } + format!("{{{}}}", entries.join(", ")) +} + +fn format_array(string_forge: &StringForge, shape_forge: &ShapeForge, obj: &JsObject) -> String { + let len = obj.prop_vec_len(); + let mut items = Vec::new(); + for i in 0..len { + let val = obj.get_prop_at(i as u8); + items.push(format_js_value(string_forge, shape_forge, val)); + } + format!("[{}]", items.join(", ")) } fn run(file: &str, kernel: &Arc, pool: &Arc) -> ExitCode {