rs_args/parsing/
mod.rs

1pub mod errors;
2
3#[cfg(test)]
4pub mod tests;
5
6use crate::lexing::{ Token, TokenKind };
7
8/// Arguments can either be positional or named. Positional arguments are
9/// identified by their position relative to the command name. Note that
10/// named arguments are not counted towards the positional argument count.
11/// Named arguments are identified by a flag, which is an identifier prefixed
12/// by a dash. The flag may be followed by a value, which is separated by a
13/// space. If the value is not present, the argument is considered a flag.
14#[derive(Debug, Clone)]
15#[allow(dead_code)]
16pub struct Argument {
17    name: Option<String>,
18    value: Option<String>,
19    position: Option<usize>,
20}
21
22impl Argument {
23    pub fn get_name(&self) -> Option<&str> {
24        self.name.as_deref()
25    }
26
27    pub fn get_value(&self) -> Option<&str> {
28        self.value.as_deref()
29    }
30
31    pub fn get_position(&self) -> Option<usize> {
32        self.position
33    }
34}
35
36pub fn parse(mut input: Vec<Token>) -> Vec<Argument> {
37    let mut arguments: Vec<Argument> = Vec::new();
38    while !input.is_empty() {
39        let result = parse_argument(
40            &mut input,
41            arguments
42                .iter()
43                .filter(|it| it.position.is_some())
44                .count()
45        );
46
47        arguments.push(result);
48    }
49
50    arguments
51}
52
53fn parse_argument(input: &mut Vec<Token>, positional_count: usize) -> Argument {
54    let token = input.get(0).unwrap();
55    match token.get_kind() {
56        TokenKind::Dash => {
57            input.remove(0);
58            parse_named_argument(input)
59        }
60        _ => parse_positional_argument(input, positional_count),
61    }
62}
63
64fn parse_named_argument(input: &mut Vec<Token>) -> Argument {
65    let key = input.remove(0);
66    if input.is_empty() || *input[0].get_kind() != TokenKind::Equals {
67        return Argument { name: Some(key.get_value().to_string()), value: None, position: None };
68    }
69
70    let _ = input.remove(0);
71
72    let value = input.remove(0);
73
74    Argument {
75        name: Some(key.get_value().clone()),
76        value: Some(value.get_value().clone()),
77        position: None,
78    }
79}
80
81fn parse_positional_argument(input: &mut Vec<Token>, count: usize) -> Argument {
82    let value = input.remove(0);
83
84    Argument {
85        name: None,
86        value: Some(value.get_value().clone()),
87        position: Some(count),
88    }
89}