Use custom operators

This commit is contained in:
2026-02-10 22:18:51 +01:00
parent 21414f75db
commit c82384764c
3 changed files with 72 additions and 63 deletions

View File

@ -38,12 +38,23 @@ pub enum Functor
}
#[derive(Clone, Debug, PartialEq)]
pub enum Operator
pub struct Operator
{
Plus,
Minus,
Cons,
Custom(String, usize, OperatorType),
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)]
@ -51,7 +62,8 @@ pub enum OperatorType
{
Prefix,
Postfix,
Infix,
LeftInfix,
RightInfix,
}
impl Display for Body
@ -150,12 +162,6 @@ impl Display for Operator
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result
{
match self
{
Operator::Plus => write!(f, "+"),
Operator::Minus => write!(f, "-"),
Operator::Cons => write!(f, "::"),
Operator::Custom(string, _, _) => write!(f, "{}", string),
}
write!(f, "{}", self.op)
}
}

View File

@ -18,12 +18,17 @@ 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.
op(8, xfx, ^).
A ^ B + C :- test.
(A::B)::C :- A.
A::B::C :- A.
[Hd|Tl] :- Hd::Tl.
"
.into();

View File

@ -21,11 +21,25 @@ impl Operator
{
pub fn get_precedence(&self) -> usize
{
match self
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>
{
Operator::Plus | Operator::Minus => 10,
Operator::Cons => 12,
Operator::Custom(_, precedence, _) => *precedence,
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!(),
}
}
}
@ -34,38 +48,32 @@ impl Operator
{
fn infix(value: String, state: &State) -> Result<Self>
{
match value.as_str()
{
"+" => Ok(Operator::Plus),
"::" => Ok(Operator::Cons),
_ => state
.custom_operators
.get(&(value, OperatorType::Infix))
.ok_or(ContextError::new())
.cloned(),
}
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>
{
match value.as_str()
{
_ => state
.custom_operators
.get(&(value, OperatorType::Prefix))
.ok_or(ContextError::new())
.cloned(),
}
state
.custom_operators
.get(&(value, OperatorType::Prefix))
.ok_or(ContextError::new())
.cloned()
}
fn postfix(value: String, state: &State) -> Result<Self>
{
match value.as_str()
{
_ => state
.custom_operators
.get(&(value, OperatorType::Postfix))
.ok_or(ContextError::new())
.cloned(),
}
state
.custom_operators
.get(&(value, OperatorType::Postfix))
.ok_or(ContextError::new())
.cloned()
}
}
@ -138,12 +146,14 @@ pub fn operator_definition_parse(input: &mut Stream) -> Result<()>
{
"xf" | "yf" => OperatorType::Postfix,
"fx" | "fy" => OperatorType::Prefix,
"xfx" | "xfy" | "yfx" => OperatorType::Infix,
"xfx" => unimplemented!(),
"yfx" => OperatorType::LeftInfix,
"xfy" => OperatorType::RightInfix,
_ => unreachable!(),
};
input.state.custom_operators.insert(
(op.clone(), op_type.clone()),
Operator::Custom(op, precedence, op_type),
Operator::new(op, precedence, op_type),
);
Ok(())
}
@ -153,13 +163,7 @@ pub fn predicate_parse_infix_expression<'a>(
) -> Result<Infix<Stream<'a>, Predicate, Operator, ContextError>>
{
let op = operator_parse_infix.parse_next(input)?;
let precedence = op.get_precedence() as i64;
Ok(Infix::Left(precedence, op, |_, a, op, b| {
Ok(Predicate::Fixed(
Functor::Operator(op),
vec![a, b],
))
}))
Ok(op.make_infix_operator())
}
pub fn predicate_parse_prefix_expression<'a>(
@ -169,10 +173,7 @@ pub fn predicate_parse_prefix_expression<'a>(
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],
))
Ok(Predicate::Fixed(Functor::Operator(op), vec![a]))
}))
}
pub fn predicate_parse_postfix_expression<'a>(
@ -182,10 +183,7 @@ pub fn predicate_parse_postfix_expression<'a>(
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],
))
Ok(Predicate::Fixed(Functor::Operator(op), vec![a]))
}))
}