1use std::str::FromStr;
2
3use nom::{
4 branch::alt,
5 bytes::complete::tag,
6 character::complete::{char, digit1},
7 combinator::{map, map_res, opt, recognize, value},
8 multi::many0,
9 sequence::{delimited, pair, preceded, tuple},
10 IResult,
11};
12use serde::Serialize;
13
14use crate::{
15 symbol::{parse_symbol, Symbol},
16 util::{ws, wsi},
17 ConfigInInput,
18};
19
20use super::source::parse_filepath;
21
22#[derive(Debug, Serialize, PartialEq, Clone)]
25pub enum Operator {
26 And,
27 Or,
28}
29
30#[derive(Debug, PartialEq, Serialize, Clone)]
31pub enum CompareOperator {
32 GreaterThan,
33 GreaterOrEqual,
34 LowerThan,
35 LowerOrEqual,
36 Equal,
37 DoubleEqual,
38 NotEqual,
39}
40
41pub type Expression = OrExpression;
43#[derive(Debug, Serialize, PartialEq, Clone)]
44pub enum AndExpression {
45 #[serde(rename = "AndTerm")]
46 Term(Term),
47
48 #[serde(rename = "And")]
49 Expression(Vec<Term>),
50}
51
52#[derive(Debug, Serialize, PartialEq, Clone)]
53pub enum OrExpression {
54 #[serde(rename = "OrTerm")]
55 Term(AndExpression),
56 #[serde(rename = "Or")]
57 Expression(Vec<AndExpression>),
58}
59
60#[derive(Debug, Serialize, PartialEq, Clone)]
61pub enum Term {
62 Not(Atom),
63 Atom(Atom),
64}
65
66#[derive(Debug, Serialize, PartialEq, Clone)]
67#[serde(rename = "Compare")]
68pub struct CompareExpression {
69 pub left: Symbol,
70 pub operator: CompareOperator,
71 pub right: Symbol,
72}
73
74#[derive(Debug, Serialize, PartialEq, Clone)]
75pub enum Atom {
76 Symbol(String),
77 Number(i64),
78 Existance(String),
79 Compare(CompareExpression),
80 Parenthesis(Box<Expression>),
81 Bracket(Box<Expression>),
82 String(Box<Atom>),
83}
84
85pub fn parse_or_expression(input: ConfigInInput) -> IResult<ConfigInInput, Expression> {
86 map(
87 tuple((
88 ws(parse_and_expression),
89 many0(preceded(
90 alt((wsi(tag("-o")), wsi(tag("||")))),
91 ws(parse_and_expression),
92 )),
93 )),
94 |(l, ee)| {
95 if ee.is_empty() {
96 OrExpression::Term(l)
97 } else {
98 let mut ll = vec![l];
99 ll.extend(ee);
100 OrExpression::Expression(ll)
101 }
102 },
103 )(input)
104}
105
106pub fn parse_and_expression(input: ConfigInInput) -> IResult<ConfigInInput, AndExpression> {
107 map(
108 tuple((
109 wsi(parse_term),
110 many0(preceded(wsi(alt((tag("-a"), tag("&&")))), wsi(parse_term))),
111 )),
112 |(l, ee)| {
113 if ee.is_empty() {
114 AndExpression::Term(l)
115 } else {
116 let mut ll = vec![l];
117 ll.extend(ee);
118 AndExpression::Expression(ll)
119 }
120 },
121 )(input)
122}
123
124pub fn parse_term(input: ConfigInInput) -> IResult<ConfigInInput, Term> {
125 alt((
126 map(
127 preceded(ws(alt((tag("-n"), tag("!")))), parse_atom),
128 Term::Not,
129 ),
130 map(parse_atom, Term::Atom),
131 ))(input)
132}
133
134pub fn parse_atom(input: ConfigInInput) -> IResult<ConfigInInput, Atom> {
135 alt((
136 map(
137 delimited(ws(tag("(")), parse_expression, ws(tag(")"))),
138 |expr| Atom::Parenthesis(Box::new(expr)),
139 ),
140 map(
141 delimited(ws(tag("[")), parse_expression, ws(tag("]"))),
142 |expr| Atom::Bracket(Box::new(expr)),
143 ),
144 ws(parse_compare),
145 map(delimited(tag("\""), parse_atom, tag("\"")), |d| {
146 Atom::String(Box::new(d))
147 }),
148 map(parse_entry_exists, Atom::Existance),
149 map(parse_number, Atom::Number),
150 map(parse_symbol, Atom::Symbol),
151 ))(input)
152}
153
154pub fn parse_entry_exists(input: ConfigInInput) -> IResult<ConfigInInput, String> {
155 map(preceded(wsi(tag("-f")), wsi(parse_filepath)), |f| {
157 f.to_string()
158 })(input)
159}
160
161pub fn parse_expression(input: ConfigInInput) -> IResult<ConfigInInput, Expression> {
162 parse_or_expression(input)
163}
164
165pub fn parse_compare_operator(input: ConfigInInput) -> IResult<ConfigInInput, CompareOperator> {
166 alt((
167 value(CompareOperator::GreaterOrEqual, tag(">=")),
168 value(CompareOperator::LowerOrEqual, tag("<=")),
169 value(CompareOperator::GreaterThan, tag(">")),
170 value(CompareOperator::LowerThan, tag("<")),
171 value(CompareOperator::DoubleEqual, tag("==")),
172 value(CompareOperator::Equal, tag("=")),
173 value(CompareOperator::NotEqual, tag("!=")),
174 ))(input)
175}
176
177pub fn parse_compare(input: ConfigInInput) -> IResult<ConfigInInput, Atom> {
178 map(
179 tuple((
180 ws(parse_symbol),
181 alt((
182 ws(delimited(tag("\""), ws(parse_compare_operator), tag("\""))),
183 ws(parse_compare_operator),
184 )),
185 ws(parse_symbol),
186 )),
187 |(l, o, r)| {
188 Atom::Compare(CompareExpression {
189 left: l,
190 operator: o,
191 right: r,
192 })
193 },
194 )(input)
195}
196
197pub fn parse_number(input: ConfigInInput) -> IResult<ConfigInInput, i64> {
198 map_res(
199 recognize(pair(opt(char('-')), digit1)),
200 |d: ConfigInInput| FromStr::from_str(d.fragment()),
201 )(input)
202}