ldscript_parser/
expressions.rs

1use idents::symbol;
2use nom::{
3    branch::alt,
4    bytes::complete::tag,
5    combinator::map,
6    multi::{fold_many0, separated_list0},
7    sequence::{delimited, pair},
8    IResult,
9};
10use numbers::number;
11use whitespace::opt_space;
12
13#[derive(Debug, PartialEq, Clone)]
14pub enum UnaryOperator {
15    LogicNot,
16    Minus,
17    BitwiseNot,
18}
19
20#[derive(Debug, PartialEq, Clone)]
21pub enum BinaryOperator {
22    LogicOr,
23    LogicAnd,
24    BitwiseOr,
25    BitwiseAnd,
26    Equals,
27    NotEquals,
28    Lesser,
29    Greater,
30    LesserOrEquals,
31    GreaterOrEquals,
32    ShiftRight,
33    ShiftLeft,
34    Plus,
35    Minus,
36    Multiply,
37    Divide,
38    Remainder,
39}
40
41#[derive(Debug, PartialEq, Clone)]
42pub enum Expression {
43    Ident(String),
44    Number(u64),
45    Call {
46        function: String,
47        arguments: Vec<Expression>,
48    },
49    UnaryOp {
50        operator: UnaryOperator,
51        right: Box<Expression>,
52    },
53    BinaryOp {
54        left: Box<Expression>,
55        operator: BinaryOperator,
56        right: Box<Expression>,
57    },
58    TernaryOp {
59        condition: Box<Expression>,
60        left: Box<Expression>,
61        right: Box<Expression>,
62    },
63}
64
65fn value_ident(input: &str) -> IResult<&str, Expression> {
66    map(symbol, |x: &str| Expression::Ident(x.into()))(input)
67}
68
69fn value_number(input: &str) -> IResult<&str, Expression> {
70    map(number, |x| Expression::Number(x))(input)
71}
72
73fn value_nested(input: &str) -> IResult<&str, Expression> {
74    delimited(tag("("), wsc!(expression), tag(")"))(input)
75}
76
77fn value_call(input: &str) -> IResult<&str, Expression> {
78    let (input, func) = symbol(input)?;
79    let (input, _) = wsc!(tag("("))(input)?;
80    let (input, args) = separated_list0(wsc!(tag(",")), expression)(input)?;
81    let (input, _) = pair(opt_space, tag(")"))(input)?;
82    Ok((
83        input,
84        Expression::Call {
85            function: func.into(),
86            arguments: args,
87        },
88    ))
89}
90
91pub fn value(input: &str) -> IResult<&str, Expression> {
92    alt((value_nested, value_call, value_number, value_ident))(input)
93}
94
95fn expr_unary_op(input: &str) -> IResult<&str, Expression> {
96    let (input, op) = alt((tag("-"), tag("!"), tag("~")))(input)?;
97    let (input, _) = opt_space(input)?;
98    let (input, right) = expr_level_1(input)?;
99    Ok((
100        input,
101        Expression::UnaryOp {
102            operator: match op {
103                "-" => UnaryOperator::Minus,
104                "!" => UnaryOperator::LogicNot,
105                "~" => UnaryOperator::BitwiseNot,
106                _ => panic!("Invalid operator"),
107            },
108            right: Box::new(right),
109        },
110    ))
111}
112
113fn expr_level_1(input: &str) -> IResult<&str, Expression> {
114    alt((expr_unary_op, value))(input)
115}
116
117fn expr_level_2(input: &str) -> IResult<&str, Expression> {
118    let (input, first) = expr_level_1(input)?;
119    let (input, fold) = fold_many0(
120        pair(wsc!(alt((tag("*"), tag("/"), tag("%")))), expr_level_1),
121        || first.clone(),
122        |prev, new: (&str, Expression)| Expression::BinaryOp {
123            left: Box::new(prev),
124            operator: match new.0 {
125                "*" => BinaryOperator::Multiply,
126                "/" => BinaryOperator::Divide,
127                "%" => BinaryOperator::Remainder,
128                _ => panic!("Invalid operator"),
129            },
130            right: Box::new(new.1),
131        },
132    )(input)?;
133    Ok((input, fold))
134}
135
136fn expr_level_3(input: &str) -> IResult<&str, Expression> {
137    let (input, first) = expr_level_2(input)?;
138    let (input, fold) = fold_many0(
139        pair(wsc!(alt((tag("+"), tag("-")))), expr_level_2),
140        || first.clone(),
141        |prev, new: (&str, Expression)| Expression::BinaryOp {
142            left: Box::new(prev),
143            operator: match new.0 {
144                "+" => BinaryOperator::Plus,
145                "-" => BinaryOperator::Minus,
146                _ => panic!("Invalid operator"),
147            },
148            right: Box::new(new.1),
149        },
150    )(input)?;
151    Ok((input, fold))
152}
153
154fn expr_level_4(input: &str) -> IResult<&str, Expression> {
155    let (input, first) = expr_level_3(input)?;
156    let (input, fold) = fold_many0(
157        pair(wsc!(alt((tag("<<"), tag(">>")))), expr_level_3),
158        || first.clone(),
159        |prev, new: (&str, Expression)| Expression::BinaryOp {
160            left: Box::new(prev),
161            operator: match new.0 {
162                "<<" => BinaryOperator::ShiftLeft,
163                ">>" => BinaryOperator::ShiftRight,
164                _ => panic!("Invalid operator"),
165            },
166            right: Box::new(new.1),
167        },
168    )(input)?;
169    Ok((input, fold))
170}
171
172fn expr_level_5(input: &str) -> IResult<&str, Expression> {
173    let (input, first) = expr_level_4(input)?;
174    let (input, fold) = fold_many0(
175        pair(
176            wsc!(alt((
177                tag("=="),
178                tag("!="),
179                tag("<="),
180                tag(">="),
181                tag("<"),
182                tag(">")
183            ))),
184            expr_level_4,
185        ),
186        || first.clone(),
187        |prev, new: (&str, Expression)| Expression::BinaryOp {
188            left: Box::new(prev),
189            operator: match new.0 {
190                "==" => BinaryOperator::Equals,
191                "!=" => BinaryOperator::NotEquals,
192                "<=" => BinaryOperator::LesserOrEquals,
193                ">=" => BinaryOperator::GreaterOrEquals,
194                "<" => BinaryOperator::Lesser,
195                ">" => BinaryOperator::Greater,
196                _ => panic!("Invalid operator"),
197            },
198            right: Box::new(new.1),
199        },
200    )(input)?;
201    Ok((input, fold))
202}
203
204fn expr_level_6(input: &str) -> IResult<&str, Expression> {
205    let (input, first) = expr_level_5(input)?;
206    let (input, fold) = fold_many0(
207        pair(wsc!(tag("&")), expr_level_5),
208        || first.clone(),
209        |prev, new: (&str, Expression)| Expression::BinaryOp {
210            left: Box::new(prev),
211            operator: BinaryOperator::BitwiseAnd,
212            right: Box::new(new.1),
213        },
214    )(input)?;
215    Ok((input, fold))
216}
217
218fn expr_level_7(input: &str) -> IResult<&str, Expression> {
219    let (input, first) = expr_level_6(input)?;
220    let (input, fold) = fold_many0(
221        pair(wsc!(tag("|")), expr_level_6),
222        || first.clone(),
223        |prev, new: (&str, Expression)| Expression::BinaryOp {
224            left: Box::new(prev),
225            operator: BinaryOperator::BitwiseOr,
226            right: Box::new(new.1),
227        },
228    )(input)?;
229    Ok((input, fold))
230}
231
232fn expr_level_8(input: &str) -> IResult<&str, Expression> {
233    let (input, first) = expr_level_7(input)?;
234    let (input, fold) = fold_many0(
235        pair(wsc!(tag("&&")), expr_level_7),
236        || first.clone(),
237        |prev, new: (&str, Expression)| Expression::BinaryOp {
238            left: Box::new(prev),
239            operator: BinaryOperator::LogicAnd,
240            right: Box::new(new.1),
241        },
242    )(input)?;
243    Ok((input, fold))
244}
245
246fn expr_level_9(input: &str) -> IResult<&str, Expression> {
247    let (input, first) = expr_level_8(input)?;
248    let (input, fold) = fold_many0(
249        pair(wsc!(tag("||")), expr_level_8),
250        || first.clone(),
251        |prev, new: (&str, Expression)| Expression::BinaryOp {
252            left: Box::new(prev),
253            operator: BinaryOperator::LogicOr,
254            right: Box::new(new.1),
255        },
256    )(input)?;
257    Ok((input, fold))
258}
259
260fn expr_ternary_op(input: &str) -> IResult<&str, Expression> {
261    let (input, cond) = expr_level_9(input)?;
262    let (input, _) = wsc!(tag("?"))(input)?;
263    let (input, left) = expression(input)?;
264    let (input, _) = wsc!(tag(":"))(input)?;
265    let (input, right) = expression(input)?;
266    Ok((
267        input,
268        Expression::TernaryOp {
269            condition: Box::new(cond),
270            left: Box::new(left),
271            right: Box::new(right),
272        },
273    ))
274}
275
276pub fn expression(input: &str) -> IResult<&str, Expression> {
277    alt((expr_ternary_op, expr_level_9))(input)
278}
279
280#[cfg(test)]
281mod tests {
282    use expressions::*;
283
284    #[test]
285    fn test_ws() {
286        let x = "a ( b ( d , ( 0 ) ) , c )";
287        assert_done!(expression(x));
288        let y = "a(b(d,(0)),c)";
289        assert_eq!(expression(x), expression(y));
290    }
291
292    #[test]
293    fn test_expression() {
294        assert_done!(expression("a ( .b ) ? c ( d ) : e"));
295
296        assert_done!(expression("A-B"), Expression::Ident("A-B".into()));
297
298        assert_done!(
299            expression("A - B"),
300            Expression::BinaryOp {
301                left: Box::new(Expression::Ident("A".into())),
302                operator: BinaryOperator::Minus,
303                right: Box::new(Expression::Ident("B".into())),
304            }
305        );
306    }
307}