aboutsummaryrefslogtreecommitdiffstats
path: root/src/parse.rs
blob: cc495b1fa6513720174e1805f7c1c511b0f70fdc (plain) (blame)
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
78
79
80
81
82
83
84
pub enum Ast {
    AssignVar(AssignVar),
    Pipes(Pipes),
}

pub struct AssignVar {
    pub to: String,
    // TODO: body
}

pub struct Pipes {
    pub cmds: Vec<Command>,
}

pub struct Command {
    pub path: String,
    pub args: Vec<String>,
}

enum ParseError {
    Incomplete,
    UnexpectedPipe,
    UnknownChar(char),
}

type Result<T> = std::result::Result<T, ParseError>;

pub fn parse(x: &str) -> Result<Ast> {
    let chars: Vec<char> = x.chars().collect();
    Ast::parse(&mut &chars[..])
}

trait Parse: Sized {
    fn parse(b: &mut &[char]) -> Result<Self>;
}

fn spaces(b: &mut &[char]) {
    while let Some(' ' | '\t') = b.get(0) {
        *b = &b[1..];
    }
}

fn parse_quoted_string(b: &mut &[char], delim: char) -> Result<String> {
    // TODO: escape sequence stuff

    *b = &b[1..];
    let mut s = String::new();
    while b.len() > 0 {
        if b[0] == delim {
            *b = &b[1..];
            return Ok(s);
        }

        s.push(b[0]);
        *b = &b[1..];
    }
    Err(ParseError::Incomplete)
}

impl Parse for String {
    fn parse(b: &mut &[char]) -> Result<Self> {
        spaces(b);
        if b.is_empty() {
            return Err(ParseError::Incomplete);
        }
        let c = b[0];
        if c == '|' {
            Err(ParseError::UnexpectedPipe)
        } else if c == '\'' || c == '"' {
            *b = &b[1..];
            parse_quoted_string(b, c)
        } else if c.is_ascii_graphic() {
            parse_quoted_string(b, ' ')
        } else {
            Err(ParseError::UnknownChar(c))
        }
    }
}

impl Parse for Ast {
    fn parse(b: &mut &[char]) -> Result<Self> {
        todo!()
    }
}