Rule execution now runs, no tests tho

This commit is contained in:
2022-08-19 12:55:02 +02:00
parent 329dea72b7
commit 891d78c112
30 changed files with 925 additions and 560 deletions

View File

@@ -7,14 +7,14 @@ Hello World in Orchid
```orchid ```orchid
import std::io::(println, out) import std::io::(println, out)
main == println out "Hello World!" main := println out "Hello World!"
``` ```
Basic command line calculator Basic command line calculator
```orchid ```orchid
import std::io::(readln, printf, in, out) import std::io::(readln, printf, in, out)
main == ( main := (
readln in >>= int |> \a. readln in >>= int |> \a.
readln in >>= \op. readln in >>= \op.
readln in >>= int |> \b. readln in >>= int |> \b.
@@ -31,7 +31,7 @@ Grep
```orchid ```orchid
import std::io::(readln, println, in, out, getarg) import std::io::(readln, println, in, out, getarg)
main == loop \r. ( main := loop \r. (
readln in >>= \line. readln in >>= \line.
if (substring (getarg 1) line) if (substring (getarg 1) line)
then (println out ln >>= r) then (println out ln >>= r)
@@ -41,7 +41,7 @@ main == loop \r. (
Filter through an arbitrary collection Filter through an arbitrary collection
```orchid ```orchid
filter == @C:Type -> Type. @:Map C. @T. \f:T -> Bool. \coll:C T. ( filter := @C:Type -> Type. @:Map C. @T. \f:T -> Bool. \coll:C T. (
coll >> \el. if (f el) then (Some el) else Nil coll >> \el. if (f el) then (Some el) else Nil
):(C T) ):(C T)
``` ```
@@ -122,9 +122,9 @@ types whose defaults have implmentations based on your defaults.
For a demonstration, here's a sample implementation of the Option monad. For a demonstration, here's a sample implementation of the Option monad.
```orchid ```orchid
--[[ The definition of Monad ]]-- --[[ The definition of Monad ]]--
Bind == \M:Type -> Type. @T -> @U -> (T -> M U) -> M T -> M U Bind := \M:Type -> Type. @T -> @U -> (T -> M U) -> M T -> M U
Return == \M:Type -> Type. @T -> T -> M T Return := \M:Type -> Type. @T -> T -> M T
Monad == \M:Type -> Type. ( Monad := \M:Type -> Type. (
@:Bind M. @:Bind M.
@:Return M. @:Return M.
0 --[ Note that empty expressions are forbidden so those that exist 0 --[ Note that empty expressions are forbidden so those that exist
@@ -134,19 +134,19 @@ Monad == \M:Type -> Type. (
) )
--[[ The definition of Option ]]-- --[[ The definition of Option ]]--
export Option == \T:Type. @U -> U -> (T -> U) -> U export Option := \T:Type. @U -> U -> (T -> U) -> U
--[ Constructors ]-- --[ Constructors ]--
export Some == @T. \data:T. ( \default. \map. map data ):(Option T) export Some := @T. \data:T. ( \default. \map. map data ):(Option T)
export None == @T. ( \default. \map. default ):(Option T) export None := @T. ( \default. \map. default ):(Option T)
--[ Implement Monad ]-- --[ Implement Monad ]--
default returnOption == Some:(Return Option) default returnOption := Some:(Return Option)
default bindOption == ( @T:Type. @U:Type. default bindOption := ( @T:Type. @U:Type.
\f:T -> U. \opt:Option T. opt None f \f:T -> U. \opt:Option T. opt None f
):(Bind Option) ):(Bind Option)
--[ Sample function that works on unknown monad to demonstrate HKTs. --[ Sample function that works on unknown monad to demonstrate HKTs.
Turns (Option (M T)) into (M (Option T)), "raising" the unknown monad Turns (Option (M T)) into (M (Option T)), "raising" the unknown monad
out of the Option ]-- out of the Option ]--
export raise == @M:Type -> Type. @T:Type. @:Monad M. \opt:Option (M T). ( export raise := @M:Type -> Type. @T:Type. @:Monad M. \opt:Option (M T). (
opt (return None) (\m. bind m (\x. Some x)) opt (return None) (\m. bind m (\x. Some x))
):(M (Option T)) ):(M (Option T))
``` ```
@@ -162,7 +162,7 @@ Add has three arguments, two are the types of the operands and one is
the result: the result:
```orchid ```orchid
default concatListAdd replacing applicativeAdd == @T. ( default concatListAdd replacing elementwiseAdd := @T. (
... ...
):(Add (List T) (List T) (List T)) ):(Add (List T) (List T) (List T))
``` ```
@@ -170,7 +170,7 @@ default concatListAdd replacing applicativeAdd == @T. (
For completeness' sake, the original definition might look like this: For completeness' sake, the original definition might look like this:
```orchid ```orchid
default elementwiseAdd == @C:Type -> Type. @T. @U. @V. @:(Applicative C). @:(Add T U V). ( default elementwiseAdd := @C:Type -> Type. @T. @U. @V. @:(Applicative C). @:(Add T U V). (
... ...
):(Add (C T) (C U) (C V)) ):(Add (C T) (C U) (C V))
``` ```
@@ -179,7 +179,7 @@ With the use of autos, here's what the recursive multiplication
implementation looks like: implementation looks like:
```orchid ```orchid
default iterativeMultiply == @T. @:(Add T T T). ( default iterativeMultiply := @T. @:(Add T T T). (
\a:int.\b:T. loop \r. (\i. \a:int.\b:T. loop \r. (\i.
ifthenelse (ieq i 0) ifthenelse (ieq i 0)
b b
@@ -191,7 +191,7 @@ default iterativeMultiply == @T. @:(Add T T T). (
This could then be applied to any type that's closed over addition This could then be applied to any type that's closed over addition
```orchid ```orchid
aroundTheWorldLyrics == ( aroundTheWorldLyrics := (
mult 18 (add (mult 4 "Around the World\n") "\n") mult 18 (add (mult 4 "Around the World\n") "\n")
) )
``` ```
@@ -218,20 +218,20 @@ are searched back-to-front. If order is still a problem, you can always
parenthesize subexpressions at the callsite. parenthesize subexpressions at the callsite.
```orchid ```orchid
(...$pre:(seq 2) if $1 then $2 else $3 ...$post:(seq 1)) =2=> ( (..$pre:2 if $1 then $2 else $3 ..$post:1) =2=> (
...$pre ..$pre
(ifthenelse $1 $2 $3) (ifthenelse $1 $2 $3)
...$post ...$post
) )
$a + $b =10=> (add $a $b) $a + $b =10=> (add $a $b)
$a == $b =5=> (eq $a $b) $a = $b =5=> (eq $a $b)
$a - $b =10=> (sub $a $b) $a - $b =10=> (sub $a $b)
``` ```
The recursive addition function now looks like this The recursive addition function now looks like this
```orchid ```orchid
default iterativeMultiply == @T. @:(Add T T T). ( default iterativeMultiply := @T. @:(Add T T T). (
\a:int.\b:T. loop \r. (\i. \a:int.\b:T. loop \r. (\i.
if (i = 0) then b if (i = 0) then b
else (b + (r (i - 1))) else (b + (r (i - 1)))
@@ -249,7 +249,7 @@ environment and can carry structured data payloads.
Here's an example of a carriage being used to turn a square-bracketed Here's an example of a carriage being used to turn a square-bracketed
list expression into a lambda expression that matches a conslist. Notice list expression into a lambda expression that matches a conslist. Notice
how the square brackets pair up, as all three variants of brackets how the square brackets pair up, as all three variants of brackets
group nodes. are considered branches in the S-tree rather than individual tokens.
``` ```
-- Initial step, eliminates entry condition (square brackets) and constructs -- Initial step, eliminates entry condition (square brackets) and constructs
@@ -303,4 +303,4 @@ ideas.
- [ ] reactive calculation of values that are deemed to be read more often - [ ] reactive calculation of values that are deemed to be read more often
than written than written
- [ ] automatic profiling based on performance metrics generated by debug - [ ] automatic profiling based on performance metrics generated by debug
builds builds

View File

@@ -9,15 +9,15 @@ export ;> $a =200=> (greet $a)
reeee := \$a.b reeee := \$a.b
-- single-word exported rule -- single-word exported rule
export main == ( export main := (
print "What is your name?" >> print "What is your name?" >>
readln >>= \name. readln >>= \name.
greet name greet name
) )
export < $a ...$rest /> == (createElement (tok_to_str $a) [(props_carriage ...$rest)]) export < $a ...$rest /> := (createElement (tok_to_str $a) [(props_carriage ...$rest)])
export (props_carriage $key = $value) == (tok_to_str $key) => $value export (props_carriage $key = $value) := (tok_to_str $key) => $value
-- The broadest trait definition in existence -- The broadest trait definition in existence
Foo == (Bar Baz) Foo := (Bar Baz)
-- default anyFoo = @T. @impl:(T (Bar Baz)). impl:(T Foo) -- default anyFoo = @T. @impl:(T (Bar Baz)). impl:(T Foo)

View File

@@ -0,0 +1 @@
expor main := foo bar baz

View File

@@ -1,6 +1,7 @@
use mappable_rc::Mrc;
use itertools::Itertools; use itertools::Itertools;
use ordered_float::NotNan; use ordered_float::NotNan;
use std::{fmt::Debug}; use std::fmt::Debug;
/// An exact value /// An exact value
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(Clone, PartialEq, Eq, Hash)]
@@ -23,12 +24,17 @@ impl Debug for Literal {
} }
/// An S-expression with a type /// An S-expression with a type
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(PartialEq, Eq, Hash)]
pub struct Expr(pub Clause, pub Option<Box<Expr>>); pub struct Expr(pub Clause, pub Option<Mrc<Expr>>);
impl Clone for Expr {
fn clone(&self) -> Self {
Self(self.0.clone(), self.1.as_ref().map(Mrc::clone))
}
}
impl Debug for Expr { impl Debug for Expr {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
// f.debug_tuple("Expr").field(&self.0).field(&self.1).finish()
let Expr(val, typ) = self; let Expr(val, typ) = self;
write!(f, "{:?}", val)?; write!(f, "{:?}", val)?;
if let Some(typ) = typ { write!(f, "{:?}", typ) } if let Some(typ) = typ { write!(f, "{:?}", typ) }
@@ -37,38 +43,62 @@ impl Debug for Expr {
} }
/// An S-expression as read from a source file /// An S-expression as read from a source file
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(PartialEq, Eq, Hash)]
pub enum Clause { pub enum Clause {
Literal(Literal), Literal(Literal),
Name{ Name{
local: Option<String>, local: Option<String>,
qualified: Vec<String> qualified: Mrc<[String]>
}, },
S(char, Vec<Expr>), S(char, Mrc<[Expr]>),
Lambda(String, Vec<Expr>, Vec<Expr>), Lambda(String, Mrc<[Expr]>, Mrc<[Expr]>),
Auto(Option<String>, Vec<Expr>, Vec<Expr>), Auto(Option<String>, Mrc<[Expr]>, Mrc<[Expr]>),
/// Second parameter: /// Second parameter:
/// None => matches one token /// None => matches one token
/// Some(prio) => prio is the sizing priority for the vectorial (higher prio grows first) /// Some((prio, nonzero)) =>
Placeh(String, Option<usize>), /// prio is the sizing priority for the vectorial (higher prio grows first)
/// nonzero is whether the vectorial matches 1..n or 0..n tokens
Placeh{
key: String,
vec: Option<(usize, bool)>
},
} }
impl Clause { impl Clause {
pub fn body(&self) -> Option<&Vec<Expr>> { pub fn body(&self) -> Option<Mrc<[Expr]>> {
match self { match self {
Clause::Auto(_, _, body) | Clause::Auto(_, _, body) |
Clause::Lambda(_, _, body) | Clause::Lambda(_, _, body) |
Clause::S(_, body) => Some(body), Clause::S(_, body) => Some(Mrc::clone(body)),
_ => None _ => None
} }
} }
pub fn typ(&self) -> Option<&Vec<Expr>> { pub fn typ(&self) -> Option<Mrc<[Expr]>> {
match self { match self {
Clause::Auto(_, typ, _) | Clause::Lambda(_, typ, _) => Some(typ), Clause::Auto(_, typ, _) | Clause::Lambda(_, typ, _) => Some(Mrc::clone(typ)),
_ => None _ => None
} }
} }
} }
impl Clone for Clause {
fn clone(&self) -> Self {
match self {
Clause::S(c, b) => Clause::S(*c, Mrc::clone(b)),
Clause::Auto(n, t, b) => Clause::Auto(
n.clone(), Mrc::clone(t), Mrc::clone(b)
),
Clause::Name { local: l, qualified: q } => Clause::Name {
local: l.clone(), qualified: Mrc::clone(q)
},
Clause::Lambda(n, t, b) => Clause::Lambda(
n.clone(), Mrc::clone(t), Mrc::clone(b)
),
Clause::Placeh{key, vec} => Clause::Placeh{key: key.clone(), vec: *vec},
Clause::Literal(l) => Clause::Literal(l.clone())
}
}
}
fn fmt_expr_seq(it: &mut dyn Iterator<Item = &Expr>, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt_expr_seq(it: &mut dyn Iterator<Item = &Expr>, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for item in Itertools::intersperse(it.map(Some), None) { match item { for item in Itertools::intersperse(it.map(Some), None) { match item {
Some(expr) => write!(f, "{:?}", expr), Some(expr) => write!(f, "{:?}", expr),
@@ -82,7 +112,7 @@ impl Debug for Clause {
match self { match self {
Self::Literal(arg0) => write!(f, "{:?}", arg0), Self::Literal(arg0) => write!(f, "{:?}", arg0),
Self::Name{local, qualified} => Self::Name{local, qualified} =>
if let Some(local) = local {write!(f, "{}<{}>", qualified.join("::"), local)} if let Some(local) = local {write!(f, "{}`{}`", qualified.join("::"), local)}
else {write!(f, "{}", qualified.join("::"))}, else {write!(f, "{}", qualified.join("::"))},
Self::S(del, items) => { Self::S(del, items) => {
f.write_str(&del.to_string())?; f.write_str(&del.to_string())?;
@@ -104,23 +134,33 @@ impl Debug for Clause {
f.write_str(":")?; fmt_expr_seq(&mut argtyp.iter(), f)?; f.write_str(".")?; f.write_str(":")?; fmt_expr_seq(&mut argtyp.iter(), f)?; f.write_str(".")?;
fmt_expr_seq(&mut body.iter(), f) fmt_expr_seq(&mut body.iter(), f)
}, },
// Self::Parameter(name) => write!(f, "`{}", name), Self::Placeh{key, vec: None} => write!(f, "${key}"),
Self::Placeh(name, None) => write!(f, "${}", name), Self::Placeh{key, vec: Some((prio, true))} => write!(f, "...${key}:{prio}"),
Self::Placeh(name, Some(prio)) => write!(f, "...${}:{}", name, prio) Self::Placeh{key, vec: Some((prio, false))} => write!(f, "..${key}:{prio}")
} }
} }
} }
/// A substitution rule as read from the source /// A substitution rule as read from the source
#[derive(Clone, PartialEq, Eq, Hash)] #[derive(PartialEq, Eq, Hash)]
pub struct Rule { pub struct Rule {
pub source: Vec<Expr>, pub source: Mrc<[Expr]>,
pub prio: NotNan<f64>, pub prio: NotNan<f64>,
pub target: Vec<Expr> pub target: Mrc<[Expr]>
}
impl Clone for Rule {
fn clone(&self) -> Self {
Self {
source: Mrc::clone(&self.source),
prio: self.prio,
target: Mrc::clone(&self.target)
}
}
} }
impl Debug for Rule { impl Debug for Rule {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?} ={}=> {:?}", self.source, self.prio, self.target) write!(f, "{:?} ={}=> {:?}", self.source, self.prio, self.target)
} }
} }

View File

@@ -1,14 +1,23 @@
#![feature(specialization)]
use std::env::current_dir; use std::{env::current_dir, process::exit};
mod parse; mod parse;
mod project; mod project;
mod utils; mod utils;
mod expression; mod expression;
mod rule; mod rule;
use expression::{Expr, Clause};
use mappable_rc::Mrc;
use project::{rule_collector, Loaded, file_loader}; use project::{rule_collector, Loaded, file_loader};
use rule::Repository;
use utils::to_mrc_slice;
fn literal(orig: &[&str]) -> Vec<String> { fn literal(orig: &[&str]) -> Mrc<[String]> {
to_mrc_slice(vliteral(orig))
}
fn vliteral(orig: &[&str]) -> Vec<String> {
orig.iter().map(|&s| s.to_owned()).collect() orig.iter().map(|&s| s.to_owned()).collect()
} }
@@ -21,15 +30,40 @@ export (match_sequence $lhs) >> (match_sequence $rhs) =100=> (bind ($lhs) (\_. $
export (match_sequence $lhs) >>= (match_sequence $rhs) =100=> (bind ($lhs) ($rhs)) export (match_sequence $lhs) >>= (match_sequence $rhs) =100=> (bind ($lhs) ($rhs))
"#; "#;
fn initial_tree() -> Mrc<[Expr]> {
to_mrc_slice(vec![Expr(Clause::Name {
local: None,
qualified: to_mrc_slice(vec!["main".to_string(), "main".to_string()])
}, None)])
}
fn main() { fn main() {
let cwd = current_dir().unwrap(); let cwd = current_dir().unwrap();
let collect_rules = rule_collector(move |n| { let collect_rules = rule_collector(move |n| {
if n == vec!["prelude"] { Ok(Loaded::Module(PRELUDE.to_string())) } if n == literal(&["prelude"]) { Ok(Loaded::Module(PRELUDE.to_string())) }
else { file_loader(cwd.clone())(n) } else { file_loader(cwd.clone())(n) }
}, literal(&["...", ">>", ">>=", "[", "]", ",", "=", "=>"])); }, vliteral(&["...", ">>", ">>=", "[", "]", ",", "=", "=>"]));
match collect_rules.try_find(&literal(&["main"])) { match collect_rules.try_find(&literal(&["main"])) {
Ok(rules) => for rule in rules.iter() { Ok(rules) => {
println!("{rule:?}") let mut tree = initial_tree();
println!("Start processing {tree:?}");
let repo = Repository::new(rules.as_ref().to_owned());
println!("Ruleset: {repo:?}");
let mut i = 0; loop {
if 10 <= i {break} else {i += 1}
match repo.step(Mrc::clone(&tree)) {
Ok(Some(phase)) => {
tree = phase;
println!("Step {i}: {tree:?}")
},
Ok(None) => exit(0),
Err(e) => {
eprintln!("Rule error: {e:?}");
exit(0)
}
}
}
} }
Err(err) => println!("{:#?}", err) Err(err) => println!("{:#?}", err)
} }

View File

@@ -1,13 +1,16 @@
use chumsky::{self, prelude::*, Parser}; use chumsky::{self, prelude::*, Parser};
use crate::{enum_parser, expression::{Clause, Expr, Literal}}; use mappable_rc::Mrc;
use crate::enum_parser;
use crate::expression::{Clause, Expr, Literal};
use crate::utils::to_mrc_slice;
use super::{lexer::Lexeme}; use super::lexer::Lexeme;
fn sexpr_parser<P>( fn sexpr_parser<P>(
expr: P expr: P
) -> impl Parser<Lexeme, Clause, Error = Simple<Lexeme>> + Clone ) -> impl Parser<Lexeme, Clause, Error = Simple<Lexeme>> + Clone
where P: Parser<Lexeme, Expr, Error = Simple<Lexeme>> + Clone { where P: Parser<Lexeme, Expr, Error = Simple<Lexeme>> + Clone {
Lexeme::paren_parser(expr.repeated()).map(|(del, b)| Clause::S(del, b)) Lexeme::paren_parser(expr.repeated()).map(|(del, b)| Clause::S(del, to_mrc_slice(b)))
} }
fn lambda_parser<P>( fn lambda_parser<P>(
@@ -28,9 +31,9 @@ where P: Parser<Lexeme, Expr, Error = Simple<Lexeme>> + Clone {
.then_ignore(just(Lexeme::name("."))) .then_ignore(just(Lexeme::name(".")))
.then_ignore(enum_parser!(Lexeme::Comment).repeated()) .then_ignore(enum_parser!(Lexeme::Comment).repeated())
.then(expr.repeated().at_least(1)) .then(expr.repeated().at_least(1))
.map(|((name, typ), mut body): ((String, Vec<Expr>), Vec<Expr>)| { .map(|((name, typ), body): ((String, Vec<Expr>), Vec<Expr>)| {
// for ent in &mut body { ent.bind_parameter(&name) }; // for ent in &mut body { ent.bind_parameter(&name) };
Clause::Lambda(name, typ, body) Clause::Lambda(name, to_mrc_slice(typ), to_mrc_slice(body))
}) })
} }
@@ -51,13 +54,10 @@ where P: Parser<Lexeme, Expr, Error = Simple<Lexeme>> + Clone {
.then_ignore(just(Lexeme::name("."))) .then_ignore(just(Lexeme::name(".")))
.then_ignore(enum_parser!(Lexeme::Comment).repeated()) .then_ignore(enum_parser!(Lexeme::Comment).repeated())
.then(expr.repeated().at_least(1)) .then(expr.repeated().at_least(1))
.try_map(|((name, typ), mut body), s| if name == None && typ.is_empty() { .try_map(|((name, typ), body), s| if name.is_none() && typ.is_empty() {
Err(Simple::custom(s, "Auto without name or type has no effect")) Err(Simple::custom(s, "Auto without name or type has no effect"))
} else { } else {
// if let Some(n) = &name { Ok(Clause::Auto(name, to_mrc_slice(typ), to_mrc_slice(body)))
// for ent in &mut body { ent.bind_parameter(n) }
// }
Ok(Clause::Auto(name, typ, body))
}) })
} }
@@ -71,8 +71,8 @@ fn name_parser() -> impl Parser<Lexeme, Vec<String>, Error = Simple<Lexeme>> + C
fn placeholder_parser() -> impl Parser<Lexeme, String, Error = Simple<Lexeme>> + Clone { fn placeholder_parser() -> impl Parser<Lexeme, String, Error = Simple<Lexeme>> + Clone {
enum_parser!(Lexeme::Name).try_map(|name, span| { enum_parser!(Lexeme::Name).try_map(|name, span| {
name.strip_prefix("$").map(&str::to_string) name.strip_prefix('$').map(&str::to_string)
.ok_or(Simple::custom(span, "Not a placeholder")) .ok_or_else(|| Simple::custom(span, "Not a placeholder"))
}) })
} }
@@ -83,18 +83,22 @@ pub fn xpr_parser() -> impl Parser<Lexeme, Expr, Error = Simple<Lexeme>> {
enum_parser!(Lexeme::Comment).repeated() enum_parser!(Lexeme::Comment).repeated()
.ignore_then(choice(( .ignore_then(choice((
enum_parser!(Lexeme >> Literal; Int, Num, Char, Str).map(Clause::Literal), enum_parser!(Lexeme >> Literal; Int, Num, Char, Str).map(Clause::Literal),
placeholder_parser().map(|n| Clause::Placeh(n, None)), placeholder_parser().map(|key| Clause::Placeh{key, vec: None}),
just(Lexeme::name("...")) just(Lexeme::name("...")).to(true)
.ignore_then(placeholder_parser()) .or(just(Lexeme::name("..")).to(false))
.then(placeholder_parser())
.then( .then(
just(Lexeme::Type) just(Lexeme::Type)
.ignore_then(enum_parser!(Lexeme::Int)) .ignore_then(enum_parser!(Lexeme::Int))
.or_not().map(Option::unwrap_or_default) .or_not().map(Option::unwrap_or_default)
) )
.map(|(name, prio)| Clause::Placeh(name, Some(prio.try_into().unwrap()))), .map(|((nonzero, key), prio)| Clause::Placeh{key, vec: Some((
prio.try_into().unwrap(),
nonzero
))}),
name_parser().map(|qualified| Clause::Name { name_parser().map(|qualified| Clause::Name {
local: if qualified.len() == 1 {Some(qualified[0].clone())} else {None}, local: if qualified.len() == 1 {Some(qualified[0].clone())} else {None},
qualified qualified: to_mrc_slice(qualified)
}), }),
sexpr_parser(expr.clone()), sexpr_parser(expr.clone()),
lambda_parser(expr.clone()), lambda_parser(expr.clone()),
@@ -104,6 +108,6 @@ pub fn xpr_parser() -> impl Parser<Lexeme, Expr, Error = Simple<Lexeme>> {
just(Lexeme::Type) just(Lexeme::Type)
.ignore_then(expr.clone()).or_not() .ignore_then(expr.clone()).or_not()
) )
.map(|(val, typ)| Expr(val, typ.map(Box::new))) .map(|(val, typ)| Expr(val, typ.map(Mrc::new)))
}).labelled("Expression") }).labelled("Expression")
} }

View File

@@ -1,20 +1,22 @@
use std::iter;
use chumsky::{Parser, prelude::*}; use chumsky::{Parser, prelude::*};
use crate::{enum_parser, utils::BoxedIter}; use itertools::Itertools;
use mappable_rc::Mrc;
use crate::utils::iter::{box_once, box_flatten, into_boxed_iter, BoxedIterIter};
use crate::utils::{to_mrc_slice, mrc_derive};
use crate::{enum_parser, box_chain};
use super::lexer::Lexeme; use super::lexer::Lexeme;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct Import { pub struct Import {
pub path: Vec<String>, pub path: Mrc<[String]>,
pub name: Option<String> pub name: Option<String>
} }
/// initialize a BoxedIter<BoxedIter<String>> with a single element. /// initialize a BoxedIter<BoxedIter<String>> with a single element.
fn init_table(name: String) -> BoxedIter<'static, BoxedIter<'static, String>> { fn init_table(name: String) -> BoxedIterIter<'static, String> {
// I'm not at all confident that this is a good approach. // I'm not at all confident that this is a good approach.
Box::new(iter::once(Box::new(iter::once(name)) as BoxedIter<String>)) box_once(box_once(name))
} }
/// Parse an import command /// Parse an import command
@@ -24,7 +26,7 @@ fn init_table(name: String) -> BoxedIter<'static, BoxedIter<'static, String>> {
/// to go wild. There's a blacklist in [name] /// to go wild. There's a blacklist in [name]
pub fn import_parser() -> impl Parser<Lexeme, Vec<Import>, Error = Simple<Lexeme>> { pub fn import_parser() -> impl Parser<Lexeme, Vec<Import>, Error = Simple<Lexeme>> {
// TODO: this algorithm isn't cache friendly, copies a lot and is generally pretty bad. // TODO: this algorithm isn't cache friendly, copies a lot and is generally pretty bad.
recursive(|expr: Recursive<Lexeme, BoxedIter<BoxedIter<String>>, Simple<Lexeme>>| { recursive(|expr: Recursive<Lexeme, BoxedIterIter<String>, Simple<Lexeme>>| {
enum_parser!(Lexeme::Name) enum_parser!(Lexeme::Name)
.separated_by(just(Lexeme::NS)) .separated_by(just(Lexeme::NS))
.then( .then(
@@ -34,7 +36,7 @@ pub fn import_parser() -> impl Parser<Lexeme, Vec<Import>, Error = Simple<Lexeme
expr.clone() expr.clone()
.separated_by(just(Lexeme::name(","))) .separated_by(just(Lexeme::name(",")))
.delimited_by(just(Lexeme::LP('(')), just(Lexeme::RP('('))) .delimited_by(just(Lexeme::LP('(')), just(Lexeme::RP('(')))
.map(|v| Box::new(v.into_iter().flatten()) as BoxedIter<BoxedIter<String>>) .map(|v| box_flatten(v.into_iter()))
.labelled("import group"), .labelled("import group"),
// Each expr returns a list of imports, flatten those into a common list // Each expr returns a list of imports, flatten those into a common list
just(Lexeme::name("*")).map(|_| init_table("*".to_string())) just(Lexeme::name("*")).map(|_| init_table("*".to_string()))
@@ -44,22 +46,23 @@ pub fn import_parser() -> impl Parser<Lexeme, Vec<Import>, Error = Simple<Lexeme
)) ))
).or_not() ).or_not()
) )
.map(|(name, opt_post): (Vec<String>, Option<BoxedIter<BoxedIter<String>>>)| -> BoxedIter<BoxedIter<String>> { .map(|(name, opt_post): (Vec<String>, Option<BoxedIterIter<String>>)| -> BoxedIterIter<String> {
if let Some(post) = opt_post { if let Some(post) = opt_post {
Box::new(post.map(move |el| { Box::new(post.map(move |el| {
Box::new(name.clone().into_iter().chain(el)) as BoxedIter<String> box_chain!(name.clone().into_iter(), el)
})) as BoxedIter<BoxedIter<String>> }))
} else { } else {
Box::new(iter::once(Box::new(name.into_iter()) as BoxedIter<String>)) box_once(into_boxed_iter(name))
} }
}) })
}).map(|paths| { }).map(|paths| {
paths.filter_map(|namespaces| { paths.filter_map(|namespaces| {
let mut path: Vec<String> = namespaces.collect(); let path = to_mrc_slice(namespaces.collect_vec());
match path.pop()?.as_str() { let path_prefix = mrc_derive(&path, |p| &p[..p.len() - 1]);
"*" => Some(Import { path, name: None }), match path.last()?.as_str() {
name => Some(Import { path, name: Some(name.to_owned()) }) "*" => Some(Import { path: path_prefix, name: None }),
name => Some(Import { path: path_prefix, name: Some(name.to_owned()) })
} }
}).collect() }).collect()
}).labelled("import") }).labelled("import")
} }

View File

@@ -2,7 +2,7 @@ use std::{ops::Range, iter, fmt};
use ordered_float::NotNan; use ordered_float::NotNan;
use chumsky::{Parser, prelude::*}; use chumsky::{Parser, prelude::*};
use std::fmt::Debug; use std::fmt::Debug;
use crate::utils::BoxedIter; use crate::{utils::{BoxedIter, iter::{box_once, box_flatten}}, box_chain};
use super::{number, string, name, comment}; use super::{number, string, name, comment};
@@ -14,9 +14,10 @@ impl Debug for Entry {
// f.debug_tuple("Entry").field(&self.0).field(&self.1).finish() // f.debug_tuple("Entry").field(&self.0).field(&self.1).finish()
} }
} }
impl Into<(Lexeme, Range<usize>)> for Entry {
fn into(self) -> (Lexeme, Range<usize>) { impl From<Entry> for (Lexeme, Range<usize>) {
(self.0, self.1) fn from(ent: Entry) -> Self {
(ent.0, ent.1)
} }
} }
@@ -107,13 +108,13 @@ fn paren_parser<'a>(
lp: char, rp: char lp: char, rp: char
) -> impl Parser<char, LexSubres<'a>, Error=Simple<char>> + 'a { ) -> impl Parser<char, LexSubres<'a>, Error=Simple<char>> + 'a {
expr.padded().repeated() expr.padded().repeated()
.map(|x| Box::new(x.into_iter().flatten()) as LexSubres) .map(|x| box_flatten(x.into_iter()))
.delimited_by(just(lp), just(rp)).map_with_span(move |b, s| { .delimited_by(just(lp), just(rp)).map_with_span(move |b, s| {
Box::new( box_chain!(
iter::once(Entry(Lexeme::LP(lp), s.start..s.start+1)) iter::once(Entry(Lexeme::LP(lp), s.start..s.start+1)),
.chain(b) b,
.chain(iter::once(Entry(Lexeme::RP(lp), s.end-1..s.end))) iter::once(Entry(Lexeme::RP(lp), s.end-1..s.end))
) as LexSubres )
}) })
} }
@@ -127,7 +128,7 @@ where T: AsRef<str> + Clone {
paren_parser(recurse.clone(), '[', ']'), paren_parser(recurse.clone(), '[', ']'),
paren_parser(recurse.clone(), '{', '}'), paren_parser(recurse.clone(), '{', '}'),
choice(( choice((
just("==").padded().to(Lexeme::rule(0f64)), just(":=").padded().to(Lexeme::rule(0f64)),
just("=").ignore_then(number::float_parser()).then_ignore(just("=>")).map(Lexeme::rule), just("=").ignore_then(number::float_parser()).then_ignore(just("=>")).map(Lexeme::rule),
comment::comment_parser().map(Lexeme::Comment), comment::comment_parser().map(Lexeme::Comment),
just("::").padded().to(Lexeme::NS), just("::").padded().to(Lexeme::NS),
@@ -139,7 +140,7 @@ where T: AsRef<str> + Clone {
string::char_parser().map(Lexeme::Char), string::char_parser().map(Lexeme::Char),
string::str_parser().map(Lexeme::Str), string::str_parser().map(Lexeme::Str),
name::name_parser(&all_ops).map(Lexeme::Name), // includes namespacing name::name_parser(&all_ops).map(Lexeme::Name), // includes namespacing
)).map_with_span(|lx, span| Box::new(iter::once(Entry(lx, span))) as LexSubres) )).map_with_span(|lx, span| box_once(Entry(lx, span)) as LexSubres)
)) ))
}).separated_by(one_of("\t ").repeated()) }).separated_by(one_of("\t ").repeated())
.flatten().collect() .flatten().collect()

View File

@@ -3,11 +3,11 @@ use chumsky::{self, prelude::*, Parser};
/// Matches any one of the passed operators, longest-first /// Matches any one of the passed operators, longest-first
fn op_parser<'a, T: AsRef<str> + Clone>(ops: &[T]) -> BoxedParser<'a, char, String, Simple<char>> { fn op_parser<'a, T: AsRef<str> + Clone>(ops: &[T]) -> BoxedParser<'a, char, String, Simple<char>> {
let mut sorted_ops: Vec<String> = ops.iter().map(|t| t.as_ref().to_string()).collect(); let mut sorted_ops: Vec<String> = ops.iter().map(|t| t.as_ref().to_string()).collect();
sorted_ops.sort_by(|a, b| b.len().cmp(&a.len())); sorted_ops.sort_by_key(|op| -(op.len() as i64));
sorted_ops.into_iter() sorted_ops.into_iter()
.map(|op| just(op).boxed()) .map(|op| just(op).boxed())
.reduce(|a, b| a.or(b).boxed()) .reduce(|a, b| a.or(b).boxed())
.unwrap_or(empty().map(|()| panic!("Empty isn't meant to match")).boxed()) .unwrap_or_else(|| empty().map(|()| panic!("Empty isn't meant to match")).boxed())
.labelled("operator").boxed() .labelled("operator").boxed()
} }
@@ -56,4 +56,4 @@ pub fn is_op<T: AsRef<str>>(s: T) -> bool {
Some(x) => !x.is_alphanumeric(), Some(x) => !x.is_alphanumeric(),
None => false None => false
} }
} }

