Compare commits

...

5 Commits

16 changed files with 586 additions and 153 deletions

4
.gitmodules vendored Normal file
View File

@ -0,0 +1,4 @@
[submodule "winnow"]
path = winnow
url = git@github.com:supersurviveur/winnow.git
branch = operator-in-expression

2
Cargo.lock generated
View File

@ -323,8 +323,6 @@ dependencies = [
[[package]]
name = "winnow"
version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
dependencies = [
"memchr",
]

View File

@ -7,6 +7,6 @@ edition = "2024"
bimap = "0.6.3"
env_logger = "0.11.8"
log = "0.4.29"
winnow = { version = "0.7.14", path = "./winnow" }
lru = "0.16.3"
owo-colors = "4.2.3"
winnow = "0.7.14"

103
doz/src/constraint.rs Normal file
View File

@ -0,0 +1,103 @@
pub mod resolution;
use std::collections::{HashMap, VecDeque};
use crate::domain::{Domain, DomainRange};
pub struct Indexical
{
pub variable: usize,
pub dependencies: Vec<usize>,
#[allow(clippy::type_complexity)]
pub propagator: Box<dyn Fn(&[DomainRange]) -> DomainRange>,
}
impl Indexical
{
pub fn new<T>(variable: usize, dependencies: &[usize], propagator: T) -> Indexical
where
T: Fn(&[DomainRange]) -> DomainRange + 'static,
{
Indexical {
variable,
dependencies: dependencies.to_vec(),
propagator: Box::new(propagator),
}
}
}
pub struct ClpContext
{
pub variables: usize,
pub domains: HashMap<usize, Domain>,
pub used_by: HashMap<usize, Vec<usize>>,
pub constraints: HashMap<usize, Vec<Indexical>>,
}
impl ClpContext
{
pub fn new() -> Self
{
ClpContext {
variables: 0,
domains: HashMap::new(),
used_by: HashMap::new(),
constraints: HashMap::new(),
}
}
pub fn get_var(&mut self) -> usize
{
let k = self.variables;
self.variables += 1;
self.domains.insert(k, Domain::from(..));
self.used_by.insert(k, vec![]);
k
}
pub fn insert_constraint(&mut self, indexical: Indexical)
{
let vec = self.constraints.entry(indexical.variable).or_insert(vec![]);
for x in indexical.dependencies.iter()
{
self.used_by.get_mut(x).unwrap().push(indexical.variable);
}
vec.push(indexical);
}
pub fn prune(&mut self) -> bool
{
let mut queue = VecDeque::from_iter(0..self.variables);
while !queue.is_empty()
{
// Apply unary constraints
let var = queue.pop_front().unwrap();
let constraints = self.constraints.get(&var);
if constraints.is_none()
{
continue;
}
let constraints = constraints.unwrap();
for c in constraints.iter()
{
if c.dependencies.is_empty()
{
// Is unary constraint
let domain = self.domains.get(&var).unwrap();
}
}
}
todo!();
}
}
impl Default for ClpContext
{
fn default() -> Self
{
Self::new()
}
}

View File

View File

@ -1,9 +1,10 @@
pub mod simple_range;
pub mod union;
pub mod domain_ops;
pub mod range_ops;
use std::fmt::Display;
use std::ops::Range;
use std::ops::RangeFrom;
use std::ops::RangeFull;
use std::ops::RangeTo;
pub struct Domain
@ -15,16 +16,6 @@ pub struct Domain
/// $$\{x \in [\text{start}; \text{end}[ | x \equiv \text{congruent} \text{mod} \text{modulo}}$$
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct DomainRange
{
pub start: LowerBound,
pub end: HigherBound,
pub modulo: u64,
pub congruent: i64,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct SimpleRange
{
pub start: LowerBound,
pub end: HigherBound,
@ -70,23 +61,6 @@ impl DomainRange
DomainRange {
start: from,
end: to,
modulo: 1,
congruent: 0,
}
}
pub fn is_simple(&self) -> Option<SimpleRange>
{
if self.modulo <= 1
{
Some(SimpleRange {
start: self.start,
end: self.end,
})
}
else
{
None
}
}
}
@ -101,6 +75,16 @@ impl From<Range<i64>> for Domain
}
}
impl From<RangeFull> for Domain
{
fn from(value: RangeFull) -> Self
{
Domain {
ranges: vec![value.into()],
}
}
}
impl From<RangeTo<i64>> for Domain
{
fn from(value: RangeTo<i64>) -> Self
@ -148,6 +132,14 @@ impl From<RangeFrom<i64>> for DomainRange
}
}
impl From<RangeFull> for DomainRange
{
fn from(_: RangeFull) -> Self
{
DomainRange::range(LowerBound::Infinity, HigherBound::Infinity)
}
}
impl Display for LowerBound
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
@ -176,12 +168,7 @@ impl Display for DomainRange
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
write!(f, "{}..{}", self.start, self.end)?;
if self.modulo > 1
{
write!(f, " ≡ {} [{}]", self.congruent, self.modulo)?;
}
Ok(())
write!(f, "{}..{}", self.start, self.end)
}
}

