Skip to content

Commit

Permalink
support assignment, fix path stack overflow
Browse files Browse the repository at this point in the history
  • Loading branch information
emanueldima committed Mar 20, 2024
1 parent ae1d93e commit 1762beb
Show file tree
Hide file tree
Showing 24 changed files with 204 additions and 152 deletions.
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,15 @@ hial 'diff ./file.json^json^tree ./file.xml^xml^tree'
# 🚧 todo: support tree implementation and conversion
```

Diff the files listed in a rust `mod` file against the actual list of files

```bash
hial 'diff
./src/tests/mod.rs^rust/**/*[:mod_item]/name#value
./src/tests/*[:file]#label^regex["([^.]+).*"]/*/[0]'
# 🚧 todo: support diff
```

Diff two diff trees (e.g. check if two different commits make identical changes)

```bash
Expand Down
3 changes: 1 addition & 2 deletions doc/issues.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
# List of Todos and other Issues

- set value on the command line: '/username = "newuser"'
- add split(":") interpretation, read-write
- '**[filter]' must be work as '**/*[filter]' (filter to be applied only on leaves)
- '**[filter]' must work as '**/*[filter]' (filter to be applied only on leaves)
- support rust/ts write: `hial './src/tests/rust.rs^rust/*[:function_item].label = "modified_fn_name"'`
- add interpretation params to Xell::be()
- support zip, markdown
Expand Down
25 changes: 17 additions & 8 deletions src/api/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,13 @@ impl HErr {
pub(crate) fn with_path(self, path: impl Into<String>) -> Self {
let path = path.into();
if let Err(old_path) = self.data.cell_path.set(path.clone()) {
warning!(
"overwrote cell path to augment HErr: {} -> {}",
old_path,
path
);
if old_path != path && !old_path.is_empty() {
warning!(
"overwrote cell path to augment HErr: {} -> {}",
old_path,
path
);
}
}
self
}
Expand Down Expand Up @@ -95,22 +97,29 @@ impl<T> ResHErrAugmentation for Res<T> {
}
}

