1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
use idents::symbol;
use nom::{
    branch::alt,
    bytes::complete::{tag, take_until},
    combinator::opt,
    sequence::{delimited, tuple},
    IResult,
};
use numbers::number;
use whitespace::opt_space;

#[derive(Debug, PartialEq)]
pub struct Region {
    pub name: String,
    pub origin: u64,
    pub length: u64,
}

fn attributes(input: &str) -> IResult<&str, &str> {
    delimited(tag("("), take_until(")"), tag(")"))(input)
}

fn origin(input: &str) -> IResult<&str, &str> {
    alt((tag("ORIGIN"), tag("org"), tag("o")))(input)
}

fn length(input: &str) -> IResult<&str, &str> {
    alt((tag("LENGTH"), tag("len"), tag("l")))(input)
}

pub fn region(input: &str) -> IResult<&str, Region> {
    let (input, name) = symbol(input)?;
    let (input, _) = tuple((
        opt_space,
        opt(attributes),
        wsc!(tag(":")),
        origin,
        wsc!(tag("=")),
    ))(input)?;
    let (input, org) = number(input)?;
    let (input, _) = tuple((wsc!(tag(",")), length, wsc!(tag("="))))(input)?;
    let (input, len) = number(input)?;
    Ok((
        input,
        Region {
            name: name.into(),
            origin: org,
            length: len,
        },
    ))
}

#[cfg(test)]
mod tests {
    use memory::*;

    #[test]
    fn test_region() {
        assert_done!(
            region("rom (rx)  : ORIGIN = 0, LENGTH = 256K"),
            Region {
                name: "rom".into(),
                origin: 0,
                length: 256 * 1024,
            }
        );
        assert_done!(
            region("ram (!rx) : org = 0x40000000, l = 4M"),
            Region {
                name: "ram".into(),
                origin: 0x40000000,
                length: 4 * 1024 * 1024,
            }
        );
    }
}