View File

@@ -14,7 +14,7 @@ fn separated_digits_parser(base: u32) -> impl Parser<char, String, Error = Simpl
just('_') just('_')
.ignore_then(text::digits(base)) .ignore_then(text::digits(base))
.repeated() .repeated()
.map(|sv| sv.iter().map(|s| s.chars()).flatten().collect()) .map(|sv| sv.iter().flat_map(|s| s.chars()).collect())
} }
/// parse a grouped uint /// parse a grouped uint
@@ -31,7 +31,7 @@ fn uint_parser(base: u32) -> impl Parser<char, u64, Error = Simple<char>> {
/// parse exponent notation, or return 0 as the default exponent. /// parse exponent notation, or return 0 as the default exponent.
/// The exponent is always in decimal. /// The exponent is always in decimal.
fn pow_parser() -> impl Parser<char, i32, Error = Simple<char>> { fn pow_parser() -> impl Parser<char, i32, Error = Simple<char>> {
return choice(( choice((
just('p') just('p')
.ignore_then(text::int(10)) .ignore_then(text::int(10))
.map(|s: String| s.parse().unwrap()), .map(|s: String| s.parse().unwrap()),
@@ -45,15 +45,15 @@ fn pow_parser() -> impl Parser<char, i32, Error = Simple<char>> {
/// ///
/// TODO it panics if it finds a negative exponent /// TODO it panics if it finds a negative exponent
fn nat2u(base: u64) -> impl Fn((u64, i32),) -> u64 { fn nat2u(base: u64) -> impl Fn((u64, i32),) -> u64 {
return move |(val, exp)| { move |(val, exp)| {
if exp == 0 {val} if exp == 0 {val}
else {val * base.checked_pow(exp.try_into().unwrap()).unwrap()} else {val * base.checked_pow(exp.try_into().unwrap()).unwrap()}
}; }
} }
/// returns a mapper that converts a mantissa and an exponent into a float /// returns a mapper that converts a mantissa and an exponent into a float
fn nat2f(base: u64) -> impl Fn((NotNan<f64>, i32),) -> NotNan<f64> { fn nat2f(base: u64) -> impl Fn((NotNan<f64>, i32),) -> NotNan<f64> {
return move |(val, exp)| { move |(val, exp)| {
if exp == 0 {val} if exp == 0 {val}
else {val * (base as f64).powf(exp.try_into().unwrap())} else {val * (base as f64).powf(exp.try_into().unwrap())}
} }

View File

@@ -4,7 +4,7 @@ use chumsky::{prelude::{Simple, end}, Stream, Parser};
use itertools::Itertools; use itertools::Itertools;
use thiserror::Error; use thiserror::Error;
use crate::expression::Rule; use crate::{expression::Rule, parse::lexer::LexedText};
use super::{Lexeme, FileEntry, lexer, line_parser, LexerEntry}; use super::{Lexeme, FileEntry, lexer, line_parser, LexerEntry};
@@ -24,14 +24,17 @@ where
S: Into<Stream<'a, char, Range<usize>, Iter>> { S: Into<Stream<'a, char, Range<usize>, Iter>> {
let lexed = lexer(ops).parse(stream).map_err(ParseError::Lex)?; let lexed = lexer(ops).parse(stream).map_err(ParseError::Lex)?;
println!("Lexed:\n{:?}", lexed); println!("Lexed:\n{:?}", lexed);
let LexedText(token_batchv) = lexed;
let parsr = line_parser().then_ignore(end()); let parsr = line_parser().then_ignore(end());
let (parsed_lines, errors_per_line) = lexed.0.into_iter().filter_map(|v| { let (parsed_lines, errors_per_line) = token_batchv.into_iter().filter(|v| {
!v.is_empty()
}).map(|v| {
// Find the first invalid position for Stream::for_iter // Find the first invalid position for Stream::for_iter
let LexerEntry(_, Range{ end, .. }) = v.last().unwrap().clone(); let LexerEntry(_, Range{ end, .. }) = v.last().unwrap().clone();
// Stream expects tuples, lexer outputs structs // Stream expects tuples, lexer outputs structs
let tuples = v.into_iter().map_into::<(Lexeme, Range<usize>)>(); let tuples = v.into_iter().map_into::<(Lexeme, Range<usize>)>();
Some(parsr.parse(Stream::from_iter(end..end+1, tuples))) parsr.parse(Stream::from_iter(end..end+1, tuples))
// ^^^^^^^^^^ // ^^^^^^^^^^
// I haven't the foggiest idea why this is needed, parsers are supposed to be lazy so the // I haven't the foggiest idea why this is needed, parsers are supposed to be lazy so the
// end of input should make little difference // end of input should make little difference
}).map(|res| match res { }).map(|res| match res {
@@ -39,13 +42,13 @@ where
Err(e) => (None, e) Err(e) => (None, e)
}).unzip::<_, _, Vec<_>, Vec<_>>(); }).unzip::<_, _, Vec<_>, Vec<_>>();
let total_err = errors_per_line.into_iter() let total_err = errors_per_line.into_iter()
.map(Vec::into_iter).flatten() .flat_map(Vec::into_iter)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
if total_err.len() > 0 { Err(ParseError::Ast(total_err)) } if !total_err.is_empty() { Err(ParseError::Ast(total_err)) }
else { Ok(parsed_lines.into_iter().map(Option::unwrap).collect()) } else { Ok(parsed_lines.into_iter().map(Option::unwrap).collect()) }
} }
pub fn reparse<'a, Iter, S, Op>(ops: &[Op], stream: S, pre: &Vec<FileEntry>) pub fn reparse<'a, Iter, S, Op>(ops: &[Op], stream: S, pre: &[FileEntry])
-> Result<Vec<FileEntry>, ParseError> -> Result<Vec<FileEntry>, ParseError>
where where
Op: 'a + AsRef<str> + Clone, Op: 'a + AsRef<str> + Clone,
@@ -62,4 +65,4 @@ where
} }
output output
}).collect()) }).collect())
} }

