diff --git a/jaq-core/src/load/debug.rs b/jaq-core/src/load/debug.rs new file mode 100644 index 000000000..78df81c5a --- /dev/null +++ b/jaq-core/src/load/debug.rs @@ -0,0 +1,102 @@ +use super::lex::StrPart; +use super::parse::{Def, Pattern, Term}; +use core::fmt::{self, Debug}; + +struct Into(T); + +impl Debug for Into { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.0.fmt(f)?; + write!(f, ".into()") + } +} + +struct Apply(&'static str, T); + +impl Debug for Apply { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple(self.0).field(&self.1).finish() + } +} + +impl Debug for Def { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("parse::Def") + .field("name", &self.name) + .field("args", &Into(&self.args)) + .field("body", &self.body) + .finish() + } +} + +impl Debug for Term { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use Term::*; + match self { + Id => f.debug_tuple("Id").finish(), + Recurse => f.debug_tuple("Recurse").finish(), + + Num(s) => f.debug_tuple("Num").field(s).finish(), + Str(fmt, parts) => f.debug_tuple("Str").field(fmt).field(&Into(parts)).finish(), + Arr(a) => f.debug_tuple("Arr").field(&a.as_ref().map(Into)).finish(), + Obj(o) => f.debug_tuple("Obj").field(&Into(o)).finish(), + Neg(t) => f.debug_tuple("Neg").field(&Into(t)).finish(), + Pipe(l, pat, r) => { + let (l, r) = (&Into(l), &Into(r)); + f.debug_tuple("Pipe").field(l).field(pat).field(r).finish() + } + BinOp(l, op, r) => { + let (l, r) = (&Into(l), &Into(r)); + f.debug_tuple("BinOp").field(l).field(op).field(r).finish() + } + Label(x, t) => f.debug_tuple("Label").field(x).field(&Into(t)).finish(), + Break(x) => f.debug_tuple("Break").field(x).finish(), + Fold(x, xs, pat, args) => f + .debug_tuple("Fold") + .field(x) + .field(&Into(xs)) + .field(pat) + .field(&Into(args)) + .finish(), + TryCatch(try_, catch) => { + let (t, c) = (Into(try_), catch.as_ref().map(Into)); + f.debug_tuple("TryCatch").field(&t).field(&c).finish() + } + IfThenElse(if_thens, else_) => { + let (it, e) = (Into(if_thens), else_.as_ref().map(Into)); + f.debug_tuple("IfThenElse").field(&it).field(&e).finish() + } + Def(defs, t) => f + .debug_tuple("Def") + .field(&Into(defs)) + .field(&Into(t)) + .finish(), + Call(x, args) => f.debug_tuple("Call").field(x).field(&Into(args)).finish(), + Var(x) => f.debug_tuple("Var").field(x).finish(), + Path(t, path) => { + let path = Apply("path::Path", Into(&path.0)); + f.debug_tuple("Path").field(&Into(t)).field(&path).finish() + } + } + } +} + +impl Debug for Pattern { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Var(x) => f.debug_tuple("Pattern::Var").field(x).finish(), + Self::Arr(a) => f.debug_tuple("Pattern::Arr").field(&Into(a)).finish(), + Self::Obj(o) => f.debug_tuple("Pattern::Obj").field(&Into(o)).finish(), + } + } +} + +impl Debug for StrPart { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Self::Str(s) => f.debug_tuple("StrPart::Str").field(s).finish(), + Self::Term(t) => f.debug_tuple("StrPart::Term").field(t).finish(), + Self::Char(c) => f.debug_tuple("StrPart::Char").field(c).finish(), + } + } +} diff --git a/jaq-core/src/load/lex.rs b/jaq-core/src/load/lex.rs index 0825f34a3..34164657c 100644 --- a/jaq-core/src/load/lex.rs +++ b/jaq-core/src/load/lex.rs @@ -6,7 +6,6 @@ use alloc::vec::Vec; /// /// `S` is a type of strings (without escape sequences), and /// `F` is a type of interpolated filters. -#[derive(Debug)] pub enum StrPart { /// string without escape sequences Str(S), diff --git a/jaq-core/src/load/mod.rs b/jaq-core/src/load/mod.rs index 496f8b432..bc6d3db7d 100644 --- a/jaq-core/src/load/mod.rs +++ b/jaq-core/src/load/mod.rs @@ -2,6 +2,7 @@ #[cfg(feature = "arbitrary")] mod arbitrary; +mod debug; pub mod lex; pub mod parse; mod prec_climb; diff --git a/jaq-core/src/load/parse.rs b/jaq-core/src/load/parse.rs index c08e65a06..d5e634c8c 100644 --- a/jaq-core/src/load/parse.rs +++ b/jaq-core/src/load/parse.rs @@ -76,7 +76,7 @@ pub struct Parser<'s, 't> { } /// Function from value to stream of values, such as `.[] | add / length`. -#[derive(Debug, Default)] +#[derive(Default)] pub enum Term { /// Identity, i.e. `.` #[default] @@ -128,7 +128,6 @@ pub enum Term { } /// Variable-binding pattern, such as in `.[] as [$x, {$y, (f): $z}]` -#[derive(Debug)] pub enum Pattern { /// Variable Var(S), @@ -828,7 +827,6 @@ pub(crate) struct Module { /// def map(f): [.[] | f]; /// def recurse(f; cond): recurse(f | select(cond)); /// ~~~ -#[derive(Debug)] pub struct Def> { /// name, e.g. `"double"` or `"map"` pub name: S, diff --git a/jaq-json/Cargo.toml b/jaq-json/Cargo.toml index e23ac47bf..7d1438c27 100644 --- a/jaq-json/Cargo.toml +++ b/jaq-json/Cargo.toml @@ -23,3 +23,6 @@ foldhash = { version = "0.1", default-features = false } hifijson = { version = "0.2.0", default-features = false, features = ["alloc"], optional = true } indexmap = { version = "2.0", default-features = false } serde_json = { version = "1.0.81", default-features = false, optional = true } + +[build-dependencies] +jaq-core = { path = "../jaq-core" } diff --git a/jaq-json/build.rs b/jaq-json/build.rs new file mode 120000 index 000000000..cd8c22378 --- /dev/null +++ b/jaq-json/build.rs @@ -0,0 +1 @@ +../jaq-std/build.rs \ No newline at end of file diff --git a/jaq-json/src/lib.rs b/jaq-json/src/lib.rs index cfc520608..b2cf2ca47 100644 --- a/jaq-json/src/lib.rs +++ b/jaq-json/src/lib.rs @@ -296,9 +296,11 @@ impl jaq_std::ValT for Val { /// Definitions of the standard library. pub fn defs() -> impl Iterator> { - load::parse(include_str!("defs.jq"), |p| p.defs()) - .unwrap() - .into_iter() + use jaq_core::ops::Math::*; + use jaq_core::path::{self, Opt::*, Part::*}; + use load::lex::StrPart; + use load::parse::{self, BinaryOp::*, Pattern, Term::*}; + include!(concat!(env!("OUT_DIR"), "/defs.rs")).into_iter() } impl Val { diff --git a/jaq-std/Cargo.toml b/jaq-std/Cargo.toml index d11c940cc..58ce701bc 100644 --- a/jaq-std/Cargo.toml +++ b/jaq-std/Cargo.toml @@ -33,3 +33,6 @@ urlencoding = { version = "2.1.3", optional = true } [dev-dependencies] jaq-json = { path = "../jaq-json" } serde_json = "1.0" + +[build-dependencies] +jaq-core = { path = "../jaq-core" } diff --git a/jaq-std/build.rs b/jaq-std/build.rs new file mode 100644 index 000000000..10b82794b --- /dev/null +++ b/jaq-std/build.rs @@ -0,0 +1,11 @@ +//! Cache parsed definitions. + +use jaq_core::load; +use std::io::{Result, Write}; + +fn main() -> Result<()> { + let defs = load::parse(include_str!("src/defs.jq"), |p| p.defs()).unwrap(); + let out_dir = std::env::var_os("OUT_DIR").unwrap(); + let dest_path = std::path::Path::new(&out_dir).join("defs.rs"); + write!(&mut std::fs::File::create(dest_path)?, "{defs:?}") +} diff --git a/jaq-std/src/lib.rs b/jaq-std/src/lib.rs index 3e296ad15..7879ea330 100644 --- a/jaq-std/src/lib.rs +++ b/jaq-std/src/lib.rs @@ -31,9 +31,11 @@ use jaq_core::{load, Bind, Cv, Error, Exn, FilterT, Native, RunPtr, UpdatePtr, V /// Definitions of the standard library. pub fn defs() -> impl Iterator> { - load::parse(include_str!("defs.jq"), |p| p.defs()) - .unwrap() - .into_iter() + use jaq_core::ops::{Cmp::*, Math::*}; + use jaq_core::path::{self, Opt::*, Part::*}; + use load::lex::StrPart; + use load::parse::{self, BinaryOp::*, Pattern, Term::*}; + include!(concat!(env!("OUT_DIR"), "/defs.rs")).into_iter() } /// Name, arguments, and implementation of a filter. diff --git a/jaq/src/main.rs b/jaq/src/main.rs index d9b54a26a..865694d69 100644 --- a/jaq/src/main.rs +++ b/jaq/src/main.rs @@ -2,12 +2,12 @@ mod cli; use cli::Cli; use core::fmt::{self, Display, Formatter}; +use is_terminal::IsTerminal; use jaq_core::{compile, load, Ctx, Native, RcIter, ValT}; use jaq_json::Val; use std::io::{self, BufRead, Write}; use std::path::{Path, PathBuf}; use std::process::{ExitCode, Termination}; -use is_terminal::IsTerminal; type Filter = jaq_core::Filter>;