sleigh_rs/syntax/block/
pattern.rs

1use nom::branch::alt;
2use nom::combinator::{map, map_res, opt, value};
3use nom::multi::{many0, separated_list0};
4use nom::sequence::{delimited, pair, tuple};
5use nom::IResult;
6
7use super::disassembly;
8use crate::preprocessor::token::Token;
9use crate::semantic::pattern::{CmpOp, Ellipsis};
10use crate::syntax::parser::ident;
11use crate::{SleighError, Span};
12
13#[derive(Clone, Copy, PartialEq, Eq, Debug)]
14pub enum Op {
15    And,
16    Or,
17}
18
19impl Op {
20    pub fn parse(input: &[Token]) -> IResult<&[Token], Op, SleighError> {
21        alt((value(Op::Or, tag!("|")), value(Op::And, tag!("&"))))(input)
22    }
23}
24
25impl CmpOp {
26    pub fn parse(input: &[Token]) -> IResult<&[Token], CmpOp, SleighError> {
27        alt((
28            value(CmpOp::Le, tag!("<=")),
29            value(CmpOp::Ge, tag!(">=")),
30            value(CmpOp::Ne, tag!("!=")),
31            //TODO order is important, so ">=" is not consumed as ">"
32            value(CmpOp::Eq, tag!("=")),
33            value(CmpOp::Lt, tag!("<")),
34            value(CmpOp::Gt, tag!(">")),
35        ))(input)
36    }
37}
38
39#[derive(Clone, Debug)]
40pub struct ConstraintValue {
41    pub expr: disassembly::Expr,
42}
43
44impl ConstraintValue {
45    fn parse(input: &[Token]) -> IResult<&[Token], Self, SleighError> {
46        map(
47            alt((
48                delimited(
49                    tag!("("),
50                    |x| disassembly::Expr::parse(x, true),
51                    tag!(")"),
52                ),
53                |x| disassembly::Expr::parse(x, false),
54            )),
55            |expr| ConstraintValue { expr },
56        )(input)
57    }
58}
59
60#[derive(Clone, Debug)]
61pub struct Constraint {
62    pub op: CmpOp,
63    pub value: ConstraintValue,
64}
65
66impl Constraint {
67    fn parse(input: &[Token]) -> IResult<&[Token], Self, SleighError> {
68        map(pair(CmpOp::parse, ConstraintValue::parse), |(op, value)| {
69            Self { op, value }
70        })(input)
71    }
72}
73
74#[derive(Clone, Debug)]
75pub enum Field {
76    Field {
77        field: String,
78        src: Span,
79        constraint: Option<Constraint>,
80    },
81    SubPattern(Pattern),
82}
83impl Field {
84    pub fn parse(input: &[Token]) -> IResult<&[Token], Self, SleighError> {
85        alt((
86            map(delimited(tag!("("), Pattern::parse, tag!(")")), |sub| {
87                Field::SubPattern(sub)
88            }),
89            map(
90                pair(ident, opt(Constraint::parse)),
91                |((field, field_src), constraint)| Field::Field {
92                    field,
93                    src: field_src.clone(),
94                    constraint,
95                },
96            ),
97        ))(input)
98    }
99}
100
101#[derive(Clone, Debug)]
102pub struct Element {
103    pub field: Field,
104    pub ellipsis: Option<Ellipsis>,
105}
106
107impl Element {
108    pub fn parse(input: &[Token]) -> IResult<&[Token], Self, SleighError> {
109        map_res(
110            tuple((
111                opt(map(tag!("..."), |span| (Ellipsis::Left, span))),
112                Field::parse,
113                opt(map(tag!("..."), |span| (Ellipsis::Right, span))),
114            )),
115            |(left, field, right)| {
116                let ellipsis = match (left, right) {
117                    (Some((_, left)), Some((_, right))) => {
118                        let location = Span::combine(
119                            left.clone().start(),
120                            right.clone().end(),
121                        );
122                        return Err(SleighError::DualEllipsis(location));
123                    }
124                    (left, right) => left.or(right).map(|(e, _)| e),
125                };
126                Ok(Element { field, ellipsis })
127            },
128        )(input)
129    }
130}
131
132#[derive(Clone, Debug)]
133pub struct Block {
134    pub src: Span,
135    pub first: Element,
136    pub elements: Vec<(Op, Element)>,
137}
138
139impl Block {
140    pub fn op(&self) -> Op {
141        self.elements.first().map(|(op, _)| *op).unwrap_or(Op::And)
142    }
143    pub fn parse(input: &[Token]) -> IResult<&[Token], Self, SleighError> {
144        map(
145            tuple((Element::parse, many0(pair(Op::parse, Element::parse)))),
146            |(first, elements)| {
147                //TODO improve this src
148                let src = match &first.field {
149                    Field::SubPattern(pat) => pat.src.clone(),
150                    Field::Field { src, .. } => src.clone(),
151                };
152                Self {
153                    first,
154                    elements,
155                    src,
156                }
157            },
158        )(input)
159    }
160}
161
162#[derive(Clone, Debug)]
163pub struct Pattern {
164    //NOTE point after the `is` in the constructor, pattern itself don't have a
165    //start, thats because it could be mixed with the `with_block` pattern
166    pub src: Span,
167    //NOTE: point after the `is`
168    pub blocks: Vec<Block>,
169}
170impl IntoIterator for Pattern {
171    type Item = Block;
172    type IntoIter = std::vec::IntoIter<Block>;
173
174    fn into_iter(self) -> Self::IntoIter {
175        self.blocks.into_iter()
176    }
177}
178
179impl Pattern {
180    pub fn parse(input: &[Token]) -> IResult<&[Token], Self, SleighError> {
181        let (rest, pattern) =
182            map(separated_list0(tag!(";"), Block::parse), |blocks| Pattern {
183                //TODO improve the src here
184                src: input.get(0).unwrap().location.clone(),
185                blocks,
186            })(input)?;
187        Ok((rest, pattern))
188    }
189}