View File

@@ -1,10 +1,10 @@
use std::collections::HashSet; use std::collections::HashSet;
use std::iter;
use crate::enum_parser; use crate::{enum_parser, box_chain};
use crate::expression::{Expr, Clause, Rule}; use crate::expression::{Expr, Clause, Rule};
use crate::utils::BoxedIter; use crate::utils::to_mrc_slice;
use crate::utils::Stackframe; use crate::utils::Stackframe;
use crate::utils::iter::box_empty;
use super::expression::xpr_parser; use super::expression::xpr_parser;
use super::import; use super::import;
@@ -24,12 +24,12 @@ pub enum FileEntry {
fn visit_all_names_clause_recur<'a, F>( fn visit_all_names_clause_recur<'a, F>(
clause: &'a Clause, clause: &'a Clause,
binds: Stackframe<String>, binds: Stackframe<String>,
mut cb: &mut F cb: &mut F
) where F: FnMut(&'a Vec<String>) { ) where F: FnMut(&'a [String]) {
match clause { match clause {
Clause::Auto(name, typ, body) => { Clause::Auto(name, typ, body) => {
for x in typ.iter() { for x in typ.iter() {
visit_all_names_expr_recur(x, binds.clone(), &mut cb) visit_all_names_expr_recur(x, binds.clone(), cb)
} }
let binds_dup = binds.clone(); let binds_dup = binds.clone();
let new_binds = if let Some(n) = name { let new_binds = if let Some(n) = name {
@@ -38,25 +38,23 @@ fn visit_all_names_clause_recur<'a, F>(
binds binds
}; };
for x in body.iter() { for x in body.iter() {
visit_all_names_expr_recur(x, new_binds.clone(), &mut cb) visit_all_names_expr_recur(x, new_binds.clone(), cb)
} }
}, },
Clause::Lambda(name, typ, body) => { Clause::Lambda(name, typ, body) => {
for x in typ.iter() { for x in typ.iter() {
visit_all_names_expr_recur(x, binds.clone(), &mut cb) visit_all_names_expr_recur(x, binds.clone(), cb)
} }
for x in body.iter() { for x in body.iter() {
visit_all_names_expr_recur(x, binds.push(name.to_owned()), &mut cb) visit_all_names_expr_recur(x, binds.push(name.to_owned()), cb)
} }
}, },
Clause::S(_, body) => for x in body.iter() { Clause::S(_, body) => for x in body.iter() {
visit_all_names_expr_recur(x, binds.clone(), &mut cb) visit_all_names_expr_recur(x, binds.clone(), cb)
}, },
Clause::Name{ local, qualified } => { Clause::Name{ local: Some(name), qualified } => {
if let Some(name) = local { if binds.iter().all(|x| x != name) {
if binds.iter().all(|x| x != name) { cb(qualified)
cb(qualified)
}
} }
} }
_ => (), _ => (),
@@ -72,7 +70,7 @@ fn visit_all_names_expr_recur<'a, F>(
expr: &'a Expr, expr: &'a Expr,
binds: Stackframe<String>, binds: Stackframe<String>,
cb: &mut F cb: &mut F
) where F: FnMut(&'a Vec<String>) { ) where F: FnMut(&'a [String]) {
let Expr(val, typ) = expr; let Expr(val, typ) = expr;
visit_all_names_clause_recur(val, binds.clone(), cb); visit_all_names_clause_recur(val, binds.clone(), cb);
if let Some(t) = typ { if let Some(t) = typ {
@@ -81,10 +79,10 @@ fn visit_all_names_expr_recur<'a, F>(
} }
/// Collect all names that occur in an expression /// Collect all names that occur in an expression
fn find_all_names(expr: &Expr) -> HashSet<&Vec<String>> { fn find_all_names(expr: &Expr) -> HashSet<&[String]> {
let mut ret = HashSet::new(); let mut ret = HashSet::new();
visit_all_names_expr_recur(expr, Stackframe::new(String::new()), &mut |n| { visit_all_names_expr_recur(expr, Stackframe::new(String::new()), &mut |n| {
if !n.last().unwrap().starts_with("$") { if !n.last().unwrap().starts_with('$') {
ret.insert(n); ret.insert(n);
} }
}); });
@@ -111,19 +109,27 @@ pub fn line_parser() -> impl Parser<Lexeme, FileEntry, Error = Simple<Lexeme>> {
println!("{:?} could not yield an export", s); e println!("{:?} could not yield an export", s); e
}) })
.ignore_then(rule_parser()) .ignore_then(rule_parser())
.map(|(source, prio, target)| FileEntry::Rule(Rule{source, prio, target}, true)), .map(|(source, prio, target)| FileEntry::Rule(Rule {
source: to_mrc_slice(source),
prio,
target: to_mrc_slice(target)
}, true)),
// This could match almost anything so it has to go last // This could match almost anything so it has to go last
rule_parser().map(|(source, prio, target)| FileEntry::Rule(Rule{source, prio, target}, false)), rule_parser().map(|(source, prio, target)| FileEntry::Rule(Rule{
source: to_mrc_slice(source),
prio,
target: to_mrc_slice(target)
}, false)),
)) ))
} }
/// Collect all exported names (and a lot of other words) from a file /// Collect all exported names (and a lot of other words) from a file
pub fn exported_names(src: &Vec<FileEntry>) -> HashSet<&Vec<String>> { pub fn exported_names(src: &[FileEntry]) -> HashSet<&[String]> {
src.iter().flat_map(|ent| match ent { src.iter().flat_map(|ent| match ent {
FileEntry::Rule(Rule{source, target, ..}, true) => FileEntry::Rule(Rule{source, target, ..}, true) =>
Box::new(source.iter().chain(target.iter())) as BoxedIter<&Expr>, box_chain!(source.iter(), target.iter()),
_ => Box::new(iter::empty()) _ => box_empty()
}).map(find_all_names).flatten().collect() }).flat_map(find_all_names).collect()
} }
/// Summarize all imports from a file in a single list of qualified names /// Summarize all imports from a file in a single list of qualified names
@@ -135,4 +141,4 @@ where I: Iterator<Item = &'b FileEntry> + 'a {
FileEntry::Import(impv) => Some(impv.iter()), FileEntry::Import(impv) => Some(impv.iter()),
_ => None _ => None
}).flatten() }).flatten()
} }

View File

