From 41af9bd00a1f14b4aefc60061659616ba1bd71b8 Mon Sep 17 00:00:00 2001 From: Emanuel Dima Date: Tue, 5 Mar 2024 09:48:04 +0100 Subject: [PATCH] add Cell::all, cleanup some tests --- issues.md | 22 ++++++-- src/base/extra.rs | 118 +++++++++++++++++------------------------ src/pathlang/search.rs | 7 ++- src/tests/ideals.rs | 4 +- src/tests/json.rs | 2 +- src/tests/path.rs | 2 +- src/tests/rust.rs | 7 ++- src/tests/search.rs | 3 +- src/tests/toml.rs | 2 +- src/tests/xml.rs | 2 +- src/tests/yaml.rs | 2 +- 11 files changed, 83 insertions(+), 88 deletions(-) diff --git a/issues.md b/issues.md index 4b879f7..9fca4cd 100644 --- a/issues.md +++ b/issues.md @@ -7,11 +7,12 @@ - explicit and implicit write support (policy, include readonly) - fix tests, todo!() and TODO: in code -- change search: multiple path indices for one cell -- support type selector: `hial './src/tests/rust.rs^rust/:function_item'` -- support rust/ts write: `hial './src/tests/rust.rs^rust/:function_item[-1]#label = "modified_fn_name"'` +- support type selector: `hial './src/tests/rust.rs^rust/*[:function_item]'` +- support rust/ts write: `hial './src/tests/rust.rs^rust/*[:function_item].label = "modified_fn_name"'` - set value on the command line -- separate api module, used by ffi and dependent crates +- new structure: /api, /api/impl, /interpretations/api, /interpretations/*, /search + +- - operations: - assign to variables; @@ -24,11 +25,12 @@ - new/set/replace/delete group (only sub or attr group) - diff with assignment of results in variables +- ?change search: multiple path indices for one cell - ?treesitter representations are too detailed, unsure what to do - ?explore python implementation and usage - ?search should return all matches embedded in a delegation cell, which has all results as subs and delegates write operations to all the subs -- ?rename XCell, Cell, CellTrait to Nex? +- ?rename XCell, Cell, CellTrait to Nex/NexIn/NexInTrait - later: python, git, database, ical, zip, markdown @@ -98,3 +100,13 @@ './**[.name=='config.yaml'][as composefile]^yaml/services/*/image[^string^http@status/code!=200] tree 'result' -> [composefile] -> image ``` + +### Examples + +1. Extract the general structure of a rust file. Get the struct/enum/type definitions (just the name and the type) and the function definitions (just the name and the signature). Get all implementations of traits and the functions inside them, as a tree. + +``` +hial 'item = ./src/tests/rust.rs^rust/**[:struct_item|:enum_item|:type_item|:function_item]; item/' + +' +``` diff --git a/src/base/extra.rs b/src/base/extra.rs index cf6d6fa..add665a 100644 --- a/src/base/extra.rs +++ b/src/base/extra.rs @@ -5,11 +5,8 @@ use std::{ }; use crate::{ - base::*, - enumerated_dynamic_type, guard_ok, guard_some, - interpretations::*, - pathlang::{search::Searcher, Path}, - warning, + base::*, enumerated_dynamic_type, guard_ok, guard_some, interpretations::*, + pathlang::search::Searcher, warning, }; const MAX_PATH_ITEMS: usize = 1000; @@ -420,18 +417,44 @@ impl Cell { } pub fn to(&self, path: &str) -> Cell { + if let DynCell::Error(err) = &self.dyn_cell { + return self.clone(); + } let path = guard_ok!(crate::pathlang::Path::parse(path), err => return Cell { dyn_cell: DynCell::from(err), domain: Rc::clone(&self.domain), } ); - PathSearch::new(self.clone(), path).first() + let mut searcher = Searcher::new(self.clone(), path); + match searcher.next() { + Some(Ok(c)) => c, + Some(Err(e)) => Cell { + dyn_cell: DynCell::from(e), + domain: Rc::clone(&self.domain), + }, + None => { + let mut path = self.path().unwrap_or_default(); + path += searcher.unmatched_path().as_str(); + warning!("💥 path search failed: {}", path); + Cell { + dyn_cell: DynCell::from(noerr().with_path(path)), + domain: Rc::clone(&self.domain), + } + } + } } - pub fn search<'a>(&self, path: &'a str) -> Res> { + pub fn search<'a>(&self, path: &'a str) -> Res> { + if let DynCell::Error(err) = &self.dyn_cell { + return Err(err.clone()); + } let path = guard_ok!(crate::pathlang::Path::parse(path), err => {return Err(err)}); - Ok(PathSearch::new(self.clone(), path)) + Ok(Searcher::new(self.clone(), path)) + } + + pub fn all(&self, path: &str) -> Res> { + self.search(path)?.collect() } pub fn head(&self) -> Res<(Cell, Relation)> { @@ -621,15 +644,29 @@ impl Cell { s } - pub fn save(&self, target: Cell) -> Res<()> { + pub fn save(&self, target: &Cell) -> Res<()> { if let DynCell::Error(err) = &self.dyn_cell { return Err(err.clone()); } if let DynCell::Error(err) = &target.dyn_cell { return Err(err.clone()); } - let s = self.read().serial()?; - target.write().set_value(OwnValue::String(s)) + Self::save_from_to(&self.dyn_cell, target) + } + + pub fn save_domain(&self, target: &Cell) -> Res<()> { + if let DynCell::Error(err) = &target.dyn_cell { + return Err(err.clone()); + } + let dyn_root = guard_some!(self.domain.dyn_root.get(), { + return fault("domain root not found while saving domain"); + }); + Self::save_from_to(dyn_root, target) + } + + fn save_from_to(dyn_cell: &DynCell, target: &Cell) -> Res<()> { + let serial = dispatch_dyn_cell!(dyn_cell, |x| { x.read()?.serial()? }); + target.write().set_value(OwnValue::String(serial)) } } @@ -679,25 +716,8 @@ impl Drop for Domain { return; }); - let serial = dispatch_dyn_cell!(&dyn_root, |x| { - let r = guard_ok!(x.read(), e => { - warning!( - "💥 cannot read root while trying to auto-save domain: {:?}", - e - ); - return; - }); - guard_ok!(r.serial(), e => { - warning!("💥 cannot serialize root while trying to auto-save domain: {:?}", e); - return; - }) - }); - - if let Err(e) = target.write().set_value(OwnValue::String(serial)) { - warning!( - "💥 cannot write to domain origin while trying to auto-save domain: {:?}", - e - ); + if let Err(err) = Cell::save_from_to(dyn_root, target) { + warning!("💥 while trying to auto-save domain: {:?}", err); } } } @@ -954,41 +974,3 @@ impl CellIterator { } } } - -#[derive(Clone, Debug)] -pub struct PathSearch<'a> { - start: Cell, - // eval_iter: EvalIter<'a>, - searcher: Searcher<'a>, -} -impl<'a> PathSearch<'a> { - pub fn new(cell: Cell, path: Path<'a>) -> Self { - PathSearch { - start: cell.clone(), - searcher: Searcher::new(cell, path), - } - } - - pub fn first(mut self) -> Cell { - match self.searcher.next() { - Some(Ok(c)) => c, - Some(Err(e)) => Cell { - dyn_cell: DynCell::from(e), - domain: Rc::clone(&self.start.domain), - }, - None => { - let mut path = self.start.path().unwrap_or_default(); - path += self.searcher.unmatched_path().as_str(); - warning!("💥 path search failed: {}", path); - Cell { - dyn_cell: DynCell::from(noerr().with_path(path)), - domain: Rc::clone(&self.start.domain), - } - } - } - } - - pub fn all(self) -> Res> { - self.searcher.collect::>>() - } -} diff --git a/src/pathlang/search.rs b/src/pathlang/search.rs index 74236c6..3199d6c 100644 --- a/src/pathlang/search.rs +++ b/src/pathlang/search.rs @@ -17,7 +17,7 @@ use crate::{ macro_rules! ifdebug { ( $body:expr ) => { - $body + // $body }; } @@ -101,7 +101,10 @@ impl<'s> Searcher<'s> { "returning cell {:?}", cell.as_ref().map(|x| x.debug_string()) )); - return Some(cell); + match cell.and_then(|cell| cell.err()) { + Ok(cell) => return Some(Ok(cell)), + Err(e) => warning!("search error: {}", e), + } } } None diff --git a/src/tests/ideals.rs b/src/tests/ideals.rs index 11185f1..1b8b505 100644 --- a/src/tests/ideals.rs +++ b/src/tests/ideals.rs @@ -20,14 +20,14 @@ fn tree() -> Res<()> { // and write back by doing a put request let cell = Cell::from("./examples/write.json") .policy(WritePolicy::WriteBackOnDrop) - .to("^path^fs^json/"); + .to("^path^fs^json"); pprint(&cell, 0, 0); assert!(cell.clone().err().is_ok()); // assert!(cell.write().set_value("weak as putty".into()).is_ok()); // let cell = Cell::from(".") // .policy(WritePolicy::WriteBackOnDrop) - // .to("/examples/productiondump.json^file") + // .to("^path^fs/examples/productiondump.json") // .to("^json/stacks/*/dockerCompose") // .to("^docker.compose/services/scheduler/image") // .to("^docker.imagetag/tag") diff --git a/src/tests/json.rs b/src/tests/json.rs index 73f4abf..2274f4c 100644 --- a/src/tests/json.rs +++ b/src/tests/json.rs @@ -146,7 +146,7 @@ fn json_write_and_save() -> Res<()> { assert_eq!(json.to(path1).read().value()?, newvalue); assert_eq!(json.to(path2).read().value()?, Value::None); - json.save(json.origin())?; + json.save(&json.origin())?; assert_eq!( flattree.read().value()?.to_string(), diff --git a/src/tests/path.rs b/src/tests/path.rs index 5c1894e..574be63 100644 --- a/src/tests/path.rs +++ b/src/tests/path.rs @@ -24,7 +24,7 @@ fn test_multihop_path() -> Res<()> { let start = Cell::from("http://api.github.com"); let path = "^http^json/rate_limit_url^http^json/resources/core/limit"; - let results = start.search(path)?.all()?; + let results = start.all(path)?; assert_eq!(results.len(), 1); let result = &results[0]; diff --git a/src/tests/rust.rs b/src/tests/rust.rs index 4c1acbf..1454250 100644 --- a/src/tests/rust.rs +++ b/src/tests/rust.rs @@ -7,8 +7,7 @@ fn test_rust() -> Res<()> { let folder = Cell::from(".").be("path").be("fs").err().unwrap(); let root = folder.to("/src/tests/rust.rs^rust"); assert_eq!( - root.search("/*[#type=='function_item']/name")? - .all()? + root.all("/*[#type=='function_item']/name")? .into_iter() .map(|c| c.debug_string()) .collect::>(), @@ -48,7 +47,7 @@ fn rust_write_and_save() -> Res<()> { .set_value("modified_rust_fn".into())?; assert_eq!(root.to("/[7]/[1]").read().value()?, "modified_rust_fn"); - root.save(root.origin())?; + root.save(&root.origin())?; assert_eq!(file.to("^rust/[7]/[1]").read().value()?, "modified_rust_fn",); root.to("/[7]/[1]") @@ -56,7 +55,7 @@ fn rust_write_and_save() -> Res<()> { .set_value("editable_rust_fn".into())?; assert_eq!(root.to("/[7]/[1]").read().value()?, "editable_rust_fn"); - root.save(file.clone())?; + root.save(&file.clone())?; assert_eq!(file.to("^rust/[7]/[1]").read().value()?, "editable_rust_fn",); Ok(()) diff --git a/src/tests/search.rs b/src/tests/search.rs index f905b3f..88219ce 100644 --- a/src/tests/search.rs +++ b/src/tests/search.rs @@ -467,8 +467,7 @@ fn search_double_kleene_with_filter() -> Res<()> { } pub fn str_eval(root: Cell, path: &str) -> Res> { - root.search(path)? - .all()? + root.all(path)? .into_iter() .map(|cell| -> Res { // if let Ok(ref cell) = cres { diff --git a/src/tests/toml.rs b/src/tests/toml.rs index cfbeafb..447fbb7 100644 --- a/src/tests/toml.rs +++ b/src/tests/toml.rs @@ -56,7 +56,7 @@ fn toml_write_and_save() -> Res<()> { let v = toml.to("/number/x"); assert_eq!(v.read().value()?, Value::from(1.1415)); - toml.save(toml.origin())?; + v.save_domain(&toml.origin())?; let v = data.to("^toml/number/x"); assert_eq!(v.read().value()?, Value::from(1.1415)); diff --git a/src/tests/xml.rs b/src/tests/xml.rs index a18690a..19412c1 100644 --- a/src/tests/xml.rs +++ b/src/tests/xml.rs @@ -105,7 +105,7 @@ fn xml_write_and_save() -> Res<()> { xml.to("/doc/q/qq").write().set_value("444".into())?; assert_eq!(xml.to("/doc/q/qq").read().value()?, "444"); - xml.save(xml.origin())?; + xml.save(&xml.origin())?; let v = text.to("^xml/doc/q/qq"); assert_eq!(v.read().value()?, "444"); diff --git a/src/tests/yaml.rs b/src/tests/yaml.rs index 19de4fa..f456ef3 100644 --- a/src/tests/yaml.rs +++ b/src/tests/yaml.rs @@ -71,7 +71,7 @@ fn yaml_write_and_save() -> Res<()> { .set_value("putty".into())?; assert_eq!(yaml.to("/hosts/[0]/labels/power").read().value()?, "putty"); - yaml.save(yaml.origin())?; + yaml.save(&yaml.origin())?; let v = text.to("^yaml/hosts/[0]/labels/power"); assert_eq!(v.read().value()?, "putty");