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 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 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 pub src: Span,
167 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 src: input.get(0).unwrap().location.clone(),
185 blocks,
186 })(input)?;
187 Ok((rest, pattern))
188 }
189}