Impressão
Arquivo: printing/mod.rs
.
1. Importações
use std::fmt::Write; use gc::Gc; use crate::core::{ Maj, MajState }; use crate::core::types::MajStream; use crate::axioms::predicates::{ maj_nilp, maj_stringp, maj_closurep, maj_primitivep, maj_macrop }; use crate::axioms::primitives::{ maj_car, maj_cdr };
2. Formatação
2.1. Formatação genérica
pub fn maj_format(state: &MajState, obj: Gc<Maj>) -> String { maj_format_raw(state, obj, true) }
pub fn maj_format_raw( state: &MajState, obj: Gc<Maj>, format_read_macros: bool ) -> String { match &*obj.clone() { Maj::Sym(_) => obj.symbol_name(&state), Maj::Cons { car: _, cdr: _ } => maj_format_list(&state, obj, format_read_macros), Maj::Char(c) => maj_format_char(*c), Maj::Stream(s) => maj_format_stream(s, obj), Maj::Vector(_) => maj_format_vector(&state, obj, format_read_macros), _ => format!("{}", obj) } }
2.2. Formatação de caracteres
pub fn maj_format_char(c: char) -> String { let f; format!("#\\{}", match c { '\x07' => "␇", ' ' => "space", '\n' => "newline", '\t' => "tab", _ => { f = format!("{}", c); &f }, }) }
2.3. Formatação de listas
fn maj_format_list( state: &MajState, list: Gc<Maj>, rm: bool ) -> String { use crate::axioms::predicates::maj_errorp; use crate::evaluator::evaluation::{ maj_quotep, maj_unquotep, maj_quasiquotep, maj_unquote_splice_p }; if rm { if maj_quotep(list.clone()).to_bool() { return format!( "'{}", maj_format_raw( state, maj_car(maj_cdr(list)), rm)); } else if maj_quasiquotep(list.clone()).to_bool() { return format!( "`{}", maj_format_raw( state, maj_car(maj_cdr(list)), rm)); } else if maj_unquotep(list.clone()).to_bool() { return format!( ",{}", maj_format_raw( state, maj_car(maj_cdr(list)), rm)); } else if maj_unquote_splice_p(list.clone()).to_bool() { return format!( ",@{}", maj_format_raw( state, maj_car(maj_cdr(list)), rm)); } } if maj_errorp(list.clone()).to_bool() { // Handle errors return maj_format_error(&state, list, rm); } else if maj_closurep(list.clone()).to_bool() && rm { // Handle closures return maj_format_closure(&state, list, rm); } else if maj_primitivep(list.clone()).to_bool() && rm { // Handle primitives return maj_format_primitive(&state, list, rm); } else if maj_macrop(list.clone()).to_bool() && rm { // Handle macros return maj_format_macro(&state, list, rm); } // Handle all other lists let mut buffer = String::new(); let mut itr = list.clone(); write!(&mut buffer, "(").unwrap(); loop { match &*itr.clone() { Maj::Cons { car, cdr } => { write!(&mut buffer, "{}", maj_format_raw( &state, car.clone(), rm)) .unwrap(); if maj_nilp(cdr.clone()).to_bool() { break; } if let Maj::Cons { car: _, cdr: _ } = *cdr.clone() { write!(&mut buffer, " ").unwrap(); itr = cdr.clone(); } else { write!(&mut buffer, " . {}", maj_format_raw( &state, cdr.clone(), rm)) .unwrap(); break; } }, _ => panic!("Cannot print ordinary object as a list") } } write!(&mut buffer, ")").unwrap(); buffer }
2.4. Formatação de vetores
fn maj_format_vector( state: &MajState, vector: Gc<Maj>, rm: bool ) -> String { let mut buffer = String::new(); use crate::core::types::MajVector; if let Maj::Vector(vector) = &*vector { match vector { MajVector::Integer(v) => { write!(&mut buffer, "[").unwrap(); let len = v.borrow().len(); for (i, int) in v.borrow().iter().enumerate() { write!(&mut buffer, "{}{}", int, if (i + 1) < len { " " } else { "" }).unwrap(); } write!(&mut buffer, "]").unwrap(); }, MajVector::Float(v) => { use crate::axioms::utils::format_raw_float; write!(&mut buffer, "[").unwrap(); let len = v.borrow().len(); for (i, fl) in v.borrow().iter().enumerate() { // Bug com casas decimais? write!(&mut buffer, "{}{}", format_raw_float(*fl), if (i + 1) < len { " " } else { "" }).unwrap(); } write!(&mut buffer, "]").unwrap(); }, MajVector::Char(s) => { write!(&mut buffer, "\"{}\"", s.borrow()).unwrap(); }, MajVector::Any(v) => { write!(&mut buffer, "[").unwrap(); let len = v.borrow().len(); for (i, obj) in v.borrow().iter().enumerate() { write!(&mut buffer, "{}{}", maj_format_raw(&state, obj.clone(), rm), if (i + 1) < len { " " } else { "" }).unwrap(); } write!(&mut buffer, "]").unwrap(); }, } } else { panic!("Vector printing on non-vector object"); } buffer }
2.5. Formatação de clausuras
fn maj_format_closure( state: &MajState, closure: Gc<Maj>, rm: bool ) -> String { // Lambda list is fourth element (cadddr). // Sorry for this ugly thing. let lambda_list = maj_car( maj_cdr(maj_cdr(maj_cdr(closure.clone())))); format!("#<function (fn {}) {{{:p}}}>", maj_format_raw(&state, lambda_list, rm), Gc::into_raw(closure)) }
2.6. Formatação de macros
fn maj_format_macro(state: &MajState, mac: Gc<Maj>, rm: bool) -> String { let closure = maj_car(maj_cdr(maj_cdr(mac))); let lambda_list = maj_car( maj_cdr(maj_cdr(maj_cdr(closure.clone())))); format!("#<macro (mac {}) {{{:p}}}>", maj_format_raw(&state, lambda_list, rm), Gc::into_raw(closure)) }
2.7. Formatação de primitivas
fn maj_format_primitive( state: &MajState, primitive: Gc<Maj>, rm: bool ) -> String { // Symbol for primitive is third element (caddr) let prim_sym = maj_car(maj_cdr(maj_cdr(primitive.clone()))); // Arity for primitive starts at fourth element (cdddr) let prim_arity = maj_cdr(maj_cdr(maj_cdr(primitive))); format!("#<function (prim {} (arity {}))>", maj_format_raw(&state, prim_sym, rm), maj_format_raw(&state, prim_arity, rm)) }
2.8. Formatação de erros
fn maj_format_error(state: &MajState, error: Gc<Maj>, rm: bool) -> String { use crate::axioms::primitives::maj_format_prim; // (lit error fmt . rest) let fmt = maj_car(maj_cdr(maj_cdr(error.clone()))); let rest = maj_cdr(maj_cdr(maj_cdr(error))); let formatted = maj_format_prim(&state, fmt, rest); let formatted = maj_format_raw(&state, formatted, rm); let len = formatted.len(); format!("{}", &formatted[1..len-1]) }
2.9. Formatação de streams
fn maj_format_stream(s: &MajStream, obj: Gc<Maj>) -> String { use crate::core::types::MajStreamDirection; format!("#<stream ({}) {{{:p}}}>", match s.direction { MajStreamDirection::In => "in", MajStreamDirection::Out => "out", }, Gc::into_raw(obj)) }
2.10. TODO Pretty printing
Ligeiramente adaptado do blog de PicoLisp, como visto em https://picolisp.com/wiki/?prettyPrint.
fn maj_pformat_helper( state: &MajState, obj: Gc<Maj>, ind: u64, ) -> String { use crate::axioms::predicates::maj_atomp; use crate::axioms::primitives::maj_length; let indent_max = 8; let mut buffer = String::new(); for _ in 0..ind { write!(&mut buffer, " ").unwrap(); } if maj_atomp(obj.clone()).to_bool() || maj_stringp(obj.clone()).to_bool() || (maj_length(obj.clone()) .to_integer() .unwrap() < indent_max) { write!(&mut buffer, "{}", maj_format(&state, obj)) .unwrap(); } else { write!(&mut buffer, "(").unwrap(); write!(&mut buffer, "{}", maj_format( &state, maj_car(obj.clone()))) .unwrap(); let mut itr = maj_cdr(obj.clone()); // TODO: Add check for special forms: // (and (member (prin1 (pop x)) *specials*) // ...) while maj_length(itr.clone()) .to_integer() .unwrap() >= indent_max { write!(&mut buffer, " ").unwrap(); itr = maj_cdr(itr); } itr = maj_cdr(obj.clone()); while !maj_nilp(itr.clone()).to_bool() { write!(&mut buffer, "\n{}", maj_pformat_helper(&state, maj_car(itr.clone()), ind + 2)) .unwrap(); itr = maj_cdr(itr); } write!(&mut buffer, ")").unwrap(); } buffer }
pub fn maj_pretty_format(state: &MajState,obj: Gc<Maj>) -> String { maj_pformat_helper(state, obj, 0) }
3. Impressão de contexto
3.1. Impressão comum
#[cfg(not(target_arch = "wasm32"))] pub fn maj_format_env(state: &MajState, env: Gc<Maj>) -> String { use comfy_table::*; use comfy_table::presets::UTF8_FULL; use comfy_table::modifiers::UTF8_ROUND_CORNERS; let mut table = Table::new(); table.load_preset(UTF8_FULL); table.apply_modifier(UTF8_ROUND_CORNERS); table.set_content_arrangement(ContentArrangement::Dynamic); table.set_header(&vec!["Symbol", "Value"]); let mut iter = env.clone(); while !maj_nilp(iter.clone()).to_bool() { let pair = maj_car(iter.clone()); let sym = maj_car(pair.clone()); let val = maj_cdr(pair); table.add_row(vec![ maj_format(&state, sym), maj_format(&state, val), ]); iter = maj_cdr(iter); } format!("{}", table) }
3.2. Impressão simples (para WebAssembly)
#[cfg(target_arch = "wasm32")] #[inline] pub fn maj_format_env_hline() -> String { format!("+{:-<21}+{:-<61}+", "", "") } #[cfg(target_arch = "wasm32")] pub fn maj_format_env(state: &MajState, env: Gc<Maj>) -> String { use crate::axioms::utils::truncate_format; let mut buffer = String::new(); let mut iter = env.clone(); let _ = writeln!(&mut buffer, "{}", maj_format_env_hline()) .unwrap(); let _ = writeln!(&mut buffer, "|{:<21}|{:<61}|", " Symbol", " Value"); let _ = writeln!(&mut buffer, "{}", maj_format_env_hline()) .unwrap(); while !maj_nilp(iter.clone()).to_bool() { let pair = maj_car(iter.clone()); let sym = maj_car(pair.clone()); let val = maj_cdr(pair); let _ = writeln!(&mut buffer, "| {:<20}| {:<60}|", truncate_format( maj_format(&state, sym.clone()), 20), truncate_format( maj_format(&state, val), 60)) .unwrap(); iter = maj_cdr(iter.clone()); } let _ = writeln!(&mut buffer, "{}", maj_format_env_hline()) .unwrap(); buffer }