summaryrefslogtreecommitdiff
path: root/src/commands/debug/parser.rs
blob: ca23c50cc9061737f462e5016326e69343063771 (plain)
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
85
86
87
88
89
90
91
92
93
use nom::branch::alt;
use nom::bytes::complete::{tag, take_while};
use nom::character::complete::{alpha1, char, space1, u32, u64};
use nom::combinator::{all_consuming, value};
use nom::sequence::tuple;
use nom::IResult;

use bch_bindgen::c::bpos;

use crate::commands::debug::{DebugCommand, DumpCommand, UpdateCommand};

fn parse_bpos(input: &str) -> IResult<&str, bpos> {
    let (input, (inode, _, offset, _, snapshot)) = tuple((
        u64,
        char(':'),
        u64,
        char(':'),
        alt((u32, value(u32::MAX, tag("U32_MAX")))),
    ))(input)?;

    Ok((
        input,
        bpos {
            inode,
            offset,
            snapshot,
        },
    ))
}

fn parse_dump_cmd(input: &str) -> IResult<&str, DebugCommand> {
    let (input, (_, btree, _, bpos)) =
        all_consuming(tuple((space1, alpha1, space1, parse_bpos)))(input)?;

    Ok((
        input,
        DebugCommand::Dump(DumpCommand {
            btree: btree.to_string(),
            bpos,
        }),
    ))
}

fn bkey_name(input: &str) -> IResult<&str, &str> {
    take_while(|c: char| c.is_alphabetic() || c == '_')(input)
}

fn field_name(input: &str) -> IResult<&str, &str> {
    take_while(|c: char| c.is_alphabetic() || c == '_' || c == '.')(input)
}

fn parse_update_cmd(input: &str) -> IResult<&str, DebugCommand> {
    let (input, (_, btree, _, bpos, _, bkey, _, field, _, value)) = all_consuming(tuple((
        space1,
        alpha1,
        space1,
        parse_bpos,
        space1,
        bkey_name,
        char('.'),
        field_name,
        char('='),
        u64,
    )))(input)?;

    Ok((
        input,
        DebugCommand::Update(UpdateCommand {
            btree: btree.to_string(),
            bpos,
            bkey: bkey.to_string(),
            field: field.to_string(),
            value,
        }),
    ))
}

fn parse_command_inner(input: &str) -> IResult<&str, DebugCommand> {
    let (input, cmd) = alt((tag("dump"), tag("update")))(input)?;

    match cmd {
        "dump" => parse_dump_cmd(input),
        "update" => parse_update_cmd(input),
        _ => unreachable!(),
    }
}

pub fn parse_command(input: &str) -> anyhow::Result<DebugCommand> {
    match parse_command_inner(input) {
        Ok((_, c)) => Ok(c),
        Err(e) => Err(anyhow::anyhow!("{e}")),
    }
}