diff --git a/Cargo.lock b/Cargo.lock index 6da6f8c..28e5a2c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -26,63 +26,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "anstream" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d664a92ecae85fd0a7392615844904654d1d5f5514837f471ddef4a057aba1b6" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" - -[[package]] -name = "anstyle-parse" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7" -dependencies = [ - "anstyle", - "windows-sys 0.52.0", -] - -[[package]] -name = "anyhow" -version = "1.0.77" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9d19de80eff169429ac1e9f48fffb163916b448a44e8e046186232046d9e1f9" -dependencies = [ - "backtrace", -] - [[package]] name = "atty" version = "0.2.14" @@ -151,7 +94,7 @@ version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da6bc11b07529f16944307272d5bd9b22530bc7d05751717c9d416586cedab49" dependencies = [ - "clap 3.2.25", + "clap", "heck", "indexmap 1.9.3", "log", @@ -166,12 +109,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.83" +version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" [[package]] name = "cfg-if" @@ -187,47 +127,13 @@ checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", "bitflags 1.3.2", - "clap_lex 0.2.4", + "clap_lex", "indexmap 1.9.3", "strsim", "termcolor", "textwrap", ] -[[package]] -name = "clap" -version = "4.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcfab8ba68f3668e89f6ff60f5b205cea56aa7b769451a59f34b8682f51c056d" -dependencies = [ - "clap_builder", - "clap_derive", -] - -[[package]] -name = "clap_builder" -version = "4.4.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb7fb5e4e979aec3be7791562fcba452f94ad85e954da024396433e0e25a79e9" -dependencies = [ - "anstream", - "anstyle", - "clap_lex 0.6.0", - "strsim", -] - -[[package]] -name = "clap_derive" -version = "4.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn 2.0.46", -] - [[package]] name = "clap_lex" version = "0.2.4" @@ -237,18 +143,6 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "clap_lex" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" - -[[package]] -name = "colorchoice" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" - [[package]] name = "core-foundation" version = "0.9.4" @@ -424,7 +318,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap 2.1.0", + "indexmap 2.2.5", "slab", "tokio", "tokio-util", @@ -468,12 +362,10 @@ checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" name = "hiallib" version = "0.1.0" dependencies = [ - "anyhow", "cbindgen", "cc", - "clap 4.4.12", "dirs", - "indexmap 2.1.0", + "indexmap 2.2.5", "linkme", "nom", "paste", @@ -582,9 +474,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.1.0" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -935,9 +827,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.2" +version = "1.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick", "memchr", @@ -947,9 +839,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -1083,7 +975,7 @@ version = "1.0.108" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.5", "itoa", "ryu", "serde", @@ -1296,7 +1188,7 @@ version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1a195ec8c9da26928f773888e0742ca3ca1040c6cd859c919c9f59c1954ab35" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.5", "serde", "serde_spanned", "toml_datetime", @@ -1318,7 +1210,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.2.5", "serde", "serde_spanned", "toml_datetime", @@ -1352,9 +1244,9 @@ dependencies = [ [[package]] name = "tree-sitter" -version = "0.20.10" +version = "0.22.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e747b1f9b7b931ed39a548c1fae149101497de3c1fc8d9e18c62c1a66c683d3d" +checksum = "bdb9c9f15eae91dcd00ee0d86a281d16e6263786991b662b34fa9632c21a046b" dependencies = [ "cc", "regex", @@ -1398,12 +1290,6 @@ dependencies = [ "percent-encoding", ] -[[package]] -name = "utf8parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" - [[package]] name = "vcpkg" version = "0.2.15" diff --git a/Cargo.toml b/Cargo.toml index 6036fac..7aa21dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,19 +9,17 @@ publish = false crate-type = ["lib", "cdylib"] [dependencies] -anyhow = { version = "1", features = ["backtrace"] } -clap = { version = "4.4", features = ["suggestions", "derive"] } dirs = "5.0" -indexmap = "2.1" +indexmap = "2.2" linkme = "0.3" nom = "7.1" paste = "1.0" rand = "0.8" -regex = "1.5" +regex = "1.10" reqwest = { version = "0.11", features = ["blocking", "json"] } serde = { version = "1.0" } -tree-sitter = "0.20" -url = "2.1" +tree-sitter = "0.22" +url = "2.5" quick-xml = { version = "0.31", features = ["encoding"] } yaml-rust = "0.4" diff --git a/doc/issues.md b/doc/issues.md index a3e6b52..3508285 100644 --- a/doc/issues.md +++ b/doc/issues.md @@ -1,7 +1,7 @@ # List of Todos and other Issues - - add split(":") interpretation, read-write - 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) - support rust/ts write: `hial './src/tests/rust.rs^rust/*[:function_item].label = "modified_fn_name"'` - add interpretation params to Xell::be() diff --git a/examples/print_rust.rs b/examples/print_rust.rs index 95e08ab..627c6e9 100644 --- a/examples/print_rust.rs +++ b/examples/print_rust.rs @@ -1,5 +1,5 @@ use hiallib::api::*; -use hiallib::pprint::pprint; +use hiallib::pprint; // examples = "."^file/examples; // for stack in examples/productiondump.json^json/stacks/*[/system_stack != true]: diff --git a/src/api/value.rs b/src/api/value.rs index fc9a201..8a4cb7c 100644 --- a/src/api/value.rs +++ b/src/api/value.rs @@ -384,6 +384,16 @@ impl From for Value<'_> { Value::Int(Int::U64(x)) } } +impl From for Value<'_> { + fn from(x: isize) -> Self { + Value::Int(Int::I64(x as i64)) + } +} +impl From for Value<'_> { + fn from(x: usize) -> Self { + Value::Int(Int::U64(x as u64)) + } +} impl From for Value<'_> { fn from(f: StrFloat) -> Self { Value::Float(f) diff --git a/src/api/xell.rs b/src/api/xell.rs index 5b0ff51..aa2fe30 100644 --- a/src/api/xell.rs +++ b/src/api/xell.rs @@ -8,7 +8,7 @@ use crate::{ api::{internal::*, interpretation::*, *}, enumerated_dynamic_type, guard_ok, guard_some, interpretations::*, - search::{searcher::Searcher, Path}, + prog::{searcher::Searcher, Path}, warning, }; @@ -466,7 +466,7 @@ impl Xell { if let DynCell::Error(err) = &self.dyn_cell { return self.clone(); } - let path = guard_ok!(crate::search::Path::parse(path), err => + let path = guard_ok!(Path::parse(path), err => return Xell { dyn_cell: DynCell::from(err), domain: Rc::clone(&self.domain), @@ -500,7 +500,7 @@ impl Xell { if let DynCell::Error(err) = &self.dyn_cell { return Err(err.clone()); } - let path = guard_ok!(crate::search::Path::parse(path), err => {return Err(err)}); + let path = guard_ok!(crate::prog::Path::parse(path), err => {return Err(err)}); Ok(Searcher::new(self.clone(), path)) } diff --git a/src/interpretations/treesitter.rs b/src/interpretations/treesitter.rs index 5c2d094..0ed9acd 100644 --- a/src/interpretations/treesitter.rs +++ b/src/interpretations/treesitter.rs @@ -127,7 +127,7 @@ fn sitter_from_source(source: String, language: String) -> Res { // } let mut parser = Parser::new(); - guard_ok!(parser.set_language(sitter_language), err => { + guard_ok!(parser.set_language(&sitter_language), err => { return Err(caused(HErrKind::Internal, format!("cannot set language {}", language), err)); }); diff --git a/src/lib.rs b/src/lib.rs index 4c2df08..826c4dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,10 +12,11 @@ pub mod api; // pub mod c_api; mod interpretations; pub mod perftests; -pub mod pprint; -pub mod search; +pub mod prog; pub mod utils; +pub use utils::pprint::pprint; + #[cfg(test)] mod tests; diff --git a/src/main.rs b/src/main.rs index 42f43a2..3d3f910 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,90 +1,60 @@ -use clap::{Parser, Subcommand}; +use hiallib::{ + api::*, + prog::{Program, ProgramParams}, + *, +}; -use hiallib::{api::*, pprint::pprint, search::Path, *}; - -#[derive(Debug, Parser)] -#[command(author, version, about, long_about = None)] -#[command(propagate_version = true)] -struct Cli { - #[command(subcommand)] - command: Option, +#[derive(Clone, Debug, Default)] +struct Args { + depth: Option, + breadth: Option, + program: String, } -#[derive(Debug, Subcommand)] -enum Commands { - Ls { - #[arg(short, long)] - verbose: bool, - #[arg(short, long, default_value = "0")] - depth: Option, - #[arg(short, long, default_value = "0")] - breadth: Option, - path: Option, - }, - Test { - #[arg(short, long)] - verbose: bool, - }, +fn main() -> Res<()> { + let args = parse_args()?; + + if args.program.is_empty() { + eprintln!("No program given."); + return Ok(()); + } + + debug!("Command: run {}", args.program); + let program = Program::parse(&args.program)?; + let params = ProgramParams { + print_depth: args.depth.unwrap_or(0), + print_breadth: args.breadth.unwrap_or(0), + }; + program.run(params)?; + Ok(()) } -fn main() -> Res<()> { - let args = Cli::parse(); +fn parse_args() -> Res { + let mut args = Args::default(); - match &args.command { - None => { - debug!("No command.") - } - Some(Commands::Test { verbose }) => { - utils::log::set_verbose(*verbose); - debug!("Command: test"); - } - Some(Commands::Ls { - verbose, - depth, - breadth, - path, - }) => { - utils::log::set_verbose(*verbose); - let depth = depth.unwrap_or(0); - let breadth = breadth.unwrap_or(0); - let path = path.as_deref().unwrap_or(""); - if path.is_empty() { - eprintln!("No path given."); - return Ok(()); + let mut args_iter = std::env::args().skip(1).peekable(); + let mut in_flags = true; + while let Some(a) = args_iter.next() { + match a.as_str() { + "-v" | "--verbose" if in_flags => { + utils::log::set_verbose(true); } - debug!("Command: print {}", path); - let (path_start, path) = match Path::parse_with_starter(path) { - Ok(x) => x, - Err(err) => { - if err.kind == HErrKind::User { - eprintln!("Bad path: {}", err); - return Ok(()); - } else { - return Err(err); - } - } - }; - debug!("Root: {}", path_start); - debug!("Path: {}", path); - let root = path_start.eval()?; - let start_value = root.path().unwrap_or_default(); - - let mut anyfound = false; - let mut eval_iter = path.eval(root.clone()); - for cell in &mut eval_iter { - anyfound = true; - match cell { - Ok(cell) => pprint(&cell, depth, breadth), - Err(err) => eprintln!("{:?}", err), - } + "-d" if in_flags => { + args.depth = args_iter.peek().and_then(|s| s.parse().ok()); + } + "-b" if in_flags => { + args.breadth = args_iter.peek().and_then(|s| s.parse().ok()); } - if !anyfound { - println!( - "No match for {}", - start_value + eval_iter.unmatched_path().as_str() - ); + "--" if in_flags => { + in_flags = false; + } + _ => { + in_flags = false; + args.program += a.as_str(); + args.program += " "; } } } - Ok(()) + + Ok(args) } diff --git a/src/prog/mod.rs b/src/prog/mod.rs new file mode 100644 index 0000000..9d4e41a --- /dev/null +++ b/src/prog/mod.rs @@ -0,0 +1,24 @@ +pub(crate) mod path; +pub(crate) mod program; +pub(crate) mod searcher; +pub(crate) mod url; + +pub(super) mod parse_path; +pub(super) mod parse_program; +pub(super) mod parse_url; + +pub use path::{Path, PathStart}; +pub use program::{Program, ProgramParams}; + +use nom::{error::VerboseError, IResult}; +pub type NomRes = IResult>; + +fn convert_error(input: &str, err: nom::Err>) -> String { + match err { + 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), + } +} diff --git a/src/search/parse.rs b/src/prog/parse_path.rs similarity index 87% rename from src/search/parse.rs rename to src/prog/parse_path.rs index 49ea37f..d4ccc12 100644 --- a/src/search/parse.rs +++ b/src/prog/parse_path.rs @@ -1,49 +1,37 @@ -use crate::{api::*, guard_ok, search::path::*, search::url::*}; -use nom::bytes::complete::take_till; -use nom::character::complete::{anychar, space0}; -use nom::error::VerboseErrorKind; -use nom::multi::separated_list1; +use super::{convert_error, NomRes}; +use crate::{ + api::*, + guard_ok, + prog::{parse_url::*, path::*}, +}; use nom::{ branch::alt, - bytes::complete::{escaped, tag}, - character::complete::{digit1, none_of, one_of}, + 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}, - IResult, }; use std::str::{from_utf8, FromStr}; -pub type NomRes = IResult>; - -impl<'a> Path<'a> { - pub fn parse(input: &str) -> Res { - let path_res = all_consuming(path_items)(input); - let path = guard_ok!(path_res, err => { return userres(convert_error(input, err))}); - Ok(path.1) - } - - pub fn parse_with_starter(input: &str) -> Res<(PathStart, Path)> { - let path_res = all_consuming(path_with_starter)(input); - let path = guard_ok!(path_res, err => { return userres(convert_error(input, err))}); - Ok(path.1) - } +pub fn parse_path(input: &str) -> Res { + let path_res = all_consuming(path_items)(input); + let path = guard_ok!(path_res, err => { return userres(convert_error(input, err))}); + Ok(path.1) } -fn convert_error(input: &str, err: nom::Err>) -> String { - match err { - 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), - } +pub fn parse_path_with_starter(input: &str) -> Res<(PathStart, Path)> { + let path_res = all_consuming(path_with_starter)(input); + let path = guard_ok!(path_res, err => { return userres(convert_error(input, err))}); + Ok(path.1) } -fn path_with_starter(input: &str) -> NomRes<&str, (PathStart, Path)> { - context("path", tuple((path_start, path_items)))(input).map(|(next_input, res)| { - let (start, path) = res; +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)) }) } diff --git a/src/prog/parse_program.rs b/src/prog/parse_program.rs new file mode 100644 index 0000000..63833b8 --- /dev/null +++ b/src/prog/parse_program.rs @@ -0,0 +1,29 @@ +use crate::{ + api::*, + guard_ok, + prog::{parse_path::*, program::*, *}, +}; +use nom::{ + character::complete::space0, combinator::all_consuming, error::context, multi::many0, + sequence::terminated, +}; + +pub fn parse_program(input: &str) -> Res { + let statements_res = all_consuming(program)(input); + let statements = guard_ok!(statements_res, err => { + return userres(convert_error(input, err)) + }); + Ok(statements.1) +} + +fn program(input: &str) -> NomRes<&str, Program> { + context("program", many0(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))) +} diff --git a/src/search/url.rs b/src/prog/parse_url.rs similarity index 88% rename from src/search/url.rs rename to src/prog/parse_url.rs index f494984..c4df4fa 100644 --- a/src/search/url.rs +++ b/src/prog/parse_url.rs @@ -1,4 +1,6 @@ -use super::parse::NomRes; +use crate::prog::url::*; + +use super::NomRes; use nom::{ branch::alt, bytes::complete::{tag, take}, @@ -9,73 +11,6 @@ use nom::{ sequence::{preceded, separated_pair, terminated, tuple}, AsChar, Err as NomErr, InputTakeAtPosition, }; -use std::fmt::{Display, Formatter}; - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Url<'a> { - scheme: Scheme, - authority: Option>, - host: Host, - port: Option, - path: Option>, - query: Option>, - fragment: Option<&'a str>, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Scheme(String); - -pub type Authority<'a> = (&'a str, Option<&'a str>); - -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Host { - Host(String), - IP([u8; 4]), -} - -pub type QueryParam<'a> = (&'a str, &'a str); -pub type QueryParams<'a> = Vec>; - -impl<'a> Display for Url<'a> { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - f.write_str(&self.scheme.0)?; - f.write_str("://")?; - if let Some(auth) = self.authority { - f.write_str(auth.0)?; - if let Some(auth2) = auth.1 { - f.write_str(auth2)?; - } - } - match &self.host { - Host::Host(s) => f.write_str(s)?, - Host::IP(ip) => f.write_fmt(format_args!("{}.{}.{}.{}", ip[0], ip[1], ip[2], ip[3]))?, - } - if let Some(port) = self.port { - f.write_fmt(format_args!(":{}", port))?; - } - if let Some(path) = &self.path { - for p in path { - f.write_str("/")?; - f.write_str(p)?; - } - } - if let Some(query) = &self.query { - f.write_str("?")?; - for (i, q) in query.iter().enumerate() { - f.write_str(q.0)?; - f.write_str("=")?; - f.write_str(q.1)?; - if i + 1 < query.len() { - f.write_str("&")?; - } - } - } - if let Some(fragment) = &self.fragment { - f.write_str(fragment)?; - } - Ok(()) - } -} pub fn url(input: &str) -> NomRes<&str, Url> { context( @@ -107,12 +42,6 @@ pub fn url(input: &str) -> NomRes<&str, Url> { }) } -impl From<&str> for Scheme { - fn from(i: &str) -> Self { - Self(i.to_lowercase()) - } -} - fn scheme(input: &str) -> NomRes<&str, Scheme> { context( "scheme", @@ -234,6 +163,7 @@ fn fragment(input: &str) -> NomRes<&str, &str> { context("fragment", tuple((tag("#"), url_code_points)))(input) .map(|(next_input, res)| (next_input, res.1)) } + fn alphanumerichyphen1(i: T) -> NomRes where T: InputTakeAtPosition, diff --git a/src/search/path.rs b/src/prog/path.rs similarity index 94% rename from src/search/path.rs rename to src/prog/path.rs index e795bc4..7361923 100644 --- a/src/search/path.rs +++ b/src/prog/path.rs @@ -2,13 +2,13 @@ use std::fmt::{Display, Formatter}; use crate::{ api::*, - search::{searcher::Searcher, url::*}, + prog::{searcher::Searcher, url::*}, }; #[derive(Clone, Debug, PartialEq)] pub struct Path<'a>(pub(crate) Vec>); -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] pub enum PathStart<'a> { Url(Url<'a>), File(String), @@ -202,6 +202,14 @@ impl<'a> PathStart<'a> { } impl<'a> Path<'a> { + pub fn parse(input: &str) -> Res { + super::parse_path::parse_path(input) + } + + pub fn parse_with_starter(input: &str) -> Res<(PathStart, Path)> { + super::parse_path::parse_path_with_starter(input) + } + pub fn eval(self, cell: Xell) -> Searcher<'a> { Searcher::new(cell, self) } diff --git a/src/prog/program.rs b/src/prog/program.rs new file mode 100644 index 0000000..02269db --- /dev/null +++ b/src/prog/program.rs @@ -0,0 +1,83 @@ +use crate::{ + api::*, + debug, pprint, + prog::{searcher::Searcher, *}, +}; +use std::fmt::{Display, Formatter}; + +macro_rules! ifdebug { + ( $body:expr ) => { + // $body + }; +} + +#[derive(Clone, Debug)] +pub struct Program<'a>(pub(crate) Vec>); + +#[derive(Clone, Debug)] +pub struct ProgramParams { + pub print_depth: usize, + pub print_breadth: usize, +} + +#[derive(Clone, Debug)] +pub enum Statement<'a> { + PathWithStart(PathStart<'a>, Path<'a>), +} + +#[derive(Clone, Debug)] +pub struct Executor<'a> { + program: Program<'a>, + statement_index: usize, + searcher: Option>, +} + +impl<'a> Display for Program<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + for statement in &self.0 { + writeln!(f, "{}", statement)?; + } + Ok(()) + } +} + +impl<'a> Display for Statement<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Statement::PathWithStart(start, path) => write!(f, "{}{}", start, path)?, + } + Ok(()) + } +} + +impl<'a> Program<'a> { + pub fn parse(input: &str) -> Res { + super::parse_program::parse_program(input) + } + + pub fn run(&self, params: ProgramParams) -> Res<()> { + for statement in &self.0 { + debug!("Running statement: {}", statement); + match statement { + Statement::PathWithStart(start, path) => { + ifdebug!(println!("-- PathWithStart: {} {}", start, path)); + let root = start.eval()?; + let mut searcher = Searcher::new(root, path.clone()); + let Some(rescell) = searcher.next() else { + continue; + }; + match rescell { + Ok(cell) => { + pprint(&cell, params.print_depth, params.print_breadth); + } + Err(e) => { + eprintln!("Error: {}", e); + } + }; + } + } + } + + Ok(()) + } +} diff --git a/src/search/searcher.rs b/src/prog/searcher.rs similarity index 99% rename from src/search/searcher.rs rename to src/prog/searcher.rs index 9ae1d79..2c276c0 100644 --- a/src/search/searcher.rs +++ b/src/prog/searcher.rs @@ -8,7 +8,7 @@ use crate::{ api::*, debug_err, guard_ok, guard_some, - search::{ + prog::{ path::{Expression, PathItem}, Path, }, diff --git a/src/prog/url.rs b/src/prog/url.rs new file mode 100644 index 0000000..374de50 --- /dev/null +++ b/src/prog/url.rs @@ -0,0 +1,73 @@ +use std::fmt::{Display, Formatter}; + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Url<'a> { + pub(super) scheme: Scheme, + pub(super) authority: Option>, + pub(super) host: Host, + pub(super) port: Option, + pub(super) path: Option>, + pub(super) query: Option>, + pub(super) fragment: Option<&'a str>, +} + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Scheme(pub(super) String); + +pub type Authority<'a> = (&'a str, Option<&'a str>); + +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Host { + Host(String), + IP([u8; 4]), +} + +pub type QueryParam<'a> = (&'a str, &'a str); +pub type QueryParams<'a> = Vec>; + +impl<'a> Display for Url<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.write_str(&self.scheme.0)?; + f.write_str("://")?; + if let Some(auth) = self.authority { + f.write_str(auth.0)?; + if let Some(auth2) = auth.1 { + f.write_str(auth2)?; + } + } + match &self.host { + Host::Host(s) => f.write_str(s)?, + Host::IP(ip) => f.write_fmt(format_args!("{}.{}.{}.{}", ip[0], ip[1], ip[2], ip[3]))?, + } + if let Some(port) = self.port { + f.write_fmt(format_args!(":{}", port))?; + } + if let Some(path) = &self.path { + for p in path { + f.write_str("/")?; + f.write_str(p)?; + } + } + if let Some(query) = &self.query { + f.write_str("?")?; + for (i, q) in query.iter().enumerate() { + f.write_str(q.0)?; + f.write_str("=")?; + f.write_str(q.1)?; + if i + 1 < query.len() { + f.write_str("&")?; + } + } + } + if let Some(fragment) = &self.fragment { + f.write_str(fragment)?; + } + Ok(()) + } +} + +impl From<&str> for Scheme { + fn from(i: &str) -> Self { + Self(i.to_lowercase()) + } +} diff --git a/src/search/mod.rs b/src/search/mod.rs deleted file mode 100644 index 45e5088..0000000 --- a/src/search/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -mod parse; -pub(crate) mod path; -pub(crate) mod searcher; -pub(crate) mod url; - -pub use path::Path; diff --git a/src/tests/fs.rs b/src/tests/fs.rs index 4470e0d..3a11a1e 100644 --- a/src/tests/fs.rs +++ b/src/tests/fs.rs @@ -1,4 +1,4 @@ -use crate::{api::*, search::path::Path}; +use crate::{api::*, prog::Path}; #[test] fn test_files() -> Res<()> { diff --git a/src/tests/http.rs b/src/tests/http.rs index 6855d31..e657550 100644 --- a/src/tests/http.rs +++ b/src/tests/http.rs @@ -1,4 +1,4 @@ -use crate::{api::*, pprint::pprint, utils::log::set_verbose}; +use crate::{api::*, pprint, utils::log::set_verbose}; #[test] fn test_http_basic() -> Res<()> { diff --git a/src/tests/ideals.rs b/src/tests/ideals.rs index 7c8579d..9c8f93a 100644 --- a/src/tests/ideals.rs +++ b/src/tests/ideals.rs @@ -1,4 +1,4 @@ -use crate::{api::*, pprint::pprint, utils::log::set_verbose}; +use crate::{api::*, pprint, utils::log::set_verbose}; const TREE: &str = r#" a: diff --git a/src/tests/json.rs b/src/tests/json.rs index 910a051..177940c 100644 --- a/src/tests/json.rs +++ b/src/tests/json.rs @@ -1,4 +1,4 @@ -use crate::{api::*, pprint::pprint, utils::log::set_verbose}; +use crate::{api::*, pprint, utils::log::set_verbose}; #[test] fn test_json() -> Res<()> { @@ -21,7 +21,7 @@ fn test_json() -> Res<()> { ] }"#; let json = Xell::from(json).be("json"); - // pprint::pprint(&json, 0, 0); + // pprint(&json, 0, 0); let hosts = json.sub().get("hosts").sub(); assert_eq!(hosts.len()?, 2); let host1 = hosts.at(0); @@ -130,7 +130,7 @@ fn json_write_and_save() -> Res<()> { let flattree = Xell::from(treestring).policy(WritePolicy::NoAutoWrite); let json = flattree.be("json"); - // pprint::pprint(&json, 0, 0); + // pprint(&json, 0, 0); let path1 = "/hosts/[1]/labels/power"; let newvalue = "weak as putty"; @@ -139,7 +139,7 @@ fn json_write_and_save() -> Res<()> { let path2 = "/hosts/[0]/host_id"; json.to(path2).write().value(OwnValue::None)?; - // pprint::pprint(&json, 0, 0); + // pprint(&json, 0, 0); assert_eq!(json.to(path1).read().value()?, newvalue); assert_eq!(json.to(path2).read().value()?, Value::None); diff --git a/src/tests/nested.rs b/src/tests/nested.rs index ae4449a..db9d8a3 100644 --- a/src/tests/nested.rs +++ b/src/tests/nested.rs @@ -1,4 +1,4 @@ -use crate::{api::*, pprint::pprint, utils::log::set_verbose}; +use crate::{api::*, pprint, utils::log::set_verbose}; #[test] fn test_nested_0() -> Res<()> { diff --git a/src/tests/search.rs b/src/tests/search.rs index 4334fa2..cd29c05 100644 --- a/src/tests/search.rs +++ b/src/tests/search.rs @@ -1,15 +1,32 @@ use crate::{ api::*, - pprint::pprint, - search::path::{ - ElevationPathItem, Expression, Filter, InterpretationParam, NormalPathItem, Path, PathItem, + pprint, + prog::{ + path::{ + ElevationPathItem, Expression, Filter, InterpretationParam, NormalPathItem, Path, + PathItem, + }, + program::Statement, + PathStart, Program, }, utils::log::set_verbose, }; +#[test] +fn path_simple_program() -> Res<()> { + let prog = Program::parse(".^regex[a] ")?; + match &prog.0[0] { + Statement::PathWithStart(start, path) => { + assert_eq!(start, &PathStart::File(".".to_string())); + assert_eq!(path, &Path::parse("^regex[a]")?); + } + } + Ok(()) +} + #[test] fn path_simple_elevation() -> Res<()> { - let path = Path::parse("^fs^fs.one[w]^fs.two[w=1]")?; + let path = Path::parse("^fs^fs.one[w]^fs.two[w=1] ")?; assert_eq!( path.0.as_slice(), &[ @@ -512,7 +529,7 @@ fn search_double_kleene_labels_json() -> Res<()> { let root = Xell::from(TREE).be("json"); - // crate::pprint::pprint(&root, 0, 0); + // crate::pprint(&root, 0, 0); let eval = str_eval(root.clone(), "/**#label")?; assert_eq!( eval, @@ -540,7 +557,7 @@ fn search_double_kleene_labels_yaml() -> Res<()> { let root = Xell::from(TREE).be("yaml"); - // crate::pprint::pprint(&root, 0, 0); + // crate::pprint(&root, 0, 0); let eval = str_eval(root.clone(), "/**#label")?; assert_eq!( eval, diff --git a/src/tests/toml.rs b/src/tests/toml.rs index cd86572..6477fd2 100644 --- a/src/tests/toml.rs +++ b/src/tests/toml.rs @@ -1,4 +1,4 @@ -use crate::{api::*, pprint::pprint}; +use crate::{api::*, pprint}; const TOML: &str = r#" # This is a TOML document diff --git a/src/tests/xml.rs b/src/tests/xml.rs index 39b766a..f4c24f5 100644 --- a/src/tests/xml.rs +++ b/src/tests/xml.rs @@ -16,7 +16,7 @@ fn test_xml() -> Res<()> { "#; let xml = Xell::from(xml.to_string()).be("xml"); - pprint::pprint(&xml, 0, 0); + pprint(&xml, 0, 0); let decl = xml.sub().at(0); assert_eq!(decl.read().label()?, "xml"); @@ -99,7 +99,7 @@ fn xml_write_and_save() -> Res<()> { .policy(WritePolicy::NoAutoWrite); let xml = text.be("xml"); - pprint::pprint(&xml, 0, 0); + pprint(&xml, 0, 0); assert_eq!(xml.to("/doc/q/qq").read().value()?, "4"); xml.to("/doc/q/qq").write().value("444")?; diff --git a/src/utils/mod.rs b/src/utils/mod.rs index 31c6ebb..b2b12e1 100644 --- a/src/utils/mod.rs +++ b/src/utils/mod.rs @@ -5,3 +5,4 @@ pub mod log; pub mod ownrc; pub mod ownrcutils; pub mod picoset; +pub mod pprint; diff --git a/src/pprint.rs b/src/utils/pprint.rs similarity index 100% rename from src/pprint.rs rename to src/utils/pprint.rs