nom_config_in/entry/
expression.rs

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// (GFS2_FS!=n) && NET && INET && (IPV6 || IPV6=n) && CONFIGFS_FS && SYSFS && (DLM=y || DLM=GFS2_FS)
23
24#[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
41// https://stackoverflow.com/questions/9509048/antlr-parser-for-and-or-logic-how-to-get-expressions-between-logic-operators
42pub 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    //let t = tag("-f")(input);
156    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}