From 777c756a7f8ba953aa4c510e35a4effc2fd10c1d Mon Sep 17 00:00:00 2001 From: Tom Alexander Date: Fri, 29 Dec 2023 17:24:38 -0500 Subject: [PATCH] Compare plain text AST nodes. --- src/compare/mod.rs | 1 + src/wasm/plain_text.rs | 2 +- src/wasm_test/compare.rs | 123 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 125 insertions(+), 1 deletion(-) diff --git a/src/compare/mod.rs b/src/compare/mod.rs index 76ee7a0..e5f8e98 100644 --- a/src/compare/mod.rs +++ b/src/compare/mod.rs @@ -16,6 +16,7 @@ pub(crate) use compare_field::EmacsField; pub(crate) use elisp_fact::ElispFact; pub use sexp::sexp; pub(crate) use sexp::unquote; +pub(crate) use sexp::TextWithProperties; pub use sexp::Token; pub(crate) use util::get_emacs_standard_properties; pub(crate) use util::get_property; diff --git a/src/wasm/plain_text.rs b/src/wasm/plain_text.rs index 8681230..974cb16 100644 --- a/src/wasm/plain_text.rs +++ b/src/wasm/plain_text.rs @@ -21,7 +21,7 @@ to_wasm!( original, wasm_context, { WasmAstNode::PlainText(original) }, - { "TODO".into() }, + { "plain-text".into() }, { Ok(( Vec::new(), diff --git a/src/wasm_test/compare.rs b/src/wasm_test/compare.rs index 558473f..6ba9b7b 100644 --- a/src/wasm_test/compare.rs +++ b/src/wasm_test/compare.rs @@ -5,9 +5,11 @@ use super::diff::WasmDiffResult; use super::diff::WasmDiffStatus; use crate::compare::get_emacs_standard_properties; use crate::compare::maybe_token_to_usize; +use crate::compare::unquote; use crate::compare::ElispFact; use crate::compare::EmacsField; use crate::compare::EmacsStandardProperties; +use crate::compare::TextWithProperties; use crate::compare::Token; use crate::wasm::WasmAngleLink; use crate::wasm::WasmAstNode; @@ -109,6 +111,9 @@ fn compare_json_value<'b, 's>( { compare_optional_pair(source, e, wasm) } + (serde_json::Value::Object(w), Token::TextWithProperties(e)) if is_plain_text(w) => { + compare_plain_text(source, e, w) + } (serde_json::Value::Null, Token::Atom(_)) => todo!(), (serde_json::Value::Null, Token::List(_)) => todo!(), (serde_json::Value::Null, Token::TextWithProperties(_)) => todo!(), @@ -478,6 +483,124 @@ fn compare_optional_pair<'e, 's, 'w>( Ok(result) } +fn is_plain_text<'e, 's, 'w>(wasm: &'w serde_json::Map) -> bool { + if let Some(serde_json::Value::String(node_type)) = wasm.get("ast-node") { + node_type == "plain-text" + } else { + false + } +} + +fn compare_plain_text<'e, 's, 'w>( + source: &'s str, + emacs: &'e TextWithProperties<'s>, + wasm: &'w serde_json::Map, +) -> Result, Box> { + let mut result = WasmDiffResult::default(); + if !is_plain_text(wasm) { + result.status.push(WasmDiffStatus::Bad( + format!( + "AST node type mismatch. Emacs=({emacs:?}) Wasm=({wasm:?}).", + emacs = emacs, + wasm = wasm, + ) + .into(), + )); + return Ok(result); + } + + let emacs_text = unquote(emacs.text)?; + let wasm_standard_properties = wasm + .get("standard-properties") + .ok_or(r#"Wasm AST nodes should have a "standard-properties" attribute."#)? + .as_object() + .ok_or(r#"Wasm ast node "standard-properties" attribute should be an object."#)?; + let wasm_begin = { + if let Some(serde_json::Value::Number(begin)) = wasm_standard_properties.get("begin") { + begin + .as_u64() + .map(|w| w as usize) + .ok_or("Begin should be a number.")? + } else { + result.status.push(WasmDiffStatus::Bad( + format!( + "AST node type mismatch. Emacs=({emacs:?}) Wasm=({wasm:?}).", + emacs = emacs, + wasm = wasm, + ) + .into(), + )); + return Ok(result); + } + }; + let wasm_end = { + if let Some(serde_json::Value::Number(end)) = wasm_standard_properties.get("end") { + end.as_u64() + .map(|w| w as usize) + .ok_or("End should be a number.")? + } else { + result.status.push(WasmDiffStatus::Bad( + format!( + "AST node type mismatch. Emacs=({emacs:?}) Wasm=({wasm:?}).", + emacs = emacs, + wasm = wasm, + ) + .into(), + )); + return Ok(result); + } + }; + let wasm_text: String = source + .chars() + .skip(wasm_begin - 1) + .take(wasm_end - wasm_begin) + .collect(); + if wasm_text != emacs_text { + result.status.push(WasmDiffStatus::Bad( + format!( + "Text mismatch. Emacs=({emacs:?}) Wasm=({wasm:?}).", + emacs = emacs_text, + wasm = wasm_text, + ) + .into(), + )); + return Ok(result); + } + + let emacs_start = emacs + .properties + .first() + .map(|t| t.as_atom()) + .map_or(Ok(None), |r| r.map(Some))?; + if emacs_start != Some("0") { + result.status.push(WasmDiffStatus::Bad( + format!( + "Text should start at offset 0. Emacs=({emacs:?}) Wasm=({wasm:?}).", + emacs = emacs, + wasm = wasm, + ) + .into(), + )); + } + let emacs_end = emacs + .properties + .get(1) + .map(|t| t.as_atom()) + .map_or(Ok(None), |r| r.map(Some))?; + if emacs_end != Some((wasm_end - wasm_begin).to_string().as_str()) { + result.status.push(WasmDiffStatus::Bad( + format!( + "Text end mismatch. Emacs=({emacs:?}) Wasm=({wasm:?}).", + emacs = emacs_end, + wasm = wasm_end - wasm_begin, + ) + .into(), + )); + } + + Ok(result) +} + // pub fn old_wasm_compare_document<'b, 's, 'p>( // source: &'s str, // emacs: &'b Token<'s>,