use an enum for OpDesc spec

This commit is contained in:
Bennet Bleßmann
2024-07-31 23:48:27 +02:00
parent 2814d79b56
commit 409f56ea37
9 changed files with 216 additions and 148 deletions

View File

@@ -26,13 +26,112 @@ pub type Specifier = u32;
pub const MAX_ARITY: usize = 1023;
pub const XFX: u32 = 0x0001;
pub const XFY: u32 = 0x0002;
pub const YFX: u32 = 0x0004;
pub const XF: u32 = 0x0010;
pub const YF: u32 = 0x0020;
pub const FX: u32 = 0x0040;
pub const FY: u32 = 0x0080;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum OpDeclSpec {
XFX = 0x0001,
XFY = 0x0002,
YFX = 0x0004,
XF = 0x0010,
YF = 0x0020,
FX = 0x0040,
FY = 0x0080,
}
pub use OpDeclSpec::*;
impl OpDeclSpec {
pub const fn value(self) -> u32 {
self as u32
}
pub fn get_spec(self) -> Atom {
match self {
XFX => atom!("xfx"),
XFY => atom!("xfy"),
YFX => atom!("yfx"),
FX => atom!("fx"),
FY => atom!("fy"),
XF => atom!("xf"),
YF => atom!("yf"),
}
}
pub const fn is_prefix(self) -> bool {
matches!(self, Self::FX | Self::FY)
}
pub const fn is_postfix(self) -> bool {
matches!(self, Self::XF | Self::YF)
}
pub const fn is_infix(self) -> bool {
matches!(self, Self::XFX | Self::XFY | Self::YFX)
}
pub const fn is_strict_left(self) -> bool {
matches!(self, Self::XFX | Self::XFY | Self::XF)
}
pub const fn is_strict_right(self) -> bool {
matches!(self, Self::XFX | Self::YFX | Self::FX)
}
#[inline(always)]
pub(crate) fn fixity(self) -> Fixity {
match self {
XFY | XFX | YFX => Fixity::In,
XF | YF => Fixity::Post,
FX | FY => Fixity::Pre,
}
}
}
impl From<OpDeclSpec> for u8 {
fn from(value: OpDeclSpec) -> Self {
value as u8
}
}
impl From<OpDeclSpec> for u32 {
fn from(value: OpDeclSpec) -> Self {
value as u32
}
}
impl TryFrom<u8> for OpDeclSpec {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
Ok(match value {
0x0001 => XFX,
0x0002 => XFY,
0x0004 => YFX,
0x0010 => XF,
0x0020 => YF,
0x0040 => FX,
0x0080 => FY,
_ => return Err(()),
})
}
}
impl TryFrom<Atom> for OpDeclSpec {
type Error = ();
fn try_from(value: Atom) -> Result<Self, Self::Error> {
Ok(match value {
atom!("xfx") => Self::XFX,
atom!("xfy") => Self::XFY,
atom!("yfx") => Self::YFX,
atom!("fx") => Self::FX,
atom!("fy") => Self::FY,
atom!("xf") => Self::XF,
atom!("yf") => Self::YF,
_ => return Err(()),
})
}
}
pub const DELIMITER: u32 = 0x0100;
pub const TERM: u32 = 0x1000;
pub const LTERM: u32 = 0x3000;
@@ -64,13 +163,13 @@ macro_rules! is_lterm {
macro_rules! is_op {
($x:expr) => {
$x as u32
& ($crate::parser::ast::XF
| $crate::parser::ast::YF
| $crate::parser::ast::FX
| $crate::parser::ast::FY
| $crate::parser::ast::XFX
| $crate::parser::ast::XFY
| $crate::parser::ast::YFX)
& ($crate::parser::ast::XF as u32
| $crate::parser::ast::YF as u32
| $crate::parser::ast::FX as u32
| $crate::parser::ast::FY as u32
| $crate::parser::ast::XFX as u32
| $crate::parser::ast::XFY as u32
| $crate::parser::ast::YFX as u32)
!= 0
};
}
@@ -84,14 +183,14 @@ macro_rules! is_negate {
#[macro_export]
macro_rules! is_prefix {
($x:expr) => {
$x as u32 & ($crate::parser::ast::FX | $crate::parser::ast::FY) != 0
$x as u32 & ($crate::parser::ast::FX as u32 | $crate::parser::ast::FY as u32) != 0
};
}
#[macro_export]
macro_rules! is_postfix {
($x:expr) => {
$x as u32 & ($crate::parser::ast::XF | $crate::parser::ast::YF) != 0
$x as u32 & ($crate::parser::ast::XF as u32 | $crate::parser::ast::YF as u32) != 0
};
}
@@ -99,7 +198,9 @@ macro_rules! is_postfix {
macro_rules! is_infix {
($x:expr) => {
($x as u32
& ($crate::parser::ast::XFX | $crate::parser::ast::XFY | $crate::parser::ast::YFX))
& ($crate::parser::ast::XFX as u32
| $crate::parser::ast::XFY as u32
| $crate::parser::ast::YFX as u32))
!= 0
};
}
@@ -107,49 +208,48 @@ macro_rules! is_infix {
#[macro_export]
macro_rules! is_xfx {
($x:expr) => {
($x as u32 & $crate::parser::ast::XFX) != 0
($x as u32 & $crate::parser::ast::XFX as u32) != 0
};
}
#[macro_export]
macro_rules! is_xfy {
($x:expr) => {
($x as u32 & $crate::parser::ast::XFY) != 0
($x as u32 & $crate::parser::ast::XFY as u32) != 0
};
}
#[macro_export]
macro_rules! is_yfx {
($x:expr) => {
($x as u32 & $crate::parser::ast::YFX) != 0
($x as u32 & $crate::parser::ast::YFX as u32) != 0
};
}
#[macro_export]
macro_rules! is_yf {
($x:expr) => {
($x as u32 & $crate::parser::ast::YF) != 0
($x as u32 & $crate::parser::ast::YF as u32) != 0
};
}
#[macro_export]
macro_rules! is_xf {
($x:expr) => {
($x as u32 & $crate::parser::ast::XF) != 0
($x as u32 & $crate::parser::ast::XF as u32) != 0
};
}
#[macro_export]
macro_rules! is_fx {
($x:expr) => {
($x as u32 & $crate::parser::ast::FX) != 0
($x as u32 & $crate::parser::ast::FX as u32) != 0
};
}
#[macro_export]
macro_rules! is_fy {
($x:expr) => {
($x as u32 & $crate::parser::ast::FY) != 0
($x as u32 & $crate::parser::ast::FY as u32) != 0
};
}
@@ -264,18 +364,18 @@ pub struct OpDesc {
impl OpDesc {
#[inline]
pub fn build_with(prec: u16, spec: u8) -> Self {
OpDesc::new().with_spec(spec).with_prec(prec)
pub fn build_with(prec: u16, spec: OpDeclSpec) -> Self {
OpDesc::new().with_spec(spec as u8).with_prec(prec)
}
#[inline]
pub fn get(self) -> (u16, u8) {
(self.prec(), self.spec())
pub fn get(self) -> (u16, OpDeclSpec) {
(self.prec(), self.get_spec())
}
pub fn set(&mut self, prec: u16, spec: u8) {
pub fn set(&mut self, prec: u16, spec: OpDeclSpec) {
self.set_prec(prec);
self.set_spec(spec);
self.set_spec(spec as u8);
}
#[inline]
@@ -284,13 +384,13 @@ impl OpDesc {
}
#[inline]
pub fn get_spec(self) -> u8 {
self.spec()
pub fn get_spec(self) -> OpDeclSpec {
OpDeclSpec::try_from(self.spec()).expect("OpDecl always contains a valud OpDeclSpec")
}
#[inline]
pub fn arity(self) -> usize {
if self.spec() as u32 & (XFX | XFY | YFX) == 0 {
if !self.get_spec().is_infix() {
1
} else {
2
@@ -354,22 +454,10 @@ impl Unknown {
pub fn default_op_dir() -> OpDir {
let mut op_dir = OpDir::with_hasher(FxBuildHasher::default());
op_dir.insert(
(atom!(":-"), Fixity::In),
OpDesc::build_with(1200, XFX as u8),
);
op_dir.insert(
(atom!(":-"), Fixity::Pre),
OpDesc::build_with(1200, FX as u8),
);
op_dir.insert(
(atom!("?-"), Fixity::Pre),
OpDesc::build_with(1200, FX as u8),
);
op_dir.insert(
(atom!(","), Fixity::In),
OpDesc::build_with(1000, XFY as u8),
);
op_dir.insert((atom!(":-"), Fixity::In), OpDesc::build_with(1200, XFX));
op_dir.insert((atom!(":-"), Fixity::Pre), OpDesc::build_with(1200, FX));
op_dir.insert((atom!("?-"), Fixity::Pre), OpDesc::build_with(1200, FX));
op_dir.insert((atom!(","), Fixity::In), OpDesc::build_with(1000, XFY));
op_dir
}

View File

@@ -385,10 +385,10 @@ impl<'a, R: CharRead> Parser<'a, R> {
}
}
fn push_unary_op(&mut self, td: TokenDesc, spec: Specifier, assoc: u32) {
fn push_unary_op(&mut self, td: TokenDesc, spec: Specifier, assoc: OpDeclSpec) {
if let Some(mut arg1) = self.terms.pop() {
if let Some(mut name) = self.terms.pop() {
if is_postfix!(assoc) {
if assoc.is_postfix() {
mem::swap(&mut arg1, &mut name);
}
@@ -912,7 +912,11 @@ impl<'a, R: CharRead> Parser<'a, R> {
// can't be prefix, so either inf == 0
// or post == 0.
self.reduce_op(inf + post);
self.promote_atom_op(name, inf + post, spec & (XFX | XFY | YFX | YF | XF));
self.promote_atom_op(
name,
inf + post,
spec & (XFX as u32 | XFY as u32 | YFX as u32 | YF as u32 | XF as u32),
);
}
_ => {
self.reduce_op(inf + post);
@@ -923,14 +927,22 @@ impl<'a, R: CharRead> Parser<'a, R> {
self.promote_atom_op(
name,
inf + post,
spec & (XFX | XFY | YFX | XF | YF),
spec & (XFX as u32
| XFY as u32
| YFX as u32
| XF as u32
| YF as u32),
);
return Ok(true);
}
}
self.promote_atom_op(name, pre, spec & (FX | FY | NEGATIVE_SIGN));
self.promote_atom_op(
name,
pre,
spec & (FX as u32 | FY as u32 | NEGATIVE_SIGN),
);
}
}
} else {
@@ -1066,7 +1078,7 @@ impl<'a, R: CharRead> Parser<'a, R> {
}
Token::Comma => {
self.reduce_op(1000);
self.shift(Token::Comma, 1000, XFY);
self.shift(Token::Comma, 1000, XFY as u32);
}
Token::End => match self.stack.last().map(|t| t.tt) {
Some(TokenType::Open)