View File

@ -0,0 +1,90 @@
use crate::domain::{Domain, DomainRange};
impl Domain
{
pub fn intersection(&self, domain: &Domain) -> Domain
{
let mut i = 0;
let mut j = 0;
let mut stack = vec![];
while i < self.ranges.len() || j < domain.ranges.len()
{
if i < self.ranges.len() && j < domain.ranges.len()
{
let a = self.ranges[i];
let b = domain.ranges[j];
if a.disjoint(&b)
{
if a.start < b.start
{
i += 1;
}
else
{
j += 1;
}
}
else
{
let inter = a.intersection(&b);
if let Some(range) = inter
{
stack.push(range);
};
if a.end > b.end
{
i += 1;
}
else
{
j += 1;
}
}
}
else
{
break;
}
}
Domain { ranges: stack }
}
pub fn union(&self, domain: &Domain) -> Domain
{
let mut stack = self
.ranges
.iter()
.copied()
.chain(domain.ranges.iter().copied())
.collect::<Vec<DomainRange>>();
stack.sort_by(|a, b| b.start.cmp(&a.start));
let mut ranges = vec![];
while !stack.is_empty()
{
if stack.len() >= 2
{
let (a, b) = (stack.pop().unwrap(), stack.pop().unwrap());
match a.union(&b)
{
crate::domain::UnionResult::Single(x) => stack.push(x),
crate::domain::UnionResult::Union(x, y) =>
{
ranges.push(x);
stack.push(y);
}
}
}
else if stack.len() == 1
{
ranges.push(stack.pop().unwrap());
}
}
Domain { ranges }
}
}

View File

