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
77
use commands::{command, Command};
use memory::region;
use memory::Region;
use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::combinator::map;
use nom::multi::many1;
use nom::sequence::tuple;
use nom::IResult;
use sections::section_command;
use sections::SectionCommand;
use statements::{statement, Statement};
use whitespace::opt_space;

#[derive(Debug, PartialEq)]
pub enum RootItem {
    Statement(Statement),
    Command(Command),
    Memory { regions: Vec<Region> },
    Sections { list: Vec<SectionCommand> },
}

fn statement_item(input: &str) -> IResult<&str, RootItem> {
    map(statement, |stmt| RootItem::Statement(stmt))(input)
}

fn command_item(input: &str) -> IResult<&str, RootItem> {
    map(command, |cmd| RootItem::Command(cmd))(input)
}

fn memory_item(input: &str) -> IResult<&str, RootItem> {
    let (input, _) = tuple((tag("MEMORY"), wsc!(tag("{"))))(input)?;
    let (input, regions) = many1(wsc!(region))(input)?;
    let (input, _) = tag("}")(input)?;
    Ok((input, RootItem::Memory { regions: regions }))
}

fn sections_item(input: &str) -> IResult<&str, RootItem> {
    let (input, _) = tuple((tag("SECTIONS"), wsc!(tag("{"))))(input)?;
    let (input, sections) = many1(wsc!(section_command))(input)?;
    let (input, _) = tag("}")(input)?;
    Ok((input, RootItem::Sections { list: sections }))
}

fn root_item(input: &str) -> IResult<&str, RootItem> {
    alt((statement_item, memory_item, sections_item, command_item))(input)
}

pub fn parse(input: &str) -> IResult<&str, Vec<RootItem>> {
    alt((many1(wsc!(root_item)), map(opt_space, |_| vec![])))(input)
}

#[cfg(test)]
mod tests {
    use script::*;
    use std::fs::{self, File};
    use std::io::Read;

    #[test]
    fn test_empty() {
        assert_done_vec!(parse(""), 0);
        assert_done_vec!(parse("                               "), 0);
        assert_done_vec!(parse("      /* hello */              "), 0);
    }

    #[test]
    fn test_parse() {
        for entry in fs::read_dir("tests").unwrap() {
            let path = entry.unwrap().path();
            println!("testing: {:?}", path);
            let mut file = File::open(path).unwrap();
            let mut contents = String::new();
            file.read_to_string(&mut contents).unwrap();
            assert_done!(parse(&contents));
        }
    }
}