@@ -13,7 +13,7 @@ fn text_parser(delim: char) -> impl Parser<char, char, Error = Simple<char>> {
.or(just('r').to('\r')) .or(just('r').to('\r'))
.or(just('t').to('\t')) .or(just('t').to('\t'))
.or(just('u').ignore_then( .or(just('u').ignore_then(
filter(|c: &char| c.is_digit(16)) filter(|c: &char| c.is_ascii_hexdigit())
.repeated() .repeated()
.exactly(4) .exactly(4)
.collect::<String>() .collect::<String>()
@@ -43,4 +43,4 @@ pub fn str_parser() -> impl Parser<char, String, Error = Simple<char>> {
.repeated() .repeated()
).then_ignore(just('"')) ).then_ignore(just('"'))
.flatten().collect() .flatten().collect()
} }

View File

@@ -3,6 +3,8 @@ use std::rc::Rc;
use std::fs::read_to_string; use std::fs::read_to_string;
use std::path::PathBuf; use std::path::PathBuf;
use mappable_rc::Mrc;
use super::loaded::Loaded; use super::loaded::Loaded;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
@@ -18,7 +20,7 @@ impl From<io::Error> for LoadingError {
} }
} }
pub fn file_loader(proj: PathBuf) -> impl FnMut(Vec<String>) -> Result<Loaded, LoadingError> + 'static { pub fn file_loader(proj: PathBuf) -> impl FnMut(Mrc<[String]>) -> Result<Loaded, LoadingError> + 'static {
move |path| { move |path| {
let dirpath = proj.join(path.join("/")); let dirpath = proj.join(path.join("/"));
if dirpath.is_dir() || dirpath.is_symlink() { if dirpath.is_dir() || dirpath.is_symlink() {
@@ -46,4 +48,4 @@ pub fn file_loader(proj: PathBuf) -> impl FnMut(Vec<String>) -> Result<Loaded, L
else { LoadingError::Missing(pathstr) }) else { LoadingError::Missing(pathstr) })
} }
} }
} }

View File

