#![no_std]
#![forbid(unsafe_code)]
#![warn(missing_docs)]
extern crate alloc;
#[cfg(feature = "std")]
extern crate std;
mod box_iter;
pub mod error;
mod filter;
mod hir;
mod into_iter;
mod lir;
mod mir;
mod path;
mod rc_iter;
mod rc_lazy_list;
mod rc_list;
pub mod results;
mod stack;
mod val;
#[allow(dead_code)]
mod exn;
pub use error::Error;
pub use filter::{Args, FilterT, Native, Owned as Filter, RunPtr, UpdatePtr};
pub use rc_iter::RcIter;
pub use val::{Val, ValR, ValRs, ValT};
use alloc::{string::String, vec::Vec};
use jaq_syn::Arg as Bind;
use rc_list::List as RcList;
use stack::Stack;
#[derive(Clone, Debug, PartialEq, Eq)]
struct Vars<V>(RcList<Bind<V, (filter::Id, Self)>>);
type Inputs<'i, V> = RcIter<dyn Iterator<Item = Result<V, String>> + 'i>;
impl<V> Vars<V> {
fn get(&self, i: usize) -> Option<&Bind<V, (filter::Id, Self)>> {
self.0.get(i)
}
}
#[derive(Clone)]
pub struct Ctx<'a, V = Val> {
vars: Vars<V>,
inputs: &'a Inputs<'a, V>,
}
impl<'a, V> Ctx<'a, V> {
pub fn new(vars: impl IntoIterator<Item = V>, inputs: &'a Inputs<'a, V>) -> Self {
let vars = Vars(RcList::new().extend(vars.into_iter().map(Bind::Var)));
Self { vars, inputs }
}
pub(crate) fn cons_var(mut self, x: V) -> Self {
self.vars.0 = self.vars.0.cons(Bind::Var(x));
self
}
pub(crate) fn cons_fun(mut self, (f, ctx): (filter::Id, Self)) -> Self {
self.vars.0 = self.vars.0.cons(Bind::Fun((f, ctx.vars)));
self
}
fn skip_vars(mut self, skip: usize) -> Self {
if skip > 0 {
self.vars.0 = self.vars.0.skip(skip).clone();
}
self
}
fn with_vars(&self, vars: Vars<V>) -> Self {
let inputs = self.inputs;
Self { vars, inputs }
}
pub fn inputs(&self) -> &'a Inputs<'a, V> {
self.inputs
}
}
pub struct ParseCtx {
pub errs: Vec<jaq_syn::Spanned<hir::Error>>,
native: Vec<((String, usize), filter::Native)>,
def: jaq_syn::Def,
}
impl ParseCtx {
pub fn new(vars: Vec<String>) -> Self {
use alloc::string::ToString;
let def = jaq_syn::Def {
lhs: jaq_syn::Call {
name: "$".to_string(),
args: vars.into_iter().map(Bind::Var).collect(),
},
rhs: jaq_syn::Main {
defs: Vec::new(),
body: (jaq_syn::filter::Filter::Id, 0..0),
},
};
Self {
errs: Vec::new(),
native: Vec::new(),
def,
}
}
pub fn insert_native(&mut self, name: String, arity: usize, f: filter::Native) {
self.native.push(((name, arity), f));
}
pub fn insert_natives<I>(&mut self, natives: I)
where
I: IntoIterator<Item = (String, usize, filter::Native)>,
{
let natives = natives
.into_iter()
.map(|(name, arity, f)| ((name, arity), f));
self.native.extend(natives);
}
pub fn insert_defs(&mut self, defs: impl IntoIterator<Item = jaq_syn::Def>) {
self.def.rhs.defs.extend(defs);
}
#[deprecated(since = "1.1.0", note = "use `insert_defs` instead")]
pub fn root_def(&mut self, def: jaq_syn::Def) {
self.def.rhs.defs.push(def);
}
#[deprecated(since = "1.1.0", note = "this call has no effect")]
pub fn root_filter(&mut self, filter: jaq_syn::Spanned<jaq_syn::filter::Filter>) {
self.def.rhs.body = filter;
}
pub fn compile(&mut self, main: jaq_syn::Main) -> Filter {
let mut hctx = hir::Ctx::default();
let native = self.native.iter().map(|(sig, _)| sig.clone());
hctx.native = native.collect();
self.def.rhs.defs.extend(main.defs);
self.def.rhs.body = main.body;
let def = hctx.def(self.def.clone());
self.errs = hctx.errs;
if !self.errs.is_empty() {
return Default::default();
}
let mut mctx = mir::Ctx::default();
let def = mctx.def(def, Default::default());
let mut lctx = lir::Ctx::default();
let id = lctx.def(def);
let native = self.native.iter().map(|(_sig, native)| native.clone());
filter::Owned::new(id, lctx.defs.into(), native.collect())
}
pub fn yields(&mut self, x: Val, f: jaq_syn::Main, ys: impl Iterator<Item = ValR>) {
let f = self.compile(f);
assert!(self.errs.is_empty());
let inputs = RcIter::new(core::iter::empty());
let out = f.run((Ctx::new([], &inputs), x));
assert!(out.eq(ys));
}
}