@ -1,54 +1,51 @@
use std::ops::Range;
use std::ops::RangeFrom;
use std::ops::RangeFull;
use std::ops::RangeTo;
// Module for computing intersection of domains
use crate::domain::DomainRange;
use crate::domain::HigherBound;
use crate::domain::LowerBound;
use crate::domain::SimpleRange;
use crate::domain::UnionResult;
impl SimpleRange
impl DomainRange
{
pub fn union(&self, range: &SimpleRange) -> UnionResult<SimpleRange>
pub fn union(&self, range: &DomainRange) -> UnionResult<DomainRange>
{
let (a, b) = (self.min_by_start(range), self.max_by_start(range));
match (a.end, b.start)
{
(HigherBound::Infinity, LowerBound::Infinity) =>
{
UnionResult::Single(SimpleRange::from(..))
UnionResult::Single(DomainRange::from(..))
}
(HigherBound::Infinity, LowerBound::Bounded(_)) => UnionResult::Single(SimpleRange {
(HigherBound::Infinity, LowerBound::Bounded(_)) => UnionResult::Single(DomainRange {
start: a.start,
end: HigherBound::Infinity,
}),
(HigherBound::Bounded(_), LowerBound::Infinity) => UnionResult::Single(SimpleRange {
(HigherBound::Bounded(_), LowerBound::Infinity) => UnionResult::Single(DomainRange {
start: LowerBound::Infinity,
end: b.end,
}),
(HigherBound::Bounded(c), LowerBound::Bounded(d)) if c < d => UnionResult::Union(a, b),
(HigherBound::Bounded(_), LowerBound::Bounded(_)) => UnionResult::Single(SimpleRange {
(HigherBound::Bounded(_), LowerBound::Bounded(_)) => UnionResult::Single(DomainRange {
start: a.start,
end: b.end,
}),
}
}
pub fn intersection(&self, range: &SimpleRange) -> Option<SimpleRange>
pub fn intersection(&self, range: &DomainRange) -> Option<DomainRange>
{
let (a, b) = (self.min_by_start(range), self.max_by_start(range));
match (a.end, b.start)
{
(HigherBound::Infinity, LowerBound::Infinity) => Some(SimpleRange::from(..)),
(HigherBound::Infinity, LowerBound::Bounded(a)) => Some(SimpleRange::from(a..)),
(HigherBound::Bounded(a), LowerBound::Infinity) => Some(SimpleRange::from(..a)),
(HigherBound::Infinity, LowerBound::Infinity) => Some(DomainRange::from(..)),
(HigherBound::Infinity, LowerBound::Bounded(a)) => Some(DomainRange::from(a..)),
(HigherBound::Bounded(a), LowerBound::Infinity) => Some(DomainRange::from(..a)),
(HigherBound::Bounded(a), LowerBound::Bounded(b)) if a <= b => None,
(HigherBound::Bounded(a), LowerBound::Bounded(b)) => Some(SimpleRange::from(a..b)),
(HigherBound::Bounded(a), LowerBound::Bounded(b)) => Some(DomainRange::from(a..b)),
}
}
pub fn without(&self, range: &SimpleRange) -> SimpleRange
pub fn without(&self, range: &DomainRange) -> DomainRange
{
match self.intersection(range)
{
@ -61,7 +58,7 @@ impl SimpleRange
}
}
pub fn symetrical_difference(&self, range: &SimpleRange) -> Option<UnionResult<SimpleRange>>
pub fn symetrical_difference(&self, range: &DomainRange) -> Option<UnionResult<DomainRange>>
{
match self.intersection(range)
{
@ -73,7 +70,25 @@ impl SimpleRange
}
}
pub fn min_by_start(&self, range: &SimpleRange) -> SimpleRange
pub fn disjoint(&self, range: &DomainRange) -> bool
{
self.intersection(range).is_none()
}
pub fn included_in(&self, range: &DomainRange) -> bool
{
if let UnionResult::Single(x) = self.union(range)
&& x == *range
{
true
}
else
{
false
}
}
pub fn min_by_start(&self, range: &DomainRange) -> DomainRange
{
if self.start < range.start
{
@ -85,7 +100,7 @@ impl SimpleRange
}
}
pub fn max_by_start(&self, range: &SimpleRange) -> SimpleRange
pub fn max_by_start(&self, range: &DomainRange) -> DomainRange
{
if self.start < range.start
{
@ -97,57 +112,13 @@ impl SimpleRange
}
}
pub fn min_by_end(&self, range: &SimpleRange) -> SimpleRange
pub fn min_by_end(&self, range: &DomainRange) -> DomainRange
{
if self.end < range.end { *self } else { *range }
}
pub fn max_by_end(&self, range: &SimpleRange) -> SimpleRange
pub fn max_by_end(&self, range: &DomainRange) -> DomainRange
{
if self.end < range.end { *range } else { *self }
}
}
impl From<Range<i64>> for SimpleRange
{
fn from(value: Range<i64>) -> Self
{
SimpleRange {
start: LowerBound::Bounded(value.start),
end: HigherBound::Bounded(value.end),
}
}
}
impl From<RangeTo<i64>> for SimpleRange
{
fn from(value: RangeTo<i64>) -> Self
{
SimpleRange {
start: LowerBound::Infinity,
end: HigherBound::Bounded(value.end),
}
}
}
impl From<RangeFrom<i64>> for SimpleRange
{
fn from(value: RangeFrom<i64>) -> Self
{
SimpleRange {
start: LowerBound::Bounded(value.start),
end: HigherBound::Infinity,
}
}
}
impl From<RangeFull> for SimpleRange
{
fn from(_: RangeFull) -> Self
{
SimpleRange {
start: LowerBound::Infinity,
end: HigherBound::Infinity,
}
}
}

View File

@ -1,16 +0,0 @@
// Module for computing intersection of domains
use crate::domain::Domain;
use crate::domain::DomainRange;
impl DomainRange
{
pub fn union(&self, domain: &DomainRange) -> Domain
{
if let Some(simple_a) = self.is_simple()
&& let Some(simple_b) = self.is_simple()
{
simple_a.union(&simple_b)
}
}
}

View File

@ -1 +1,2 @@
pub mod constraint;
pub mod domain;

View File

@ -1,5 +1,7 @@
use doz::constraint::Indexical;
use doz::domain::Domain;
use doz::domain::DomainRange;
use doz::indexical;
fn main()
{
@ -7,10 +9,13 @@ fn main()
ranges: vec![DomainRange {
start: doz::domain::LowerBound::Infinity,
end: doz::domain::HigherBound::Infinity,
modulo: 2,
congruent: 0,
}],
};
//let k = Indexical::new([Box::new(|a, b, c| a), Box::new(|a, b, c| b)]);
//
let k = indexical![|[a, _b]| { a }, |[_a, b]| { b }];
println!("{}", even);
}

View File

@ -30,7 +30,43 @@ pub enum Body
pub enum Predicate
{
Variable(Variable), // Upercase variable like X
Fixed(String, Vec<Predicate>),
Fixed(Functor, Vec<Predicate>),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum Functor
{
Operator(Operator),
Functor(String),
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct Operator
{
pub op: String,
pub precedence: usize,
pub op_type: OperatorType,
}
impl Operator
{
pub fn new(op: String, precedence: usize, op_type: OperatorType) -> Self
{
Self {
op,
precedence,
op_type,
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub enum OperatorType
{
Prefix,
Postfix,
LeftInfix,
RightInfix,
}
impl Display for Body
@ -126,3 +162,22 @@ impl Display for Module
Ok(())
}
}
impl Display for Functor
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
match self
{
Functor::Operator(op) => write!(f, "{}", op),
Functor::Functor(name) => write!(f, "{}", name),
}
}
}
impl Display for Operator
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
write!(f, "{}", self.op)
}
}

View File

@ -17,9 +17,24 @@ fn main()
mult(zero, X, zero).
mult(s(Y), X, Z) :- mult(Y, X, W), add(W, X, Z).
op(10, yfx, +).
op(8, yfx, ^).
op(6, xfy, ::).
op(2, fx, [).
op(2, xf, ]).
op(3, yfx, |).
A + B :- test.
A ^ B + C :- test.
A::B::C :- A.
[Hd|Tl] :- Hd::Tl.
"
.into();
// println!("{}", module);
// let prop: Body = "mult(X, s(s(s(zero))), s(s(s(s(s(s(s(s(s(zero))))))))))".into();
//let prop: Body = "integer(s(X))".into();
let prop: Body = "mult(X, s(s(zero)), s(s(s(s(zero)))))".into();
//let prop: Body = "mult(X, Y, Z)".into();

View File

@ -1,25 +1,205 @@
use std::path::Path;
use std::{collections::HashMap, path::Path};
use winnow::Parser;
use winnow::Result;
use winnow::ascii::alphanumeric0;
use winnow::ascii::multispace0;
use winnow::combinator::alt;
use winnow::combinator::delimited;
use winnow::combinator::opt;
use winnow::combinator::separated;
use winnow::combinator::seq;
use winnow::error::ContextError;
use winnow::{
ascii::{self, alphanumeric1, multispace0},
combinator::{
alt, delimited, expression, opt, preceded, repeat, separated, seq, terminated, Infix,
Postfix, Prefix,
},
error::ContextError,
Parser, Result, Stateful,
};
use crate::ast::Body;
use crate::ast::Clause;
use crate::ast::Functor;
use crate::ast::Module;
use crate::ast::Operator;
use crate::ast::Predicate;
use crate::ast::{Body, OperatorType};
use crate::ast::Variable;
pub fn predicate_parse(input: &mut &str) -> Result<Predicate>
impl Operator
{
let ident = alphanumeric0.parse_next(input)?;
pub fn get_precedence(&self) -> usize
{
self.precedence
}
pub fn make_infix_operator<'a>(self) -> Infix<Stream<'a>, Predicate, Operator, ContextError>
{
fn make_predicate(
_: &mut Stream,
a: Predicate,
op: Operator,
b: Predicate,
) -> Result<Predicate>
{
Ok(Predicate::Fixed(Functor::Operator(op), vec![a, b]))
}
let precedence = self.get_precedence() as i64;
match self.op_type
{
OperatorType::LeftInfix => Infix::Left(precedence, self, make_predicate),
OperatorType::RightInfix => Infix::Right(precedence, self, make_predicate),
_ => unreachable!(),
}
}
}
impl Operator
{
fn infix(value: String, state: &State) -> Result<Self>
{
state
.custom_operators
.get(&(value.clone(), OperatorType::RightInfix))
.or_else(|| {
state
.custom_operators
.get(&(value, OperatorType::LeftInfix))
})
.ok_or(ContextError::new())
.cloned()
}
fn prefix(value: String, state: &State) -> Result<Self>
{
state
.custom_operators
.get(&(value, OperatorType::Prefix))
.ok_or(ContextError::new())
.cloned()
}
fn postfix(value: String, state: &State) -> Result<Self>
{
state
.custom_operators
.get(&(value, OperatorType::Postfix))
.ok_or(ContextError::new())
.cloned()
}
}
const OPERATORS: [&str; 9] = [":", "-", "+", "|", "/", "*", "[", "]", "^"];
#[derive(Debug)]
pub struct State
{
custom_operators: HashMap<(String, OperatorType), Operator>,
}
impl Default for State
{
fn default() -> Self
{
Self::new()
}
}
impl State
{
pub fn new() -> Self
{
Self {
custom_operators: HashMap::new(),
}
}
}
type Stream<'is> = Stateful<&'is str, State>;
pub fn operator_parse(input: &mut Stream) -> Result<String>
{
delimited(multispace0, repeat(1.., alt(OPERATORS)), multispace0)
.map(|op: String| Ok(op))
.parse_next(input)?
}
pub fn operator_parse_infix(input: &mut Stream) -> Result<Operator>
{
operator_parse(input).map(|op| Operator::infix(op, &input.state))?
}
pub fn operator_parse_postfix(input: &mut Stream) -> Result<Operator>
{
operator_parse(input).map(|op| Operator::postfix(op, &input.state))?
}
pub fn operator_parse_prefix(input: &mut Stream) -> Result<Operator>
{
operator_parse(input).map(|op| Operator::prefix(op, &input.state))?
}
pub fn operator_definition_parse(input: &mut Stream) -> Result<()>
{
let (precedence, op_type, op) = preceded(
"op",
delimited(
("(", multispace0),
seq! {
ascii::dec_uint,
_: (multispace0, ",", multispace0),
alt(("xfx", "xfy", "yfx", "xf", "yf", "fy", "fx")),
_: (multispace0, ",", multispace0),
operator_parse,
},
(multispace0, ")", multispace0, "."),
),
)
.parse_next(input)?;
let op_type = match op_type
{
"xf" | "yf" => OperatorType::Postfix,
"fx" | "fy" => OperatorType::Prefix,
"xfx" => unimplemented!(),
"yfx" => OperatorType::LeftInfix,
"xfy" => OperatorType::RightInfix,
_ => unreachable!(),
};
input.state.custom_operators.insert(
(op.clone(), op_type.clone()),
Operator::new(op, precedence, op_type),
);
Ok(())
}
pub fn predicate_parse_infix_expression<'a>(
input: &mut Stream<'a>,
) -> Result<Infix<Stream<'a>, Predicate, Operator, ContextError>>
{
let op = operator_parse_infix.parse_next(input)?;
Ok(op.make_infix_operator())
}
pub fn predicate_parse_prefix_expression<'a>(
input: &mut Stream<'a>,
) -> Result<Prefix<Stream<'a>, Predicate, Operator, ContextError>>
{
let op = operator_parse_prefix.parse_next(input)?;
let precedence = op.get_precedence() as i64;
Ok(Prefix(precedence, op, |_, op, a| {
Ok(Predicate::Fixed(Functor::Operator(op), vec![a]))
}))
}
pub fn predicate_parse_postfix_expression<'a>(
input: &mut Stream<'a>,
) -> Result<Postfix<Stream<'a>, Predicate, Operator, ContextError>>
{
let op = operator_parse_postfix.parse_next(input)?;
let precedence = op.get_precedence() as i64;
Ok(Postfix(precedence, op, |_, a, op| {
Ok(Predicate::Fixed(Functor::Operator(op), vec![a]))
}))
}
pub fn predicate_parse_expression(input: &mut Stream) -> Result<Predicate>
{
expression(predicate_parse_recursive)
.infix(predicate_parse_infix_expression)
.postfix(predicate_parse_postfix_expression)
.prefix(predicate_parse_prefix_expression)
.parse_next(input)
}
pub fn predicate_parse_variable_or_functor(input: &mut Stream) -> Result<Predicate>
{
let ident = alphanumeric1.parse_next(input)?;
// Check if output is a variable
if ident.chars().next().is_some_and(|char| char.is_uppercase())
@ -35,11 +215,28 @@ pub fn predicate_parse(input: &mut &str) -> Result<Predicate>
)
.parse_next(input)
.unwrap_or(Vec::new());
Ok(Predicate::Fixed(String::from(ident), arguments))
Ok(Predicate::Fixed(
Functor::Functor(String::from(ident)),
arguments,
))
}
}
fn body_parse_or(input: &mut &str) -> Result<Body>
pub fn predicate_parse_recursive(input: &mut Stream) -> Result<Predicate>
{
alt((
delimited("(", predicate_parse, ")"),
predicate_parse_variable_or_functor,
))
.parse_next(input)
}
pub fn predicate_parse(input: &mut Stream) -> Result<Predicate>
{
alt((predicate_parse_expression, predicate_parse_recursive)).parse_next(input)
}
fn body_parse_or(input: &mut Stream) -> Result<Body>
{
separated(
1..,
@ -53,7 +250,7 @@ fn body_parse_or(input: &mut &str) -> Result<Body>
.parse_next(input)
}
pub fn body_parse(input: &mut &str) -> Result<Body>
pub fn body_parse(input: &mut Stream) -> Result<Body>
{
// Parse and
separated(1.., body_parse_or, (multispace0, ",", multispace0))
@ -61,7 +258,7 @@ pub fn body_parse(input: &mut &str) -> Result<Body>
.parse_next(input)
}
pub fn clause_parse(input: &mut &str) -> Result<Clause>
pub fn clause_parse(input: &mut Stream) -> Result<Clause>
{
seq! {
Clause
@ -75,12 +272,19 @@ pub fn clause_parse(input: &mut &str) -> Result<Clause>
.parse_next(input)
}
pub fn module_parse(input: &mut &str) -> Result<Module>
pub fn module_parse(input: &mut Stream) -> Result<Module>
{
let _: Result<&str, ContextError> = multispace0.parse_next(input);
separated(0.., clause_parse, multispace0)
.map(|clauses| Module { clauses })
.parse_next(input)
separated(
0..,
preceded::<_, (), _, _, _, _>(
repeat(0.., terminated(operator_definition_parse, multispace0)),
clause_parse,
),
multispace0,
)
.map(|clauses| Module { clauses })
.parse_next(input)
}
impl<T> From<T> for Module
@ -89,8 +293,13 @@ where
{
fn from(value: T) -> Self
{
let mut str: &str = value.as_ref();
module_parse.parse_next(&mut str).unwrap()
let str: &str = value.as_ref();
module_parse
.parse_next(&mut Stream {
input: str,
state: State::new(),
})
.unwrap()
}
}
@ -108,8 +317,13 @@ where
{
fn from(value: T) -> Self
{
let mut str: &str = value.as_ref();
predicate_parse.parse_next(&mut str).unwrap()
let str: &str = value.as_ref();
predicate_parse
.parse_next(&mut Stream {
input: str,
state: State::new(),
})
.unwrap()
}
}
@ -119,7 +333,12 @@ where
{
fn from(value: T) -> Self
{
let mut str: &str = value.as_ref();
body_parse.parse_next(&mut str).unwrap()
let str: &str = value.as_ref();
body_parse
.parse_next(&mut Stream {
input: str,
state: State::new(),
})
.unwrap()
}
}

View File

@ -1,8 +1,8 @@
use log::info;
use owo_colors::OwoColorize;
use owo_colors::Style;
use owo_colors::colors::css::DarkGray;
use owo_colors::colors::css::Gray;
use owo_colors::OwoColorize;
use owo_colors::Style;
use std::fmt::Display;
#[derive(Clone, Copy)]

1
winnow Submodule

Submodule winnow added at cc0438a28f