@@ -1,36 +1,38 @@
use std::{collections::HashMap}; use std::collections::HashMap;
use mappable_rc::Mrc;
use thiserror::Error; use thiserror::Error;
use crate::utils::Stackframe; use crate::utils::{Stackframe, to_mrc_slice};
use crate::expression::{Expr, Clause}; use crate::expression::{Expr, Clause};
type ImportMap = HashMap<String, Vec<String>>; type ImportMap = HashMap<String, Mrc<[String]>>;
#[derive(Debug, Clone, Error)] #[derive(Debug, Clone, Error)]
pub enum ResolutionError<Err> { pub enum ResolutionError<Err> {
#[error("Reference cycle at {0:?}")] #[error("Reference cycle at {0:?}")]
Cycle(Vec<Vec<String>>), Cycle(Vec<Mrc<[String]>>),
#[error("No module provides {0:?}")] #[error("No module provides {0:?}")]
NoModule(Vec<String>), NoModule(Mrc<[String]>),
#[error(transparent)] #[error(transparent)]
Delegate(#[from] Err) Delegate(#[from] Err)
} }
type ResolutionResult<E> = Result<Mrc<[String]>, ResolutionError<E>>;
/// Recursively resolves symbols to their original names in expressions while caching every /// Recursively resolves symbols to their original names in expressions while caching every
/// resolution. This makes the resolution process lightning fast and invalidation completely /// resolution. This makes the resolution process lightning fast and invalidation completely
/// impossible since the intermediate steps of a resolution aren't stored. /// impossible since the intermediate steps of a resolution aren't stored.
pub struct NameResolver<FSplit, FImps, E> { pub struct NameResolver<FSplit, FImps, E> {
cache: HashMap<Vec<String>, Result<Vec<String>, ResolutionError<E>>>, cache: HashMap<Mrc<[String]>, ResolutionResult<E>>,
get_modname: FSplit, get_modname: FSplit,
get_imports: FImps get_imports: FImps
} }
impl<FSplit, FImps, E> NameResolver<FSplit, FImps, E> impl<FSplit, FImps, E> NameResolver<FSplit, FImps, E>
where where
FSplit: FnMut(&Vec<String>) -> Option<Vec<String>>, FSplit: FnMut(Mrc<[String]>) -> Option<Mrc<[String]>>,
FImps: FnMut(&Vec<String>) -> Result<ImportMap, E>, FImps: FnMut(Mrc<[String]>) -> Result<ImportMap, E>,
E: Clone E: Clone
{ {
pub fn new(get_modname: FSplit, get_imports: FImps) -> Self { pub fn new(get_modname: FSplit, get_imports: FImps) -> Self {
@@ -43,58 +45,63 @@ where
/// Obtains a symbol's originnal name /// Obtains a symbol's originnal name
/// Uses a substack to detect loops /// Uses a substack to detect loops
fn find_origin_rec<'a>( fn find_origin_rec(
&mut self, &mut self,
symbol: &'a Vec<String>, symbol: Mrc<[String]>,
import_path: Stackframe<'a, &'a Vec<String>> import_path: Stackframe<Mrc<[String]>>
) -> Result<Vec<String>, ResolutionError<E>> { ) -> Result<Mrc<[String]>, ResolutionError<E>> {
if let Some(cached) = self.cache.get(symbol) { return cached.clone() } if let Some(cached) = self.cache.get(&symbol) { return cached.as_ref().map_err(|e| e.clone()).map(Mrc::clone) }
// The imports and path of the referenced file and the local name // The imports and path of the referenced file and the local name
let path = (self.get_modname)(symbol).ok_or(ResolutionError::NoModule(symbol.clone()))?; let path = (self.get_modname)(Mrc::clone(&symbol)).ok_or_else(|| {
let (_, name) = symbol.split_at(path.len()); ResolutionError::NoModule(Mrc::clone(&symbol))
let imports = (self.get_imports)(&path)?; })?;
let name = &symbol[path.len()..];
if name.is_empty() {
panic!("Something's really broken\n{:?}", import_path)
}
let imports = (self.get_imports)(Mrc::clone(&path))?;
let result = if let Some(source) = imports.get(&name[0]) { let result = if let Some(source) = imports.get(&name[0]) {
let new_sym: Vec<String> = source.iter().chain(name.iter()).cloned().collect(); let new_sym: Vec<String> = source.iter().chain(name.iter()).cloned().collect();
if import_path.iter().any(|el| el == &&new_sym) { if import_path.iter().any(|el| el.as_ref() == new_sym.as_slice()) {
Err(ResolutionError::Cycle(import_path.iter().cloned().cloned().collect())) Err(ResolutionError::Cycle(import_path.iter().map(Mrc::clone).collect()))
} else { } else {
self.find_origin_rec(&new_sym, import_path.push(symbol)) self.find_origin_rec(to_mrc_slice(new_sym), import_path.push(Mrc::clone(&symbol)))
} }
} else { } else {
Ok(symbol.clone()) // If not imported, it must be locally defined Ok(symbol.clone()) // If not imported, it must be locally defined
}; };
self.cache.insert(symbol.clone(), result.clone()); self.cache.insert(symbol, result.clone());
return result result
} }
fn process_exprv_rec(&mut self, exv: &[Expr]) -> Result<Vec<Expr>, ResolutionError<E>> { fn process_exprv_rec(&mut self, exv: &[Expr]) -> Result<Vec<Expr>, ResolutionError<E>> {
exv.iter().map(|ex| self.process_expression_rec(ex)).collect() exv.iter().map(|ex| self.process_expression_rec(ex)).collect()
} }
fn process_exprboxopt_rec(&mut self, fn process_exprmrcopt_rec(&mut self,
exbo: &Option<Box<Expr>> exbo: &Option<Mrc<Expr>>
) -> Result<Option<Box<Expr>>, ResolutionError<E>> { ) -> Result<Option<Mrc<Expr>>, ResolutionError<E>> {
exbo.iter().map(|exb| Ok(Box::new(self.process_expression_rec(exb.as_ref())?))) exbo.iter().map(|exb| Ok(Mrc::new(self.process_expression_rec(exb.as_ref())?)))
.next().transpose() .next().transpose()
} }
fn process_clause_rec(&mut self, tok: &Clause) -> Result<Clause, ResolutionError<E>> { fn process_clause_rec(&mut self, tok: &Clause) -> Result<Clause, ResolutionError<E>> {
Ok(match tok { Ok(match tok {
Clause::S(c, exv) => Clause::S(*c, Clause::S(c, exv) => Clause::S(*c, to_mrc_slice(
exv.iter().map(|e| self.process_expression_rec(e)) exv.as_ref().iter().map(|e| self.process_expression_rec(e))
.collect::<Result<Vec<Expr>, ResolutionError<E>>>()? .collect::<Result<Vec<Expr>, ResolutionError<E>>>()?
), )),
Clause::Lambda(name, typ, body) => Clause::Lambda(name.clone(), Clause::Lambda(name, typ, body) => Clause::Lambda(name.clone(),
self.process_exprv_rec(typ)?, to_mrc_slice(self.process_exprv_rec(typ.as_ref())?),
self.process_exprv_rec(body)? to_mrc_slice(self.process_exprv_rec(body.as_ref())?)
), ),
Clause::Auto(name, typ, body) => Clause::Auto(name.clone(), Clause::Auto(name, typ, body) => Clause::Auto(name.clone(),
self.process_exprv_rec(typ)?, to_mrc_slice(self.process_exprv_rec(typ.as_ref())?),
self.process_exprv_rec(body)? to_mrc_slice(self.process_exprv_rec(body.as_ref())?)
), ),
Clause::Name{local, qualified} => Clause::Name{ Clause::Name{local, qualified} => Clause::Name{
local: local.clone(), local: local.clone(),
qualified: self.find_origin(qualified)? qualified: self.find_origin(Mrc::clone(qualified))?
}, },
x => x.clone() x => x.clone()
}) })
@@ -103,12 +110,12 @@ where
fn process_expression_rec(&mut self, Expr(token, typ): &Expr) -> Result<Expr, ResolutionError<E>> { fn process_expression_rec(&mut self, Expr(token, typ): &Expr) -> Result<Expr, ResolutionError<E>> {
Ok(Expr( Ok(Expr(
self.process_clause_rec(token)?, self.process_clause_rec(token)?,
self.process_exprboxopt_rec(typ)? self.process_exprmrcopt_rec(typ)?
)) ))
} }
pub fn find_origin(&mut self, symbol: &Vec<String>) -> Result<Vec<String>, ResolutionError<E>> { pub fn find_origin(&mut self, symbol: Mrc<[String]>) -> Result<Mrc<[String]>, ResolutionError<E>> {
self.find_origin_rec(symbol, Stackframe::new(symbol)) self.find_origin_rec(Mrc::clone(&symbol), Stackframe::new(symbol))
} }
#[allow(dead_code)] #[allow(dead_code)]
@@ -119,4 +126,4 @@ where
pub fn process_expression(&mut self, ex: &Expr) -> Result<Expr, ResolutionError<E>> { pub fn process_expression(&mut self, ex: &Expr) -> Result<Expr, ResolutionError<E>> {
self.process_expression_rec(ex) self.process_expression_rec(ex)
} }
} }

View File

@@ -1,4 +1,6 @@
use crate::expression::{Expr, Clause}; use mappable_rc::Mrc;
use crate::{expression::{Expr, Clause}, utils::collect_to_mrc};
/// Replaces the first element of a name with the matching prefix from a prefix map /// Replaces the first element of a name with the matching prefix from a prefix map
@@ -6,32 +8,34 @@ use crate::expression::{Expr, Clause};
/// Called by [#prefix] which handles Typed. /// Called by [#prefix] which handles Typed.
fn prefix_clause( fn prefix_clause(
expr: &Clause, expr: &Clause,
namespace: &Vec<String> namespace: Mrc<[String]>
) -> Clause { ) -> Clause {
match expr { match expr {
Clause::S(c, v) => Clause::S(*c, v.iter().map(|e| prefix_expr(e, namespace)).collect()), Clause::S(c, v) => Clause::S(*c,
collect_to_mrc(v.iter().map(|e| prefix_expr(e, Mrc::clone(&namespace))))
),
Clause::Auto(name, typ, body) => Clause::Auto( Clause::Auto(name, typ, body) => Clause::Auto(
name.clone(), name.clone(),
typ.iter().map(|e| prefix_expr(e, namespace)).collect(), collect_to_mrc(typ.iter().map(|e| prefix_expr(e, Mrc::clone(&namespace)))),
body.iter().map(|e| prefix_expr(e, namespace)).collect(), collect_to_mrc(body.iter().map(|e| prefix_expr(e, Mrc::clone(&namespace)))),
), ),
Clause::Lambda(name, typ, body) => Clause::Lambda( Clause::Lambda(name, typ, body) => Clause::Lambda(
name.clone(), name.clone(),
typ.iter().map(|e| prefix_expr(e, namespace)).collect(), collect_to_mrc(typ.iter().map(|e| prefix_expr(e, Mrc::clone(&namespace)))),
body.iter().map(|e| prefix_expr(e, namespace)).collect(), collect_to_mrc(body.iter().map(|e| prefix_expr(e, Mrc::clone(&namespace)))),
), ),
Clause::Name{local, qualified} => Clause::Name{ Clause::Name{local, qualified} => Clause::Name{
local: local.clone(), local: local.clone(),
qualified: namespace.iter().chain(qualified.iter()).cloned().collect() qualified: collect_to_mrc(namespace.iter().chain(qualified.iter()).cloned())
}, },
x => x.clone() x => x.clone()
} }
} }
/// Produce an Expr object for any value of Expr /// Produce an Expr object for any value of Expr
pub fn prefix_expr(Expr(clause, typ): &Expr, namespace: &Vec<String>) -> Expr { pub fn prefix_expr(Expr(clause, typ): &Expr, namespace: Mrc<[String]>) -> Expr {
Expr( Expr(
prefix_clause(clause, namespace), prefix_clause(clause, Mrc::clone(&namespace)),
typ.as_ref().map(|e| Box::new(prefix_expr(e, namespace))) typ.as_ref().map(|e| Mrc::new(prefix_expr(e, namespace)))
) )
} }

View File

@@ -1,10 +1,13 @@
use std::cell::RefCell;
use std::collections::{HashMap, HashSet, VecDeque}; use std::collections::{HashMap, HashSet, VecDeque};
use std::fmt::Debug; use std::fmt::Debug;
use std::rc::Rc; use std::rc::Rc;
use mappable_rc::Mrc;
use crate::expression::Rule; use crate::expression::Rule;
use crate::parse::{self, FileEntry}; use crate::parse::{self, FileEntry};
use crate::utils::Cache; use crate::utils::{Cache, mrc_derive, to_mrc_slice};
use super::name_resolver::NameResolver; use super::name_resolver::NameResolver;
use super::module_error::ModuleError; use super::module_error::ModuleError;
@@ -17,27 +20,29 @@ type ParseResult<T, ELoad> = Result<T, ModuleError<ELoad>>;
pub struct Module { pub struct Module {
pub rules: Vec<Rule>, pub rules: Vec<Rule>,
pub exports: Vec<String>, pub exports: Vec<String>,
pub references: Vec<Vec<String>> pub references: Vec<Mrc<[String]>>
} }
pub type RuleCollectionResult<ELoad> = Result<Vec<super::Rule>, ModuleError<ELoad>>;
pub fn rule_collector<F: 'static, ELoad>( pub fn rule_collector<F: 'static, ELoad>(
mut load_mod: F, mut load_mod: F,
prelude: Vec<String> prelude: Vec<String>
// ) -> impl FnMut(Vec<String>) -> Result<&'a Vec<super::Rule>, ParseError<ELoad>> + 'a ) -> Cache<'static, Mrc<[String]>, RuleCollectionResult<ELoad>>
) -> Cache<'static, Vec<String>, Result<Vec<super::Rule>, ModuleError<ELoad>>>
where where
F: FnMut(Vec<String>) -> Result<Loaded, ELoad>, F: FnMut(Mrc<[String]>) -> Result<Loaded, ELoad>,
ELoad: Clone + Debug ELoad: Clone + Debug
{ {
let load_mod_rc = RefCell::new(load_mod);
// Map paths to a namespace with name list (folder) or module with source text (file) // Map paths to a namespace with name list (folder) or module with source text (file)
let loaded = Rc::new(Cache::new(move |path: Vec<String>, _| let loaded = Rc::new(Cache::new(move |path: Mrc<[String]>, _|
-> ParseResult<Loaded, ELoad> { -> ParseResult<Loaded, ELoad> {
load_mod(path).map_err(ModuleError::Load) (load_mod_rc.borrow_mut())(path).map_err(ModuleError::Load)
})); }));
// Map names to the longest prefix that points to a valid module // Map names to the longest prefix that points to a valid module
let modname = Rc::new(Cache::new({ let modname = Rc::new(Cache::new({
let loaded = Rc::clone(&loaded); let loaded = Rc::clone(&loaded);
move |symbol: Vec<String>, _| -> Result<Vec<String>, Vec<ModuleError<ELoad>>> { move |symbol: Mrc<[String]>, _| -> Result<Mrc<[String]>, Vec<ModuleError<ELoad>>> {
let mut errv: Vec<ModuleError<ELoad>> = Vec::new(); let mut errv: Vec<ModuleError<ELoad>> = Vec::new();
let reg_err = |e, errv: &mut Vec<ModuleError<ELoad>>| { let reg_err = |e, errv: &mut Vec<ModuleError<ELoad>>| {
errv.push(e); errv.push(e);
@@ -45,11 +50,10 @@ where
else { Ok(()) } else { Ok(()) }
}; };
loop { loop {
let (path, _) = symbol.split_at(symbol.len() - errv.len()); let path = mrc_derive(&symbol, |s| &s[..s.len() - errv.len()]);
let pathv = path.to_vec(); match loaded.try_find(&path) {
match loaded.try_find(&pathv) {
Ok(imports) => match imports.as_ref() { Ok(imports) => match imports.as_ref() {
Loaded::Module(_) => break Ok(pathv.clone()), Loaded::Module(_) => break Ok(path),
_ => reg_err(ModuleError::None, &mut errv)? _ => reg_err(ModuleError::None, &mut errv)?
}, },
Err(err) => reg_err(err, &mut errv)? Err(err) => reg_err(err, &mut errv)?
@@ -61,7 +65,7 @@ where
let preparsed = Rc::new(Cache::new({ let preparsed = Rc::new(Cache::new({
let loaded = Rc::clone(&loaded); let loaded = Rc::clone(&loaded);
let prelude2 = prelude.clone(); let prelude2 = prelude.clone();
move |path: Vec<String>, _| -> ParseResult<Vec<FileEntry>, ELoad> { move |path: Mrc<[String]>, _| -> ParseResult<Vec<FileEntry>, ELoad> {
let loaded = loaded.try_find(&path)?; let loaded = loaded.try_find(&path)?;
if let Loaded::Module(source) = loaded.as_ref() { if let Loaded::Module(source) = loaded.as_ref() {
Ok(parse::parse(&prelude2, source.as_str())?) Ok(parse::parse(&prelude2, source.as_str())?)
@@ -72,7 +76,7 @@ where
let exports = Rc::new(Cache::new({ let exports = Rc::new(Cache::new({
let loaded = Rc::clone(&loaded); let loaded = Rc::clone(&loaded);
let preparsed = Rc::clone(&preparsed); let preparsed = Rc::clone(&preparsed);
move |path: Vec<String>, _| -> ParseResult<Vec<String>, ELoad> { move |path: Mrc<[String]>, _| -> ParseResult<Vec<String>, ELoad> {
let loaded = loaded.try_find(&path)?; let loaded = loaded.try_find(&path)?;
if let Loaded::Namespace(names) = loaded.as_ref() { if let Loaded::Namespace(names) = loaded.as_ref() {
return Ok(names.clone()); return Ok(names.clone());
@@ -88,19 +92,19 @@ where
let imports = Rc::new(Cache::new({ let imports = Rc::new(Cache::new({
let preparsed = Rc::clone(&preparsed); let preparsed = Rc::clone(&preparsed);
let exports = Rc::clone(&exports); let exports = Rc::clone(&exports);
move |path: Vec<String>, _| -> ParseResult<HashMap<String, Vec<String>>, ELoad> { move |path: Mrc<[String]>, _| -> ParseResult<HashMap<String, Mrc<[String]>>, ELoad> {
let entv = preparsed.try_find(&path)?.clone(); let entv = preparsed.try_find(&path)?;
let import_entries = parse::imports(entv.iter()); let import_entries = parse::imports(entv.iter());
let mut imported_symbols: HashMap<String, Vec<String>> = HashMap::new(); let mut imported_symbols: HashMap<String, Mrc<[String]>> = HashMap::new();
for imp in import_entries { for imp in import_entries {
let export = exports.try_find(&imp.path)?; let export = exports.try_find(&imp.path)?;
if let Some(ref name) = imp.name { if let Some(ref name) = imp.name {
if export.contains(&name) { if export.contains(name) {
imported_symbols.insert(name.clone(), imp.path.clone()); imported_symbols.insert(name.clone(), Mrc::clone(&imp.path));
} }
} else { } else {
for exp in export.as_ref() { for exp in export.as_ref() {
imported_symbols.insert(exp.clone(), imp.path.clone()); imported_symbols.insert(exp.clone(), Mrc::clone(&imp.path));
} }
} }
} }
@@ -112,7 +116,7 @@ where
let preparsed = Rc::clone(&preparsed); let preparsed = Rc::clone(&preparsed);
let imports = Rc::clone(&imports); let imports = Rc::clone(&imports);
let loaded = Rc::clone(&loaded); let loaded = Rc::clone(&loaded);
move |path: Vec<String>, _| -> ParseResult<Vec<FileEntry>, ELoad> { move |path: Mrc<[String]>, _| -> ParseResult<Vec<FileEntry>, ELoad> {
let imported_ops: Vec<String> = let imported_ops: Vec<String> =
imports.try_find(&path)? imports.try_find(&path)?
.keys() .keys()
@@ -127,45 +131,44 @@ where
} else { Err(ModuleError::None) } } else { Err(ModuleError::None) }
} }
})); }));
let mut name_resolver = NameResolver::new({ let mut name_resolver_rc = RefCell::new(NameResolver::new({
let modname = Rc::clone(&modname); let modname = Rc::clone(&modname);
move |path| { move |path| {
Some(modname.try_find(path).ok()?.as_ref().clone()) Some(modname.try_find(&path).ok()?.as_ref().clone())
} }
}, { }, {
let imports = Rc::clone(&imports); let imports = Rc::clone(&imports);
move |path| { move |path| {
imports.try_find(path).map(|f| f.as_ref().clone()) imports.try_find(&path).map(|f| f.as_ref().clone())
} }
}); }));
// Turn parsed files into a bag of rules and a list of toplevel export names // Turn parsed files into a bag of rules and a list of toplevel export names
let resolved = Rc::new(Cache::new({ let resolved = Rc::new(Cache::new({
let parsed = Rc::clone(&parsed); let parsed = Rc::clone(&parsed);
let exports = Rc::clone(&exports); let exports = Rc::clone(&exports);
let imports = Rc::clone(&imports); let imports = Rc::clone(&imports);
let modname = Rc::clone(&modname); let modname = Rc::clone(&modname);
move |path: Vec<String>, _| -> ParseResult<Module, ELoad> { move |path: Mrc<[String]>, _| -> ParseResult<Module, ELoad> {
let mut name_resolver = name_resolver_rc.borrow_mut();
let module = Module { let module = Module {
rules: parsed.try_find(&path)? rules: parsed.try_find(&path)?
.iter() .iter()
.filter_map(|ent| { .filter_map(|ent| {
if let FileEntry::Rule(Rule{source, prio, target}, _) = ent { if let FileEntry::Rule(Rule{source, prio, target}, _) = ent {
Some(Rule { Some(Rule {
source: source.iter().map(|ex| prefix_expr(ex, &path)).collect(), source: source.iter().map(|ex| prefix_expr(ex, Mrc::clone(&path))).collect(),
target: target.iter().map(|ex| prefix_expr(ex, &path)).collect(), target: target.iter().map(|ex| prefix_expr(ex, Mrc::clone(&path))).collect(),
prio: *prio, prio: *prio,
}) })
} else { None } } else { None }
}) })
.map(|rule| Ok(super::Rule { .map(|rule| Ok(super::Rule {
source: rule.source.iter() source: to_mrc_slice(rule.source.iter()
.map(|ex| name_resolver.process_expression(ex)) .map(|ex| name_resolver.process_expression(ex))
.collect::<Result<Vec<_>, _>>()?, .collect::<Result<Vec<_>, _>>()?),
target: rule.target.iter() target: to_mrc_slice(rule.target.iter()
.map(|ex| name_resolver.process_expression(ex)) .map(|ex| name_resolver.process_expression(ex))
.collect::<Result<Vec<_>, _>>()?, .collect::<Result<Vec<_>, _>>()?),
// source: name_resolver.process_expression(&rule.source)?,
// target: name_resolver.process_expression(&rule.target)?,
..rule ..rule
})) }))
.collect::<ParseResult<Vec<super::Rule>, ELoad>>()?, .collect::<ParseResult<Vec<super::Rule>, ELoad>>()?,
@@ -173,19 +176,20 @@ where
references: imports.try_find(&path)? references: imports.try_find(&path)?
.values() .values()
.filter_map(|imps| { .filter_map(|imps| {
modname.try_find(&imps).ok().map(|r| r.as_ref().clone()) modname.try_find(imps).ok().map(|r| r.as_ref().clone())
}) })
.collect() .collect()
}; };
Ok(module) Ok(module)
} }
})); }));
let all_rules = Cache::new({ Cache::new({
let resolved = Rc::clone(&resolved); let resolved = Rc::clone(&resolved);
move |path: Vec<String>, _| -> ParseResult<Vec<super::Rule>, ELoad> { move |path: Mrc<[String]>, _| -> ParseResult<Vec<super::Rule>, ELoad> {
let mut processed: HashSet<Vec<String>> = HashSet::new(); // Breadth-first search
let mut processed: HashSet<Mrc<[String]>> = HashSet::new();
let mut rules: Vec<super::Rule> = Vec::new(); let mut rules: Vec<super::Rule> = Vec::new();
let mut pending: VecDeque<Vec<String>> = VecDeque::new(); let mut pending: VecDeque<Mrc<[String]>> = VecDeque::new();
pending.push_back(path); pending.push_back(path);
while let Some(el) = pending.pop_front() { while let Some(el) = pending.pop_front() {
let resolved = resolved.try_find(&el)?; let resolved = resolved.try_find(&el)?;
@@ -201,6 +205,5 @@ where
}; };
Ok(rules) Ok(rules)
} }
}); })
return all_rules;
} }

View File

@@ -0,0 +1,151 @@
use hashbrown::HashMap;
use mappable_rc::Mrc;
use crate::{expression::{Expr, Clause}, utils::{iter::{box_once, into_boxed_iter}, to_mrc_slice}};
use super::{super::RuleError, state::{State, Entry}, slice_matcher::SliceMatcherDnC};
fn verify_scalar_vec(pattern: &Expr, is_vec: &mut HashMap<String, bool>)
-> Result<(), String> {
let verify_clause = |clause: &Clause, is_vec: &mut HashMap<String, bool>| -> Result<(), String> {
match clause {
Clause::Placeh{key, vec} => {
if let Some(known) = is_vec.get(key) {
if known != &vec.is_some() { return Err(key.to_string()) }
} else {
is_vec.insert(key.clone(), vec.is_some());
}
}
Clause::Auto(name, typ, body) => {
if let Some(key) = name.as_ref().and_then(|key| key.strip_prefix('$')) {
if is_vec.get(key) == Some(&true) { return Err(key.to_string()) }
}
typ.iter().try_for_each(|e| verify_scalar_vec(e, is_vec))?;
body.iter().try_for_each(|e| verify_scalar_vec(e, is_vec))?;
}
Clause::Lambda(name, typ, body) => {
if let Some(key) = name.strip_prefix('$') {
if is_vec.get(key) == Some(&true) { return Err(key.to_string()) }
}
typ.iter().try_for_each(|e| verify_scalar_vec(e, is_vec))?;
body.iter().try_for_each(|e| verify_scalar_vec(e, is_vec))?;
}
Clause::S(_, body) => {
body.iter().try_for_each(|e| verify_scalar_vec(e, is_vec))?;
}
_ => ()
};
Ok(())
};
let Expr(val, typ_opt) = pattern;
verify_clause(val, is_vec)?;
if let Some(typ) = typ_opt {
verify_scalar_vec(typ, is_vec)?;
}
Ok(())
}
fn slice_to_vec(src: &mut Mrc<[Expr]>, tgt: &mut Mrc<[Expr]>) {
let prefix_expr = Expr(Clause::Placeh{key: "::prefix".to_string(), vec: Some((0, false))}, None);
let postfix_expr = Expr(Clause::Placeh{key: "::postfix".to_string(), vec: Some((0, false))}, None);
// Prefix or postfix to match the full vector
let head_multi = matches!(src.first().expect("Src can never be empty!").0, Clause::Placeh{vec: Some(_), ..});
let tail_multi = matches!(src.last().expect("Impossible branch!").0, Clause::Placeh{vec: Some(_), ..});
let prefix_vec = if head_multi {vec![]} else {vec![prefix_expr]};
let postfix_vec = if tail_multi {vec![]} else {vec![postfix_expr]};
*src = to_mrc_slice(prefix_vec.iter().chain(src.iter()).chain(postfix_vec.iter()).cloned().collect());
*tgt = to_mrc_slice(prefix_vec.iter().chain(tgt.iter()).chain(postfix_vec.iter()).cloned().collect());
}
/// Traverse the tree, calling pred on every sibling list until it returns some vec
/// then replace the sibling list with that vec and return true
/// return false if pred never returned some
fn update_first_seq_rec<F>(input: Mrc<[Expr]>, pred: &mut F) -> Option<Mrc<[Expr]>>
where F: FnMut(Mrc<[Expr]>) -> Option<Mrc<[Expr]>> {
if let o@Some(_) = pred(Mrc::clone(&input)) {o} else {
for Expr(cls, _) in input.iter() {
if let Some(t) = cls.typ() {
if let o@Some(_) = update_first_seq_rec(t, pred) {return o}
}
if let Some(b) = cls.body() {
if let o@Some(_) = update_first_seq_rec(b, pred) {return o}
}
}
None
}
}
/// keep re-probing the input with pred until it stops matching
fn update_all_seqs<F>(input: Mrc<[Expr]>, pred: &mut F) -> Option<Mrc<[Expr]>>
where F: FnMut(Mrc<[Expr]>) -> Option<Mrc<[Expr]>> {
let mut tmp = update_first_seq_rec(input, pred);
while let Some(xv) = tmp {
tmp = update_first_seq_rec(Mrc::clone(&xv), pred);
if tmp.is_none() {return Some(xv)}
}
None
}
/// Fill in a template from a state as produced by a pattern
fn write_slice(state: &State, tpl: &Mrc<[Expr]>) -> Mrc<[Expr]> {
tpl.iter().flat_map(|Expr(clause, xpr_typ)| match clause {
Clause::Auto(name_opt, typ, body) => box_once(Expr(Clause::Auto(
name_opt.as_ref().and_then(|name| {
let state_key = name.strip_prefix('$')
.expect("Auto template may only reference, never enforce the name");
match &state[state_key] {
Entry::NameOpt(name) => name.as_ref().map(|s| s.as_ref().to_owned()),
Entry::Name(name) => Some(name.as_ref().to_owned()),
_ => panic!("Auto template name may only be derived from Auto or Lambda name")
}
}),
write_slice(state, typ),
write_slice(state, body)
), xpr_typ.to_owned())),
Clause::Lambda(name, typ, body) => box_once(Expr(Clause::Lambda(
if let Some(state_key) = name.strip_prefix('$') {
if let Entry::Name(name) = &state[state_key] {
name.as_ref().to_owned()
} else {panic!("Lambda template name may only be derived from Lambda name")}
} else {
name.to_owned()
},
write_slice(state, typ),
write_slice(state, body)
), xpr_typ.to_owned())),
Clause::S(c, body) => box_once(Expr(Clause::S(
*c,
write_slice(state, body)
), xpr_typ.to_owned())),
Clause::Placeh{key, vec: None} => if let Entry::Scalar(x) = &state[key] {
box_once(x.as_ref().to_owned())
} else {panic!("Scalar template may only be derived from scalar placeholder")},
Clause::Placeh{key, vec: Some(_)} => if let Entry::Vec(v) = &state[key] {
into_boxed_iter(v.as_ref().to_owned())
} else {panic!("Vectorial template may only be derived from vectorial placeholder")},
// Explicit base case so that we get an error if Clause gets new values
c@Clause::Literal(_) | c@Clause::Name { .. } =>
box_once(Expr(c.to_owned(), xpr_typ.to_owned()))
}).collect()
}
/// Apply a rule (a pair of pattern and template) to an expression
pub fn execute(mut src: Mrc<[Expr]>, mut tgt: Mrc<[Expr]>, input: Mrc<[Expr]>)
-> Result<Option<Mrc<[Expr]>>, RuleError> {
// Dimension check
let mut is_vec_db = HashMap::new();
src.iter().try_for_each(|e| verify_scalar_vec(e, &mut is_vec_db))
.map_err(RuleError::ScalarVecMismatch)?;
tgt.iter().try_for_each(|e| verify_scalar_vec(e, &mut is_vec_db))
.map_err(RuleError::ScalarVecMismatch)?;
// Padding
slice_to_vec(&mut src, &mut tgt);
// Generate matcher
let matcher = SliceMatcherDnC::new(src);
println!("Matcher: {matcher:#?}");
let matcher_cache = SliceMatcherDnC::get_matcher_cache();
Ok(update_all_seqs(Mrc::clone(&input), &mut |p| {
let state = matcher.match_range_cached(p, &matcher_cache)?;
Some(write_slice(&state, &tgt))
}))
}

View File

@@ -1,4 +1,8 @@
mod slice_matcher; mod slice_matcher;
mod state; mod state;
mod execute;
mod split_at_max_vec;
use state::State; use state::State;
pub use execute::execute;

View File

@@ -1,28 +1,27 @@
use hashbrown::HashMap;
use itertools::Itertools; use std::fmt::Debug;
use mappable_rc::Mrc;
use crate::expression::{Expr, Clause}; use crate::expression::{Expr, Clause};
use crate::unwrap_or_continue; use crate::unwrap_or_continue;
use crate::utils::{Side, Cache}; use crate::utils::iter::box_empty;
use super::super::RuleError; use crate::utils::{Side, Cache, mrc_derive, mrc_try_derive, to_mrc_slice};
use super::State;
fn split_at_max_vec(pattern: &[Expr]) -> Option<(&[Expr], (&str, usize), &[Expr])> { use super::State;
let rngidx = pattern.iter().position_max_by_key(|ex| { use super::split_at_max_vec::split_at_max_vec;
if let Expr(Clause::Placeh(_, Some(prio)), _) = ex { *prio as i64 } else { -1 }
})?; /// Tuple with custom cloning logic
let (left, not_left) = pattern.split_at(rngidx); #[derive(Debug, Eq, PartialEq, Hash)]
let (placeh, right) = if rngidx == pattern.len() { pub struct CacheEntry<'a>(Mrc<[Expr]>, &'a SliceMatcherDnC);
(&not_left[0].0, [].as_slice()) impl<'a> Clone for CacheEntry<'a> {
} else { fn clone(&self) -> Self {
let (placeh_unary_slice, right) = pattern.split_at(rngidx + 1); let CacheEntry(mrc, matcher) = self;
(&placeh_unary_slice[0].0, right) CacheEntry(Mrc::clone(mrc), matcher)
}; }
if let Clause::Placeh(name, Some(prio)) = placeh {
Some((left, (name, *prio), right))
} else {None}
} }
/// Matcher that applies a pattern to a slice via divide-and-conquer /// Matcher that applies a pattern to a slice via divide-and-conquer
/// ///
/// Upon construction, it selects the clause of highest priority, then /// Upon construction, it selects the clause of highest priority, then
@@ -31,134 +30,171 @@ fn split_at_max_vec(pattern: &[Expr]) -> Option<(&[Expr], (&str, usize), &[Expr]
/// ///
/// Upon matching, it uses a cache to accelerate the process of executing /// Upon matching, it uses a cache to accelerate the process of executing
/// a pattern on the entire tree. /// a pattern on the entire tree.
#[derive(Debug, Clone, Eq)] #[derive(Clone, Eq)]
pub struct SliceMatcherDnC<'a> { pub struct SliceMatcherDnC {
/// The entire pattern this will match /// The entire pattern this will match
pattern: &'a [Expr], pattern: Mrc<[Expr]>,
/// The exact clause this can match /// The exact clause this can match
clause: &'a Clause, clause: Mrc<Clause>,
/// Matcher for the parts of the pattern right from us /// Matcher for the parts of the pattern right from us
right_subm: Option<Box<SliceMatcherDnC<'a>>>, right_subm: Option<Box<SliceMatcherDnC>>,
/// Matcher for the parts of the pattern left from us /// Matcher for the parts of the pattern left from us
left_subm: Option<Box<SliceMatcherDnC<'a>>>, left_subm: Option<Box<SliceMatcherDnC>>,
/// Matcher for the body of this clause if it has one. /// Matcher for the body of this clause if it has one.
/// Must be Some if pattern is (Auto, Lambda or S) /// Must be Some if pattern is (Auto, Lambda or S)
body_subm: Option<Box<SliceMatcherDnC<'a>>>, body_subm: Option<Box<SliceMatcherDnC>>,
/// Matcher for the type of this expression if it has one (Auto usually does) /// Matcher for the type of this expression if it has one (Auto usually does)
/// Optional /// Optional
typ_subm: Option<Box<SliceMatcherDnC<'a>>>, typ_subm: Option<Box<SliceMatcherDnC>>,
} }
impl<'a> PartialEq for SliceMatcherDnC<'a> { impl PartialEq for SliceMatcherDnC {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.pattern == other.pattern self.pattern == other.pattern
} }
} }
impl<'a> std::hash::Hash for SliceMatcherDnC<'a> { impl std::hash::Hash for SliceMatcherDnC {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.pattern.hash(state); self.pattern.hash(state);
} }
} }
impl<'a> SliceMatcherDnC<'a> { impl SliceMatcherDnC {
/// If this is true, `clause`, `typ_subm`, `body_subm` and `clause_qual_name` are meaningless. /// If this is true, `clause`, `typ_subm`, `body_subm` and `clause_qual_name` are meaningless.
/// If it's false, it's also false for both side matchers. /// If it's false, it's also false for both side matchers.
pub fn clause_is_vectorial(&self) -> bool { pub fn clause_is_vectorial(&self) -> bool {
if let Clause::Placeh(_, Some(_)) = self.clause {true} else {false} matches!(self.clause.as_ref(), Clause::Placeh{vec: Some(..), ..})
} }
/// If clause is a name, the qualified name this can match /// If clause is a name, the qualified name this can match
pub fn clause_qual_name(&self) -> Option<&'a Vec<String>> { pub fn clause_qual_name(&self) -> Option<Mrc<[String]>> {
if let Clause::Name { qualified, .. } = self.clause {Some(qualified)} else {None} if let Clause::Name { qualified, .. } = self.clause.as_ref() {Some(Mrc::clone(qualified))} else {None}
} }
/// If clause is a Placeh, the key in the state the match will be stored at /// If clause is a Placeh, the key in the state the match will be stored at
pub fn state_key(&self) -> Option<&'a String> { pub fn state_key(&self) -> Option<&String> {
if let Clause::Placeh(key, _) = self.clause {Some(key)} else {None} if let Clause::Placeh { key, .. } = self.clause.as_ref() {Some(key)} else {None}
} }
pub fn own_max_size(&self, total: usize) -> usize { pub fn own_max_size(&self, total: usize) -> Option<usize> {
if !self.clause_is_vectorial() {return self.len()} if !self.clause_is_vectorial() {
return total - self.min(Side::Left) - self.min(Side::Right) if total == self.len() {Some(total)} else {None}
} else {
let margin = self.min(Side::Left) + self.min(Side::Right);
if margin + self.own_min_size() <= total {Some(total - margin)} else {None}
}
} }
pub fn own_min_size(&self) -> usize {
if let Clause::Placeh { vec: Some((_, nonzero)), .. } = self.clause.as_ref() {
if *nonzero {1} else {0}
} else {self.len()}
}
/// Enumerate all valid subdivisions based on the reported size constraints of self and /// Enumerate all valid subdivisions based on the reported size constraints of self and
/// the two subranges /// the two subranges
pub fn valid_subdivisions<'b>(&self, pub fn valid_subdivisions(&self,
range: &'b [Expr] range: Mrc<[Expr]>
) -> impl Iterator<Item = (&'b [Expr], &'b [Expr], &'b [Expr])> { ) -> impl Iterator<Item = (Mrc<[Expr]>, Mrc<[Expr]>, Mrc<[Expr]>)> {
let own_size = self.own_max_size(range.len()); let own_max = {
if let Some(x) = self.own_max_size(range.len()) {x}
else {return box_empty()}
};
let own_min = self.own_min_size();
let lmin = self.min(Side::Left); let lmin = self.min(Side::Left);
let lmax = self.max(Side::Left, range.len()); let _lmax = self.max(Side::Left, range.len());
let rmin = self.min(Side::Right); let rmin = self.min(Side::Right);
let rmax = self.max(Side::Right, range.len()); let _rmax = self.max(Side::Right, range.len());
let full_len = range.len(); let full_len = range.len();
(1..=own_size).rev().flat_map(move |own_len| { Box::new((own_min..=own_max).rev().flat_map(move |own_len| {
let wiggle = full_len - lmin - rmin - own_len; let wiggle = full_len - lmin - rmin - own_len;
(0..wiggle).map(move |offset| { let range = Mrc::clone(&range);
(0..=wiggle).map(move |offset| {
let first_break = lmin + offset; let first_break = lmin + offset;
let (left, rest) = range.split_at(first_break); let second_break = first_break + own_len;
let (mid, right) = rest.split_at(own_len); let left = mrc_derive(&range, |p| &p[0..first_break]);
let mid = mrc_derive(&range, |p| &p[first_break..second_break]);
let right = mrc_derive(&range, |p| &p[second_break..]);
(left, mid, right) (left, mid, right)
}) })
}) }))
} }
pub fn new(pattern: &'a [Expr]) -> Self { pub fn new(pattern: Mrc<[Expr]>) -> Self {
let (Expr(clause, _), left_subm, right_subm) = if pattern.len() == 1 { let (clause, left_subm, right_subm) = mrc_try_derive(&pattern, |p| {
(&pattern[0], None, None) if p.len() == 1 {Some(&p[0].0)} else {None}
} else if let Some((left, _, right)) = split_at_max_vec(pattern) {( }).map(|e| (e, None, None))
&pattern[left.len()], .or_else(|| split_at_max_vec(Mrc::clone(&pattern)).map(|(left, _, right)| (
Some(Box::new(Self::new(left))), mrc_derive(&pattern, |p| &p[left.len()].0),
Some(Box::new(Self::new(right))) if !left.is_empty() {Some(Box::new(Self::new(left)))} else {None},
)} else {( if !right.is_empty() {Some(Box::new(Self::new(right)))} else {None}
&pattern[0], )))
None, .unwrap_or_else(|| (
Some(Box::new(Self::new(&pattern[1..]))) mrc_derive(&pattern, |p| &p[0].0),
)}; None,
Some(Box::new(Self::new(mrc_derive(&pattern, |p| &p[1..]))))
));
// let (Expr(clause, _), left_subm, right_subm) = if pattern.len() == 1 {
// (&pattern[0], None, None)
// } else if let Some((left, _, right)) = split_at_max_vec(pattern) {(
// &pattern[left.len()],
// Some(Box::new(Self::new(left))),
// Some(Box::new(Self::new(right)))
// )} else {(
// &pattern[0],
// None,
// Some(Box::new(Self::new(&pattern[1..])))
// )};
Self { Self {
pattern, right_subm, left_subm, clause, pattern, right_subm, left_subm,
clause: Mrc::clone(&clause),
body_subm: clause.body().map(|b| Box::new(Self::new(b))), body_subm: clause.body().map(|b| Box::new(Self::new(b))),
typ_subm: clause.typ().map(|t| Box::new(Self::new(t))) typ_subm: clause.typ().map(|t| Box::new(Self::new(t)))
} }
} }
/// The shortest slice this pattern can match /// The shortest slice this pattern can match
fn len(&self) -> usize {self.pattern.len()} fn len(&self) -> usize {
if self.clause_is_vectorial() {
self.min(Side::Left) + self.min(Side::Right) + self.own_min_size()
} else {self.pattern.len()}
}
/// Pick a subpattern based on the parameter /// Pick a subpattern based on the parameter
fn side(&self, side: Side) -> Option<&Box<SliceMatcherDnC<'a>>> { fn side(&self, side: Side) -> Option<&SliceMatcherDnC> {
match side { match side {
Side::Left => &self.left_subm, Side::Left => &self.left_subm,
Side::Right => &self.right_subm Side::Right => &self.right_subm
}.as_ref() }.as_ref().map(|b| b.as_ref())
} }
/// The shortest slice the given side can match /// The shortest slice the given side can match
fn min(&self, side: Side) -> usize {self.side(side).map_or(0, |right| right.len())} fn min(&self, side: Side) -> usize {self.side(side).map_or(0, |right| right.len())}
/// The longest slice the given side can match /// The longest slice the given side can match
fn max(&self, side: Side, total: usize) -> usize { fn max(&self, side: Side, total: usize) -> usize {
self.side(side).map_or(0, |m| if m.clause_is_vectorial() { self.side(side).map_or(0, |m| if m.clause_is_vectorial() {
total - self.min(side.opposite()) - 1 total - self.min(side.opposite()) - self.own_min_size()
} else {m.len()}) } else {m.len()})
} }
/// Take the smallest possible slice from the given side /// Take the smallest possible slice from the given side
fn slice_min<'b>(&self, side: Side, range: &'b [Expr]) -> &'b [Expr] { fn slice_min<'a>(&self, side: Side, range: &'a [Expr]) -> &'a [Expr] {
side.slice(self.min(side), range) side.slice(self.min(side), range)
} }
/// Matches the body on a range /// Matches the body on a range
/// # Panics /// # Panics
/// when called on an instance that does not have a body (not Auto, Lambda or S) /// when called on an instance that does not have a body (not Auto, Lambda or S)
fn match_body<'b>(&'a self, fn match_body<'a>(&'a self,
range: &'b [Expr], cache: &Cache<(&'b [Expr], &'a SliceMatcherDnC<'a>), Option<State>> range: Mrc<[Expr]>, cache: &Cache<CacheEntry<'a>, Option<State>>
) -> Option<State> { ) -> Option<State> {
self.body_subm.as_ref().unwrap().match_range_cached(range, cache) self.body_subm.as_ref()
.expect("Missing body matcher")
.match_range_cached(range, cache)
} }
/// Matches the type and body on respective ranges /// Matches the type and body on respective ranges
/// # Panics /// # Panics
/// when called on an instance that does not have a body (not Auto, Lambda or S) /// when called on an instance that does not have a body (not Auto, Lambda or S)
fn match_parts<'b>(&'a self, fn match_parts<'a>(&'a self,
typ_range: &'b [Expr], body_range: &'b [Expr], typ_range: Mrc<[Expr]>, body_range: Mrc<[Expr]>,
cache: &Cache<(&'b [Expr], &'a SliceMatcherDnC<'a>), Option<State>> cache: &Cache<CacheEntry<'a>, Option<State>>
) -> Option<State> { ) -> Option<State> {
let typ_state = if let Some(typ) = &self.typ_subm { let typ_state = if let Some(typ) = &self.typ_subm {
typ.match_range_cached(&typ_range, cache)? typ.match_range_cached(typ_range, cache)?
} else {State::new()}; } else {State::new()};
let body_state = self.match_body(body_range, cache)?; let body_state = self.match_body(body_range, cache)?;
typ_state + body_state typ_state + body_state
@@ -166,181 +202,124 @@ impl<'a> SliceMatcherDnC<'a> {
/// Match the specified side-submatcher on the specified range with the cache /// Match the specified side-submatcher on the specified range with the cache
/// In absence of a side-submatcher empty ranges are matched to empty state /// In absence of a side-submatcher empty ranges are matched to empty state
fn apply_side_with_cache<'b>(&'a self, fn apply_side_with_cache<'a>(&'a self,
side: Side, range: &'b [Expr], side: Side, range: Mrc<[Expr]>,
cache: &Cache<(&'b [Expr], &'a SliceMatcherDnC<'a>), Option<State>> cache: &Cache<CacheEntry<'a>, Option<State>>
) -> Option<State> { ) -> Option<State> {
match &self.side(side) { match &self.side(side) {
None => { None => {
if range.len() != 0 {None} if !range.is_empty() {None}
else {Some(State::new())} else {Some(State::new())}
}, },
Some(m) => cache.try_find(&(range, &m)).map(|s| s.as_ref().to_owned()) Some(m) => cache.try_find(&CacheEntry(range, m)).map(|s| s.as_ref().to_owned())
} }
} }
fn match_range_scalar_cached<'b>(&'a self, fn match_range_scalar_cached<'a>(&'a self,
target: &'b [Expr], target: Mrc<[Expr]>,
cache: &Cache<(&'b [Expr], &'a SliceMatcherDnC<'a>), Option<State>> cache: &Cache<CacheEntry<'a>, Option<State>>
) -> Option<State> { ) -> Option<State> {
let pos = self.min(Side::Left); let pos = self.min(Side::Left);
if target.len() != self.pattern.len() {return None} if target.len() != self.pattern.len() {return None}
let mut own_state = ( let mut own_state = (
self.apply_side_with_cache(Side::Left, &target[0..pos], cache)? self.apply_side_with_cache(Side::Left, mrc_derive(&target, |t| &t[0..pos]), cache)?
+ self.apply_side_with_cache(Side::Right, &target[pos+1..], cache) + self.apply_side_with_cache(Side::Right, mrc_derive(&target, |t| &t[pos+1..]), cache)
)?; )?;
match (self.clause, &target[pos].0) { match (self.clause.as_ref(), &target.as_ref()[pos].0) {
(Clause::Literal(val), Clause::Literal(tgt)) => { (Clause::Literal(val), Clause::Literal(tgt)) => {
if val == tgt {Some(own_state)} else {None} if val == tgt {Some(own_state)} else {None}
} }
(Clause::Placeh(name, None), _) => { (Clause::Placeh{key, vec: None}, _) => {
own_state.insert(name, &[target[pos].clone()]) own_state.insert_scalar(&key, &target[pos])
} }
(Clause::S(c, _), Clause::S(c_tgt, body_range)) => { (Clause::S(c, _), Clause::S(c_tgt, body_range)) => {
if c != c_tgt {return None} if c != c_tgt {return None}
own_state + self.match_parts(&[], body_range, cache) own_state + self.match_parts(to_mrc_slice(vec![]), Mrc::clone(body_range), cache)
} }
(Clause::Name{qualified, ..}, Clause::Name{qualified: q_tgt, ..}) => { (Clause::Name{qualified, ..}, Clause::Name{qualified: q_tgt, ..}) => {
if qualified == q_tgt {Some(own_state)} else {None} if qualified == q_tgt {Some(own_state)} else {None}
} }
(Clause::Lambda(name, _, _), Clause::Lambda(name_tgt, typ_tgt, body_tgt)) => { (Clause::Lambda(name, _, _), Clause::Lambda(name_tgt, typ_tgt, body_tgt)) => {
// Primarily, the name works as a placeholder // Primarily, the name works as a placeholder
if let Some(state_key) = name.strip_prefix("$") { if let Some(state_key) = name.strip_prefix('$') {
own_state = own_state.insert( own_state = own_state.insert_name(state_key, name_tgt)?
state_key,
&[Expr(Clause::Name{
local: Some(name_tgt.clone()),
qualified: vec![name_tgt.clone()]
}, None)]
)?
// But if you're weird like that, it can also work as a constraint
} else if name != name_tgt {return None} } else if name != name_tgt {return None}
own_state + self.match_parts(typ_tgt, body_tgt, cache) // ^ But if you're weird like that, it can also work as a constraint
own_state + self.match_parts(Mrc::clone(typ_tgt), Mrc::clone(body_tgt), cache)
} }
(Clause::Auto(name_opt, _, _), Clause::Auto(name_range, typ_range, body_range)) => { (Clause::Auto(name_opt, _, _), Clause::Auto(name_range, typ_range, body_range)) => {
if let Some(name) = name_opt { if let Some(name) = name_opt {
if let Some(state_name) = name.strip_prefix("$") { // TODO: Enforce this at construction, on a type system level
own_state = own_state.insert( let state_key = name.strip_prefix('$')
state_name, .expect("Auto patterns may only reference, never enforce the name");
&[Expr(Clause::Name{ own_state = own_state.insert_name_opt(state_key, name_range.as_ref())?
local: name_range.clone(),
qualified: name_range.as_ref()
.map(|s| vec![s.clone()])
.unwrap_or_default()
}, None)]
)?
// TODO: Enforce this at construction, on a type system level
} else {panic!("Auto patterns may only reference, never enforce the name")}
} }
own_state + self.match_parts(typ_range, body_range, cache) own_state + self.match_parts(Mrc::clone(typ_range), Mrc::clone(body_range), cache)
}, },
_ => None _ => None
} }
} }
/// Match the range with a vectorial _assuming we are a vectorial_ /// Match the range with a vectorial _assuming we are a vectorial_
fn match_range_vectorial_cached<'b>(&'a self, fn match_range_vectorial_cached<'a>(&'a self,
name: &str, name: &str,
target: &'b [Expr], target: Mrc<[Expr]>,
cache: &Cache<(&'b [Expr], &'a SliceMatcherDnC<'a>), Option<State>> cache: &Cache<CacheEntry<'a>, Option<State>>
) -> Option<State> { ) -> Option<State> {
// Step through valid slicings based on reported size constraints in order // Step through valid slicings based on reported size constraints in order
// from longest own section to shortest and from left to right // from longest own section to shortest and from left to right
for (left, own, right) in self.valid_subdivisions(target) { for (left, own, right) in self.valid_subdivisions(target) {
let left_result = unwrap_or_continue!(self.apply_side_with_cache(Side::Left, left, cache)); let sides_result = unwrap_or_continue!(
let right_result = unwrap_or_continue!(self.apply_side_with_cache(Side::Right, right, cache)); self.apply_side_with_cache(Side::Left, left, cache)
) + self.apply_side_with_cache(Side::Right, right, cache);
return Some(unwrap_or_continue!( return Some(unwrap_or_continue!(
right_result.clone() unwrap_or_continue!(sides_result)
+ left_result.insert(name, own) .insert_vec(name, own.as_ref())
)) ))
} }
return None None
} }
/// Try and match the specified range /// Try and match the specified range
pub fn match_range_cached<'b>(&'a self, pub fn match_range_cached<'a>(&'a self,
target: &'b [Expr], target: Mrc<[Expr]>,
cache: &Cache<(&'b [Expr], &'a SliceMatcherDnC<'a>), Option<State>> cache: &Cache<CacheEntry<'a>, Option<State>>
) -> Option<State> { ) -> Option<State> {
if self.pattern.len() == 0 { eprintln!("Matching {target:?} with {:?}", self.pattern);
return if target.len() == 0 {Some(State::new())} else {None} if self.pattern.is_empty() {
return if target.is_empty() {Some(State::new())} else {None}
} }
match self.clause { match self.clause.as_ref() {
Clause::Placeh(name, Some(_)) => self.match_range_vectorial_cached(name, target, cache), Clause::Placeh{key, vec: Some(_)} =>
self.match_range_vectorial_cached(key, target, cache),
_ => self.match_range_scalar_cached(target, cache) _ => self.match_range_scalar_cached(target, cache)
} }
} }
pub fn match_range(&self, target: &[Expr]) -> Option<State> { pub fn get_matcher_cache<'a>()
self.match_range_cached(target,&Cache::<(&[Expr], &SliceMatcherDnC), _>::new( -> Cache<'a, CacheEntry<'a>, Option<State>> {
|(tgt, matcher), cache| { Cache::new(
|CacheEntry(tgt, matcher), cache| {
matcher.match_range_cached(tgt, cache) matcher.match_range_cached(tgt, cache)
} }
)) )
}
pub fn match_range(&self, target: Mrc<[Expr]>) -> Option<State> {
self.match_range_cached(target, &Self::get_matcher_cache())
} }
} }
pub fn verify_scalar_vec(pattern: &Expr, is_vec: &mut HashMap<String, bool>) impl Debug for SliceMatcherDnC {
-> Result<(), String> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let verify_clause = |clause: &Clause, is_vec: &mut HashMap<String, bool>| -> Result<(), String> { f.debug_struct("Matcher")
match clause { .field("clause", &self.clause)
Clause::Placeh(name, prio) => { .field("vectorial", &self.clause_is_vectorial())
if let Some(known) = is_vec.get(name) { .field("min", &self.len())
if known != &prio.is_some() { return Err(name.to_string()) } .field("left", &self.left_subm)
} else { .field("right", &self.right_subm)
is_vec.insert(name.clone(), prio.is_some()); .field("lmin", &self.min(Side::Left))
} .field("rmin", &self.min(Side::Right))
} .finish()
Clause::Auto(name, typ, body) => {
if let Some(key) = name.as_ref().map(|key| key.strip_prefix("$")).flatten() {
if is_vec.get(key) == Some(&true) { return Err(key.to_string()) }
}
typ.iter().try_for_each(|e| verify_scalar_vec(e, is_vec))?;
body.iter().try_for_each(|e| verify_scalar_vec(e, is_vec))?;
}
Clause::Lambda(name, typ, body) => {
if let Some(key) = name.strip_prefix("$") {
if is_vec.get(key) == Some(&true) { return Err(key.to_string()) }
}
typ.iter().try_for_each(|e| verify_scalar_vec(e, is_vec))?;
body.iter().try_for_each(|e| verify_scalar_vec(e, is_vec))?;
}
Clause::S(_, body) => {
body.iter().try_for_each(|e| verify_scalar_vec(e, is_vec))?;
}
_ => ()
};
Ok(())
};
let Expr(val, typ_opt) = pattern;
verify_clause(val, is_vec)?;
if let Some(typ) = typ_opt {
verify_scalar_vec(typ, is_vec)?;
} }
return Ok(())
} }
pub fn execute(mut src: Vec<Expr>, mut tgt: Vec<Expr>, mut input: Vec<Expr>)
-> Result<(Vec<Expr>, bool), RuleError> {
// Static values
let prefix_expr = Expr(Clause::Placeh("::prefix".to_string(), Some(0)), None);
let postfix_expr = Expr(Clause::Placeh("::postfix".to_string(), Some(0)), None);
// Dimension check
let mut is_vec_db = HashMap::new();
src.iter().try_for_each(|e| verify_scalar_vec(e, &mut is_vec_db))
.map_err(RuleError::ScalarVecMismatch)?;
tgt.iter().try_for_each(|e| verify_scalar_vec(e, &mut is_vec_db))
.map_err(RuleError::ScalarVecMismatch)?;
// Prefix or postfix to match the full vector
let head_multi = if let Clause::Placeh(_, Some(_)) = src.first().unwrap().0 {true} else {false};
let tail_multi = if let Clause::Placeh(_, Some(_)) = src.last().unwrap().0 {true} else {false};
if !head_multi {
src.insert(0, prefix_expr.clone());
tgt.insert(0, prefix_expr.clone());
}
if !tail_multi {
src.push(postfix_expr.clone());
tgt.push(postfix_expr.clone());
}
todo!()
}

View File

@@ -0,0 +1,33 @@
use mappable_rc::Mrc;
use itertools::Itertools;
use crate::expression::{Expr, Clause};
use crate::utils::{mrc_derive, mrc_try_derive};
pub type MaxVecSplit = (Mrc<[Expr]>, (Mrc<str>, usize, bool), Mrc<[Expr]>);
/// Derive the details of the central vectorial and the two sides from a slice of Expr's
pub fn split_at_max_vec(pattern: Mrc<[Expr]>) -> Option<MaxVecSplit> {
let rngidx = pattern.iter().position_max_by_key(|ex| {
if let Expr(Clause::Placeh{vec: Some((prio, _)), ..}, _) = ex {
*prio as i64
} else { -1 }
})?;
let left = mrc_derive(&pattern, |p| &p[0..rngidx]);
let placeh = mrc_derive(&pattern, |p| &p[rngidx].0);
let right = if rngidx == pattern.len() {
mrc_derive(&pattern, |x| &x[0..1])
} else {
mrc_derive(&pattern, |x| &x[rngidx + 1..])
};
mrc_try_derive(&placeh, |p| {
if let Clause::Placeh{key, vec: Some(_)} = p {
Some(key)
} else {None} // Repeated below on unchanged data
}).map(|key| {
let key = mrc_derive(&key, String::as_str);
if let Clause::Placeh{vec: Some((prio, nonzero)), ..} = placeh.as_ref() {
(left, (key, *prio, *nonzero), right)
}
else {panic!("Impossible branch")} // Duplicate of above
})
}

View File

@@ -1,21 +1,31 @@
use std::ops::{Add, Index}; use std::{ops::{Add, Index}, rc::Rc, fmt::Debug};
use hashbrown::{HashMap, hash_map::IntoIter}; use hashbrown::HashMap;
use mappable_rc::Mrc;
use crate::expression::Expr; use crate::expression::Expr;
#[derive(Debug, PartialEq, Eq)]
pub enum Entry {
Vec(Rc<Vec<Expr>>),
Scalar(Rc<Expr>),
Name(Rc<String>),
NameOpt(Option<Rc<String>>)
}
/// A bucket of indexed expression fragments. Addition may fail if there's a conflict. /// A bucket of indexed expression fragments. Addition may fail if there's a conflict.
#[derive(PartialEq, Eq)] #[derive(PartialEq, Eq, Clone)]
pub struct State(HashMap<String, Mrc<Vec<Expr>>>); pub struct State(HashMap<String, Entry>);
/// Clone without also cloning arbitrarily heavy Expr objects. /// Clone without also cloning arbitrarily heavy Expr objects.
/// Key is expected to be a very short string with an allocator overhead close to zero. /// Key is expected to be a very short string with an allocator overhead close to zero.
impl Clone for State { impl Clone for Entry {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self(HashMap::from_iter( match self {
self.0.iter().map(|(k, v)| (k.clone(), Mrc::clone(v))) Self::Name(n) => Self::Name(Rc::clone(n)),
)) Self::Scalar(x) => Self::Scalar(Rc::clone(x)),
Self::Vec(v) => Self::Vec(Rc::clone(v)),
Self::NameOpt(o) => Self::NameOpt(o.as_ref().map(Rc::clone))
}
} }
} }
@@ -23,24 +33,65 @@ impl State {
pub fn new() -> Self { pub fn new() -> Self {
Self(HashMap::new()) Self(HashMap::new())
} }
/// Insert a new element, return None on conflict, clone only on success pub fn insert_vec<S>(mut self, k: &S, v: &[Expr]) -> Option<Self>
pub fn insert<S>(mut self, k: &S, v: &[Expr]) -> Option<State> where S: AsRef<str> + ToString + ?Sized + Debug {
eprintln!("{:?} + {k:?}-{v:?}", self.0);
if let Some(old) = self.0.get(k.as_ref()) {
if let Entry::Vec(val) = old {
if val.as_slice() != v {return None}
} else {return None}
} else {
self.0.insert(k.to_string(), Entry::Vec(Rc::new(v.to_vec())));
}
Some(self)
}
pub fn insert_scalar<S>(mut self, k: &S, v: &Expr) -> Option<Self>
where S: AsRef<str> + ToString + ?Sized { where S: AsRef<str> + ToString + ?Sized {
if let Some(old) = self.0.get(k.as_ref()) { if let Some(old) = self.0.get(k.as_ref()) {
if old.as_ref() != v {return None} if let Entry::Scalar(val) = old {
if val.as_ref() != v {return None}
} else {return None}
} else { } else {
self.0.insert(k.to_string(), Mrc::new(v.to_vec())); self.0.insert(k.to_string(), Entry::Scalar(Rc::new(v.to_owned())));
} }
return Some(self) Some(self)
}
pub fn insert_name<S1, S2>(mut self, k: &S1, v: &S2) -> Option<Self>
where
S1: AsRef<str> + ToString + ?Sized,
S2: AsRef<str> + ToString + ?Sized
{
if let Some(old) = self.0.get(k.as_ref()) {
if let Entry::Name(val) = old {
if val.as_str() != v.as_ref() {return None}
} else {return None}
} else {
self.0.insert(k.to_string(), Entry::Name(Rc::new(v.to_string())));
}
Some(self)
}
pub fn insert_name_opt<S1, S2>(mut self, k: &S1, v: Option<&S2>) -> Option<Self>
where
S1: AsRef<str> + ToString + ?Sized,
S2: AsRef<str> + ToString + ?Sized
{
if let Some(old) = self.0.get(k.as_ref()) {
if let Entry::NameOpt(val) = old {
if val.as_ref().map(|s| s.as_ref().as_str()) != v.map(|s| s.as_ref()) {return None}
} else {return None}
} else {
self.0.insert(k.to_string(), Entry::NameOpt(v.map(|s| Rc::new(s.to_string()))));
}
Some(self)
} }
/// Insert a new entry, return None on conflict /// Insert a new entry, return None on conflict
pub fn insert_pair(mut self, (k, v): (String, Mrc<Vec<Expr>>)) -> Option<State> { pub fn insert_pair(mut self, (k, v): (String, Entry)) -> Option<State> {
if let Some(old) = self.0.get(&k) { if let Some(old) = self.0.get(&k) {
if old != &v {return None} if old != &v {return None}
} else { } else {
self.0.insert(k, v); self.0.insert(k, v);
} }
return Some(self) Some(self)
} }
/// Returns `true` if the state contains no data /// Returns `true` if the state contains no data
pub fn empty(&self) -> bool { pub fn empty(&self) -> bool {
@@ -58,7 +109,7 @@ impl Add for State {
for pair in rhs.0 { for pair in rhs.0 {
self = self.insert_pair(pair)? self = self.insert_pair(pair)?
} }
return Some(self); Some(self)
} }
} }
@@ -70,20 +121,20 @@ impl Add<Option<State>> for State {
} }
} }
impl<'a, S> Index<&S> for State where S: AsRef<str> { impl<S> Index<S> for State where S: AsRef<str> {
type Output = Vec<Expr>; type Output = Entry;
fn index(&self, index: &S) -> &Self::Output { fn index(&self, index: S) -> &Self::Output {
return &self.0[index.as_ref()] return &self.0[index.as_ref()]
} }
} }
impl IntoIterator for State { impl IntoIterator for State {
type Item = (String, Mrc<Vec<Expr>>); type Item = (String, Entry);
type IntoIter = IntoIter<String, Mrc<Vec<Expr>>>; type IntoIter = hashbrown::hash_map::IntoIter<String, Entry>;
fn into_iter(self) -> Self::IntoIter { fn into_iter(self) -> Self::IntoIter {
self.0.into_iter() self.0.into_iter()
} }
} }

View File

@@ -1,6 +1,7 @@
// mod rule;
mod executor; mod executor;
mod rule_error; mod rule_error;
mod repository;
// pub use rule::Rule; // pub use rule::Rule;
pub use rule_error::RuleError; pub use rule_error::RuleError;
pub use repository::Repository;

View File

@@ -1,3 +0,0 @@
struct Name {
qualified: Vec<String>
}

45
src/rule/repository.rs Normal file
View File

@@ -0,0 +1,45 @@
use std::fmt::Debug;
use mappable_rc::Mrc;
use crate::expression::Expr;
use super::{super::expression::Rule, executor::execute, RuleError};
pub struct Repository(Vec<Rule>);
impl Repository {
pub fn new(mut rules: Vec<Rule>) -> Self {
rules.sort_by_key(|r| r.prio);
Self(rules)
}
pub fn step(&self, mut code: Mrc<[Expr]>) -> Result<Option<Mrc<[Expr]>>, RuleError> {
let mut ran_once = false;
for rule in self.0.iter() {
if let Some(tmp) = execute(
Mrc::clone(&rule.source), Mrc::clone(&rule.target),
Mrc::clone(&code)
)? {
ran_once = true;
code = tmp;
}
}
Ok(if ran_once {Some(code)} else {None})
}
pub fn long_step(&self, mut code: Mrc<[Expr]>) -> Result<Mrc<[Expr]>, RuleError> {
while let Some(tmp) = self.step(Mrc::clone(&code))? {
code = tmp
}
Ok(code)
}
}
impl Debug for Repository {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
for rule in self.0.iter() {
writeln!(f, "{rule:?}")?
}
Ok(())
}
}

View File

@@ -1,50 +0,0 @@
use std::{cmp::{min, max}, error::Error, fmt, ops::Range};
use hashbrown::HashMap;
use crate::expression::Expr;
use super::BadState;
type State = HashMap<String, Expr>;
pub trait Rule {
type Out: Iterator<Item = Expr>;
/// The minimum and maximum set of symbols this rule may match.
fn len(&self) -> (Option<usize>, Option<usize>);
/// Check if the slice matches, and extract data
fn read(&self, input: &[Expr]) -> Option<State>;
/// Construct item from state
fn write(&self, state: &State) -> Result<Self::Out, BadState>;
/// Placeholders present in this pattern (all consumed must also be provided)
fn placeholders(&'_ self) -> &'_ [&'_ str];
/// Try all subsections of Vec of appropriate size, longest first, front-to-back
/// Match the first, return the position and produced state
fn scan_slice(&self, input: &[Expr]) -> Option<(Range<usize>, State)> {
let len_range = self.len();
let lo = max(len_range.0.unwrap_or(1), 1);
let hi = min(len_range.1.unwrap_or(input.len()), input.len());
for width in (lo..hi).rev() {
let starts = (0..input.len() - width).into_iter();
let first_match = starts.filter_map(|start| {
let res = self.read(&input[start..start+width])?;
Some((start..start+width, res))
}).next();
if first_match.is_some() {
return first_match;
}
}
None
}
}
pub fn verify<Src, Tgt>(src: &Src, tgt: &Tgt) -> Option<Vec<String>> where Src: Rule, Tgt: Rule {
let mut amiss: Vec<String> = Vec::new();
for ent in tgt.placeholders() {
if src.placeholders().iter().find(|x| x == &ent).is_none() {
amiss.push(ent.to_string())
}
}
if amiss.len() > 0 { Some(amiss) }
else { None }
}

View File

@@ -1,37 +1,60 @@
use std::{hash::Hash, cell::RefCell}; use std::{hash::Hash, cell::RefCell, rc::Rc};
use hashbrown::HashMap; use hashbrown::HashMap;
use mappable_rc::Mrc; use mappable_rc::Mrc;
/// Convenience trait for overriding Mrc's strange cloning logic
pub trait MyClone {
fn my_clone(&self) -> Self;
}
impl<T> MyClone for T where T: Clone {
default fn my_clone(&self) -> Self { self.clone() }
}
impl<T: ?Sized> MyClone for Rc<T> {
fn my_clone(&self) -> Self { Rc::clone(self) }
}
impl<T: ?Sized> MyClone for Mrc<T> {
fn my_clone(&self) -> Self { Mrc::clone(self) }
}
/// Cache the return values of an effectless closure in a hashmap /// Cache the return values of an effectless closure in a hashmap
/// Inspired by the closure_cacher crate. /// Inspired by the closure_cacher crate.
pub struct Cache<'a, I, O: 'static> /*where O: Clone*/ { pub struct Cache<'a, I, O: 'static> {
store: RefCell<HashMap<I, Mrc<O>>>, store: RefCell<HashMap<I, Mrc<O>>>,
closure: RefCell<Box<dyn FnMut (I, &Self) -> Mrc<O> + 'a>> closure: Box<dyn Fn (I, &Self) -> Mrc<O> + 'a>
} }
impl<'a, I, O> Cache<'a, I, O> where impl<'a, I, O> Cache<'a, I, O> where
I: Eq + Hash + Clone I: Eq + Hash + MyClone
{ {
pub fn new<F: 'a>(mut closure: F) -> Self where F: FnMut(I, &Self) -> O { pub fn new<F: 'a>(closure: F) -> Self where F: Fn(I, &Self) -> O {
Self::new_raw(move |o, s| Mrc::new(closure(o, s))) Self::new_raw(move |o, s| Mrc::new(closure(o, s)))
} }
/// Take an Mrc<O> closure rather than an O closure /// Take an Mrc<O> closure rather than an O closure
/// Used internally to derive caches from other systems working with Mrc-s /// Used internally to derive caches from other systems working with Mrc-s
pub fn new_raw<F: 'a>(closure: F) -> Self where F: FnMut(I, &Self) -> Mrc<O> { pub fn new_raw<F: 'a>(closure: F) -> Self where F: Fn(I, &Self) -> Mrc<O> {
Self { Self {
store: RefCell::new(HashMap::new()), store: RefCell::new(HashMap::new()),
closure: RefCell::new(Box::new(closure)) closure: Box::new(closure)
} }
} }
/// Produce and cache a result by cloning I if necessary /// Produce and cache a result by cloning I if necessary
pub fn find(&self, i: &I) -> Mrc<O> { pub fn find(&self, i: &I) -> Mrc<O> {
let mut closure = self.closure.borrow_mut(); let closure = &self.closure;
if let Some(v) = self.store.borrow().get(i) {
return Mrc::clone(v)
}
// In the moment of invocation the refcell is on immutable
// this is important for recursive calculations
let result = closure(i.my_clone(), self);
let mut store = self.store.borrow_mut(); let mut store = self.store.borrow_mut();
Mrc::clone(store.raw_entry_mut().from_key(i) Mrc::clone(store.raw_entry_mut().from_key(i)
.or_insert_with(|| (i.clone(), closure(i.clone(), self))).1) .or_insert_with(|| (i.my_clone(), result)).1)
} }
#[allow(dead_code)] #[allow(dead_code)]
/// Return the result if it has already been computed /// Return the result if it has already been computed
pub fn known(&self, i: &I) -> Option<Mrc<O>> { pub fn known(&self, i: &I) -> Option<Mrc<O>> {
@@ -46,7 +69,7 @@ impl<'a, I, O> Cache<'a, I, O> where
} }
impl<'a, I, O, E> Cache<'a, I, Result<O, E>> where impl<'a, I, O, E> Cache<'a, I, Result<O, E>> where
I: Eq + Hash + Clone, I: Eq + Hash + MyClone,
// O: Clone, // O: Clone,
E: Clone E: Clone
{ {
@@ -60,7 +83,7 @@ impl<'a, I, O, E> Cache<'a, I, Result<O, E>> where
} }
impl<'a, I, O> Cache<'a, I, Option<O>> where impl<'a, I, O> Cache<'a, I, Option<O>> where
I: Eq + Hash + Clone, I: Eq + Hash + MyClone,
// O: Clone // O: Clone
{ {
#[allow(dead_code)] #[allow(dead_code)]
@@ -70,4 +93,4 @@ impl<'a, I, O> Cache<'a, I, Option<O>> where
let ent = self.find(i); let ent = self.find(i);
Mrc::try_map(ent, |o| o.as_ref()).ok() Mrc::try_map(ent, |o| o.as_ref()).ok()
} }
} }

36
src/utils/iter.rs Normal file
View File

@@ -0,0 +1,36 @@
/// Utility functions to get rid of explicit casts to BoxedIter which are tedious
use std::iter;
pub type BoxedIter<'a, T> = Box<dyn Iterator<Item = T> + 'a>;
pub type BoxedIterIter<'a, T> = BoxedIter<'a, BoxedIter<'a, T>>;
/// BoxedIter of a single element
pub fn box_once<'a, T: 'a>(t: T) -> BoxedIter<'a, T> {
Box::new(iter::once(t))
}
/// BoxedIter of no elements
pub fn box_empty<'a, T: 'a>() -> BoxedIter<'a, T> {
Box::new(iter::empty())
}
#[macro_export]
macro_rules! box_chain {
($curr:expr) => {
Box::new($curr) as BoxedIter<_>
};
($curr:expr, $($rest:expr),*) => {
Box::new($curr$(.chain($rest))*) as $crate::utils::iter::BoxedIter<_>
};
}
pub fn box_flatten<'a, T: 'a, I: 'a, J: 'a>(i: I) -> BoxedIter<'a, T>
where
J: Iterator<Item = T>,
I: Iterator<Item = J>,
{
Box::new(i.flatten())
}
pub fn into_boxed_iter<'a, T: 'a>(t: T) -> BoxedIter<'a, <T as IntoIterator>::Item>
where T: IntoIterator {
Box::new(t.into_iter())
}

View File

@@ -2,11 +2,33 @@ mod cache;
mod substack; mod substack;
mod side; mod side;
mod merge_sorted; mod merge_sorted;
mod sorted_pairs;
mod unwrap_or_continue; mod unwrap_or_continue;
pub mod iter;
pub use cache::Cache; pub use cache::Cache;
use mappable_rc::Mrc;
pub use substack::Stackframe; pub use substack::Stackframe;
pub use side::Side; pub use side::Side;
pub use merge_sorted::merge_sorted; pub use merge_sorted::merge_sorted;
pub use iter::BoxedIter;
pub type BoxedIter<'a, T> = Box<dyn Iterator<Item = T> + 'a>; pub fn mrc_derive<T: ?Sized, P, U: ?Sized>(m: &Mrc<T>, p: P) -> Mrc<U>
where P: for<'a> FnOnce(&'a T) -> &'a U {
Mrc::map(Mrc::clone(m), p)
}
pub fn mrc_try_derive<T: ?Sized, P, U: ?Sized>(m: &Mrc<T>, p: P) -> Option<Mrc<U>>
where P: for<'a> FnOnce(&'a T) -> Option<&'a U> {
Mrc::try_map(Mrc::clone(m), p).ok()
}
pub fn to_mrc_slice<T>(v: Vec<T>) -> Mrc<[T]> {
Mrc::map(Mrc::new(v), |v| v.as_slice())
}
pub fn collect_to_mrc<I>(iter: I) -> Mrc<[I::Item]> where I: Iterator {
to_mrc_slice(iter.collect())
}
pub fn mrc_derive_slice<T>(mv: &Mrc<Vec<T>>) -> Mrc<[T]> {
mrc_derive(mv, |v| v.as_slice())
}

