ldscript_parser/
statements.rs

1use expressions::expression;
2use expressions::Expression;
3use idents::{string, symbol};
4use nom::branch::alt;
5use nom::bytes::complete::tag;
6use nom::combinator::map;
7use nom::combinator::opt;
8use nom::IResult;
9use whitespace::opt_space;
10
11#[derive(Debug, PartialEq)]
12pub enum AssignOperator {
13    Equals,
14    Plus,
15    Minus,
16    Multiply,
17    Divide,
18    ShiftLeft,
19    ShiftRight,
20    And,
21    Or,
22}
23
24#[derive(Debug, PartialEq)]
25pub enum Statement {
26    Assign {
27        name: String,
28        operator: AssignOperator,
29        expression: Box<Expression>,
30    },
31    Hidden {
32        name: String,
33        expression: Box<Expression>,
34    },
35    Provide {
36        name: String,
37        expression: Box<Expression>,
38    },
39    ProvideHidden {
40        name: String,
41        expression: Box<Expression>,
42    },
43    Assert {
44        expr: Box<Expression>,
45        text: String,
46    },
47}
48
49fn assign_operator(input: &str) -> IResult<&str, AssignOperator> {
50    map(
51        alt((
52            tag("="),
53            tag("+="),
54            tag("-="),
55            tag("*="),
56            tag("/="),
57            tag("<<="),
58            tag(">>="),
59            tag("&="),
60            tag("|="),
61        )),
62        |op: &str| match op {
63            "=" => AssignOperator::Equals,
64            "+=" => AssignOperator::Plus,
65            "-=" => AssignOperator::Minus,
66            "*=" => AssignOperator::Multiply,
67            "/=" => AssignOperator::Divide,
68            "<<=" => AssignOperator::ShiftLeft,
69            ">>=" => AssignOperator::ShiftRight,
70            "&=" => AssignOperator::And,
71            "|=" => AssignOperator::Or,
72            _ => panic!("wrong operator"),
73        },
74    )(input)
75}
76
77fn special_assign(input: &str) -> IResult<&str, Statement> {
78    let (input, keyword) = alt((tag("PROVIDE_HIDDEN"), tag("PROVIDE"), tag("HIDDEN")))(input)?;
79    let (input, _) = wsc!(tag("("))(input)?;
80    let (input, name) = symbol(input)?;
81    let (input, _) = wsc!(tag("="))(input)?;
82    let (input, expr) = expression(input)?;
83    let (input, _) = wsc!(tag(")"))(input)?;
84    let (input, _) = tag(";")(input)?;
85    Ok((
86        input,
87        match keyword {
88            "HIDDEN" => Statement::Hidden {
89                name: name.into(),
90                expression: Box::new(expr),
91            },
92            "PROVIDE" => Statement::Provide {
93                name: name.into(),
94                expression: Box::new(expr),
95            },
96            "PROVIDE_HIDDEN" => Statement::ProvideHidden {
97                name: name.into(),
98                expression: Box::new(expr),
99            },
100            _ => panic!("invalid assign keyword"),
101        },
102    ))
103}
104
105fn assign(input: &str) -> IResult<&str, Statement> {
106    let (input, name) = symbol(input)?;
107    let (input, op) = wsc!(assign_operator)(input)?;
108    let (input, expr) = expression(input)?;
109    let (input, _) = opt_space(input)?;
110    let (input, _) = tag(";")(input)?;
111    Ok((
112        input,
113        Statement::Assign {
114            name: name.into(),
115            operator: op,
116            expression: Box::new(expr),
117        },
118    ))
119}
120
121fn assert_stmt(input: &str) -> IResult<&str, Statement> {
122    let (input, _) = tag("ASSERT")(input)?;
123    let (input, _) = wsc!(tag("("))(input)?;
124    let (input, expr) = expression(input)?;
125    let (input, _) = wsc!(tag(","))(input)?;
126    let (input, text) = string(input)?;
127    let (input, _) = wsc!(tag(")"))(input)?;
128    let (input, _) = opt(tag(";"))(input)?;
129    Ok((
130        input,
131        Statement::Assert {
132            expr: Box::new(expr),
133            text: text.into(),
134        },
135    ))
136}
137
138pub fn statement(input: &str) -> IResult<&str, Statement> {
139    alt((special_assign, assign, assert_stmt))(input)
140}
141
142#[cfg(test)]
143mod tests {
144    use expressions::Expression;
145    use statements::*;
146
147    #[test]
148    fn test_statement() {
149        assert_done!(
150            statement("A = 11 ;"),
151            Statement::Assign {
152                name: "A".into(),
153                operator: AssignOperator::Equals,
154                expression: Box::new(Expression::Number(11)),
155            }
156        );
157        assert_done!(
158            statement("PROVIDE ( x = x ) ;"),
159            Statement::Provide {
160                name: "x".into(),
161                expression: Box::new(Expression::Ident("x".into())),
162            }
163        );
164        assert_done!(statement("PROBLEM += HELLO ( WORLD , 0 ) + 1 ;"));
165    }
166}