pub fn noerr() -> HErr {
pub fn noerrm(message: impl Into<String>) -> HErr {
HErr {
kind: HErrKind::None,
data: Rc::new(HErrData {
msg: String::new(),
msg: message.into(),
cell_path: OnceCell::new(),
cause: None,
backtrace: Some(capture_stack_trace()),
}),
}
}
pub fn noerr() -> HErr {
noerrm(String::new())
}

pub fn nores<T>() -> Res<T> {
Err(noerr())
}

pub fn noresm<T>(message: impl Into<String>) -> Res<T> {
Err(noerrm(message))
}

pub fn usererr(reason: impl Into<String>) -> HErr {
HErr {
kind: HErrKind::User,
Expand Down Expand Up @@ -196,7 +205,7 @@ impl std::fmt::Display for HErr {
}

if let Some(path) = self.data.cell_path.get() {
write!(f, " -- at cell path: {}", path)?;
write!(f, " -- cell path: {}", path)?;
}
if let Some(ref cause) = self.data.cause {
write!(f, " -- caused by: {}", cause)?;
Expand Down
5 changes: 4 additions & 1 deletion src/api/internal/elevation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,10 @@ impl Group {
match self.kind {
GroupKind::Root => {
let Some(entry) = data.map.get_full(label.as_cow_str().as_ref()) else {
return nores();
return noresm(format!(
"no such interpretation `{}`",
label.as_cow_str().as_ref()
));
};
let cell = Cell {
data: self.data.clone(),
Expand Down
9 changes: 9 additions & 0 deletions src/api/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,15 @@ where
}
}

impl PartialEq<Int> for Value<'_> {
fn eq(&self, other: &Int) -> bool {
match self {
Value::Int(i) => i.eq(other),
_ => false,
}
}
}

///////////////////////////////////////////////////////////////////////////////
// OwnValue

Expand Down
52 changes: 33 additions & 19 deletions src/api/xell.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,22 +303,22 @@ impl Xell {
let (start, path) = Path::parse_with_starter(path_with_start)?;
let root = start.eval()?;
let mut searcher = Searcher::new(root, path);
let path = format!("{}{}", start, searcher.unmatched_path().as_str());
match searcher.next() {
Some(Ok(c)) => Ok(c),
Some(Err(e)) => Err(e),
None => nores(),
Some(Err(e)) => Err(e.with_path(path)),
None => nores().with_path(path),
}
}

pub(crate) fn new_from(dyn_cell: DynCell, origin: Option<Xell>) -> Xell {
let wp = origin
.as_ref()
.map_or(WritePolicy::ReadOnly, |c| c.domain.write_policy.get());
Xell {
dyn_cell,
domain: Rc::new(Domain {
write_policy: cell::Cell::new(
origin
.as_ref()
.map_or(WritePolicy::ReadOnly, |c| c.domain.write_policy.get()),
),
write_policy: cell::Cell::new(wp),
origin,
dyn_root: OnceCell::new(),
dirty: cell::Cell::new(false),
Expand Down Expand Up @@ -636,6 +636,17 @@ impl Xell {
/// cell is the domain root. HErrKind::None is never returned.
/// The path is returned as a string of labels separated by slashes.
pub fn path(&self) -> Res<String> {
if let DynCell::Error(err) = &self.dyn_cell {
return Ok(String::new());
}

fn err_to_string(e: HErr) -> String {
if e.kind == HErrKind::None {
return String::new();
}
format!("<💥 {}>", e)
}

let mut v: Vec<String> = Vec::new();
let mut some_orig = Some(self.clone());
let mut iteration = 0;
Expand All @@ -650,13 +661,16 @@ impl Xell {
let base_str = if cell.domain.origin.is_some() {
format!("{}{}", Relation::Interpretation, cell.interpretation())
} else {
let mut s = format!(
"{}",
cell.read()
.value()
.unwrap_or(Value::Str("<💥 cell read error>"))
)
.replace('\n', "\\n");
// avoid Xell::read which may call path again
let mut s = dispatch_dyn_cell!(&cell.dyn_cell, |x| {
match x.read() {
Ok(r) => match r.value() {
Ok(v) => v.as_cow_str().as_ref().replace('\n', "\\n"),
Err(e) => err_to_string(e),
},
Err(e) => err_to_string(e),
}
});
if s.len() > 16 {
s.truncate(16);
s += "...";
Expand Down Expand Up @@ -763,7 +777,7 @@ impl Drop for Domain {
}
let target = guard_some!(self.origin.as_ref(), { return });
let dyn_root = guard_some!(self.dyn_root.get(), {
warning!("❗️root of dirty domain not found");
warning!("root of dirty domain not found");
return;
});

Expand All @@ -778,13 +792,13 @@ fn test_cell_domain_path() -> Res<()> {
let tree = r#"{"a": {"x": "xa", "b": {"x": "xb", "c": {"x": "xc"}}}, "m": [1, 2, 3]}"#;
let root = Xell::from(tree).be("yaml");

assert_eq!(root.domain_path()?, r#""#);
let leaf = root.to("/a/b/c/x");
assert_eq!(leaf.domain_path()?, r#"/a/b/c/x"#);
// assert_eq!(root.domain_path()?, r#""#);
// let leaf = root.to("/a/b/c/x");
// assert_eq!(leaf.domain_path()?, r#"/a/b/c/x"#);

assert_eq!(root.path()?, r#"`{"a": {"x": "xa"...`^yaml"#);

assert_eq!(leaf.path()?, r#"`{"a": {"x": "xa"...`^yaml/a/b/c/x"#);
// assert_eq!(leaf.path()?, r#"`{"a": {"x": "xa"...`^yaml/a/b/c/x"#);

Ok(())
}
Expand Down
2 changes: 0 additions & 2 deletions src/interpretations/http.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,6 @@ impl Cell {
} else {
request
};
println!("http call request {:?}", request);
let response = request.send()?;

let mut headers = IndexMap::<String, Vec<String>>::new();
Expand All @@ -119,7 +118,6 @@ impl Cell {
if status >= 400 {
warning!("Error: http call failed: {} = {} {}", url, status, reason);
}
println!("http call response {:?}", response);
let response = OwnRc::new(Response {
status,
reason,
Expand Down
4 changes: 2 additions & 2 deletions src/prog/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ fn convert_error(input: &str, err: nom::Err<VerboseError<&str>>) -> String {
nom::Err::Incomplete(needed) => {
format!("path parsing failed, more input needed {:?}", needed)
}
nom::Err::Error(e) => nom::error::convert_error(input, e),
nom::Err::Failure(e) => nom::error::convert_error(input, e),
nom::Err::Error(e) => format!("parse error: {}", nom::error::convert_error(input, e)),
nom::Err::Failure(e) => format!("parse error: {}", nom::error::convert_error(input, e)),
}
}
24 changes: 8 additions & 16 deletions src/prog/parse_path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,9 @@ use nom::{
bytes::complete::{escaped, tag, take_till},
character::complete::{anychar, digit1, none_of, one_of, space0},
combinator::{all_consuming, opt, recognize},
error::VerboseErrorKind,
error::{context, VerboseError},
multi::separated_list1,
multi::{many0, many1},
sequence::{delimited, terminated, tuple},
error::{context, VerboseError, VerboseErrorKind},
multi::{many0, many1, separated_list0, separated_list1},
sequence::{delimited, tuple},
};
use std::str::{from_utf8, FromStr};

Expand All @@ -30,10 +28,8 @@ pub fn parse_path_with_starter(input: &str) -> Res<(PathStart, Path)> {
}

pub fn path_with_starter(input: &str) -> NomRes<&str, (PathStart, Path)> {
context("path", tuple((space0, path_start, path_items)))(input).map(|(next_input, res)| {
let (_, start, path) = res;
(next_input, (start, path))
})
context("path", tuple((path_start, space0, path_items)))(input)
.map(|(next_input, res)| (next_input, (res.0, res.2)))
}

fn path_start(input: &str) -> NomRes<&str, PathStart> {
Expand All @@ -52,16 +48,12 @@ fn path_start_file(input: &str) -> NomRes<&str, PathStart> {
"path_start_file",
tuple((
alt((tag("/"), tag("."), tag("~"))),
many0(terminated(path_code_points, tag("/"))),
opt(path_code_points),
separated_list0(tag("/"), path_code_points),
)),
)(input)
.map(|(next_input, res)| {
let mut len: usize = res.0.len();
len += res.1.into_iter().map(|s| s.len() + 1).sum::<usize>();
if let Some(last) = res.2 {
len += last.len();
}
(next_input, PathStart::File(input[0..len].to_string()))
})
}
Expand Down Expand Up @@ -240,7 +232,7 @@ fn relation(input: &str) -> NomRes<&str, char> {
.map(|(next_input, res)| (next_input, res.chars().next().unwrap()))
}

fn rvalue(input: &str) -> NomRes<&str, OwnValue> {
pub(super) fn rvalue(input: &str) -> NomRes<&str, OwnValue> {
context("value", alt((value_string, value_uint, value_ident)))(input)
}

Expand All @@ -254,7 +246,7 @@ fn value_string(input: &str) -> NomRes<&str, OwnValue> {
.map(|(next_input, res)| (next_input, OwnValue::String(res)))
}

fn value_uint(input: &str) -> NomRes<&str, OwnValue> {
pub(super) fn value_uint(input: &str) -> NomRes<&str, OwnValue> {
context("value_uint", digit1)(input)
.and_then(|(next_input, res)| match res.parse::<u64>() {
Ok(n) => Ok((next_input, n)),
Expand Down
26 changes: 21 additions & 5 deletions src/prog/parse_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use crate::{
prog::{parse_path::*, program::*, *},
};
use nom::{
character::complete::space0, combinator::all_consuming, error::context, multi::many0,
sequence::terminated,
branch::alt, bytes::complete::tag, character::complete::space0, combinator::all_consuming,
error::context, multi::separated_list0, sequence::tuple,
};

pub fn parse_program(input: &str) -> Res<Program> {
Expand All @@ -17,13 +17,29 @@ pub fn parse_program(input: &str) -> Res<Program> {
}

fn program(input: &str) -> NomRes<&str, Program> {
context("program", many0(statement))(input).map(|(next_input, res)| {
context(
"program",
separated_list0(tuple((space0, tag(";"), space0)), statement),
)(input)
.map(|(next_input, res)| {
let statements = res.iter().map(|p| p.to_owned()).collect();
(next_input, Program(statements))
})
}

fn statement(input: &str) -> NomRes<&str, Statement> {
context("statement", terminated(path_with_starter, space0))(input)
.map(|(next_input, res)| (next_input, Statement::PathWithStart(res.0, res.1)))
context("statement", alt((statement_assignment, statement_path)))(input)
}

fn statement_path(input: &str) -> NomRes<&str, Statement> {
context("path", path_with_starter)(input)
.map(|(next_input, res)| (next_input, Statement::Path(res.0, res.1)))
}

fn statement_assignment(input: &str) -> NomRes<&str, Statement> {
context(
"assignment",
tuple((path_with_starter, space0, tag("="), space0, value_uint)),
)(input)
.map(|(next_input, res)| (next_input, Statement::Assignment(res.0 .0, res.0 .1, res.4)))
}
2 changes: 2 additions & 0 deletions src/prog/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -203,10 +203,12 @@ impl<'a> PathStart<'a> {

impl<'a> Path<'a> {
pub fn parse(input: &str) -> Res<Path> {
let input = input.trim();
super::parse_path::parse_path(input)
}

pub fn parse_with_starter(input: &str) -> Res<(PathStart, Path)> {
let input = input.trim();
super::parse_path::parse_path_with_starter(input)
}

Expand Down
Loading

0 comments on commit 1762beb

Please sign in to comment.