View File

@@ -1,35 +0,0 @@
use std::ops::Add;
/// Combine two sorted iterators with their mapper function into a sorted iterator of pairs
pub struct SortedPairs<L, R, IL, IR, ML, MR, O> {
left: IL, right: IR,
left_map: ML, right_map: MR,
left_buf: Vec<(L, O)>, right_buf: Vec<(R, O)>
}
impl<L, R, IL, IR, ML, MR, O> SortedPairs<L, R, IL, IR, ML, MR, O>
where IL: Iterator<Item = L>, IR: Iterator<Item = R>,
ML: Fn(L) -> O, MR: Fn(R) -> O,
O: Ord + Add + Clone
{
pub fn new(left: IL, right: IR, left_map: ML, right_map: MR) -> Self {
Self {
left, right, left_map, right_map,
left_buf: Vec::new(),
right_buf: Vec::new()
}
}
}
impl<'a, L: 'a, R: 'a, IL: 'a, IR: 'a, ML: 'a, MR: 'a, O: 'a> Iterator
for &'a mut SortedPairs<L, R, IL, IR, ML, MR, O>
where IL: Iterator<Item = L>, IR: Iterator<Item = R>,
ML: Fn(L) -> O, MR: Fn(R) -> O,
O: Ord + Add + Clone,
{
type Item = (&'a L, &'a R);
fn next(&mut self) -> Option<Self::Item> {
todo!()
}
}