1use crate::rifgen::{AddressKind, Context, InstMode, RegInst};
2
3use winnow::{
4    ascii::space0,
5    combinator::{alt, delimited, opt, preceded, terminated},
6    error::StrContext,
7    token::take_until,
8    Parser
9};
10
11use super::{identifier, parser_expr::{parse_expr, ExprTokens}, val_u64, val_u16, ws, Res, ResF};
12
13pub fn page_properties<'a>(input: &mut &'a str) -> Res<'a, Context> {
17    terminated(
18        alt((
19            ws("baseAddress").value(Context::BaseAddress),
20            ws("addrWidth").value(Context::AddrWidth),
21            ws("description").value(Context::Description),
22            ws("desc").value(Context::Description),
23            ws("clkEn").value(Context::HwClkEn),
24            ws("external").value(Context::External),
25            ws("optional").value(Context::Optional),
26            ws("registers").value(Context::Registers),
27            ws("instances").value(Context::Instances),
28            ws("include").value(Context::Include),
29        )),
30        opt(ws(":")),
31    ).context(StrContext::Label("page property"))
32    .parse_next(input)
33}
34
35pub fn is_auto(input: &str) -> ResF<InstMode> {
39    alt((
40        ws("auto-legacy").value(InstMode::AutoLegacy),
41        ws("auto").value(InstMode::Automatic),
42        space0.value(InstMode::Manual)
43    )).parse(input)
44}
45
46pub fn reg_inst(input: &str) -> ResF<RegInst> {
48    (
49        preceded(ws("-"), ws(identifier)),
50        opt(
51            delimited(
52                ws("["),
53                take_until(1..,"]"),
54                ws("]")
55            )
56        ).try_map(|s| if let Some(expr) = s {parse_expr(expr)} else {Ok(ExprTokens::new(0))}),
57        opt(preceded(ws("="), ws(identifier))),
58        opt(delimited(ws("("), identifier, ws(")"))),
59        opt((
60            alt((
61                ws("@+=").value(AddressKind::RelativeSet),
62                ws("@+").value(AddressKind::Relative),
63                ws("@").value(AddressKind::Absolute),
64            )),
65            ws(val_u64),
66        )),
67    ).context(StrContext::Label("register instance"))
68    .parse(input)
69    .map(|v| v.into())
70}
71
72pub fn reg_inst_properties<'a>(input: &mut &'a str) -> Res<'a, Context> {
73    terminated(
74        alt((
75            alt((ws("description"),ws("desc"))).value(Context::Description),
76            ws("parameters").value(Context::Parameters),
77            ws("info").value(Context::Info),
78            ws("optional").value(Context::Optional),
79            ws("hidden").value(Context::Hidden),
80            alt((ws("disabled"),ws("disable"))).value(Context::Disabled),
81            ws("reserved").value(Context::Reserved),
82            ws("hw").value(Context::HwAccess),
83            delimited(ws("["), val_u16, ws("].")).map(Context::RegIndex),
84            terminated(identifier, ".").map(|v| Context::Item(v.into())),
85            reg_inst_field_array,
86        )),
87        opt(alt((ws(":"),ws("=")))),
88    ).context(StrContext::Label("register instance property"))
89    .parse_next(input)
90}
91
92pub fn reg_inst_array_properties<'a>(input: &mut &'a str) -> Res<'a, Context> {
93    terminated(
94        alt((
95            alt((ws("description"),ws("desc"))).value(Context::Description),
96            ws("optional").value(Context::Optional),
97            ws("info").value(Context::Info),
98            ws("hidden").value(Context::Hidden),
99            ws("reserved").value(Context::Reserved),
100            alt((ws("disabled"),ws("disable"))).value(Context::Disabled),
101            ws("hw").value(Context::HwAccess),
102            terminated(identifier, ".").map(|v| Context::Item(v.into())),
103        )),
104        opt(alt((ws(":"),ws("=")))),
105    ).context(StrContext::Label("register instance array property"))
106    .parse_next(input)
107}
108
109pub fn reg_inst_field_properties<'a>(input: &mut &'a str) -> Res<'a, Context> {
110    terminated(
111        alt((
112            alt((ws("description"),ws("desc"))).value(Context::Description),
113            ws("info").value(Context::Info),
114            ws("optional").value(Context::Optional),
115            ws("hidden").value(Context::Hidden),
116            ws("reserved").value(Context::Reserved),
117            alt((ws("disabled"),ws("disable"))).value(Context::Disabled),
118            alt((ws("reset"),ws("rst"))).value(Context::HwReset),
119            ws("limit").value(Context::Limit),
120        )),
121        opt(alt((ws(":"),ws("=")))),
122    ).context(StrContext::Label("register field property"))
123    .parse_next(input)
124}
125
126pub fn reg_inst_field_array<'a>(input: &mut &'a str) -> Res<'a, Context> {
127    (
128        identifier,
129        delimited(ws("["), val_u16, ws("].")),
130    ).map(|v| Context::FieldIndex((v.0.to_owned(),v.1)))
131    .context(StrContext::Label("register field array"))
132    .parse_next(input)
133}
134
135#[cfg(test)]
139mod tests_parsing {
140
141    use std::collections::HashMap;
142
143    use super::*;
144
145    #[test]
146    fn test_page_properties() {
147        assert_eq!(
148            page_properties(&mut "baseAddress : 0x240"),
149            Ok(Context::BaseAddress)
150        );
151        assert_eq!(page_properties(&mut "registers: "), Ok(Context::Registers));
152        assert_eq!(
153            page_properties(&mut "description: text with 9 and €"),
154            Ok(Context::Description)
155        );
156        assert_eq!(
157            page_properties(&mut "instances: auto "),
158            Ok(Context::Instances)
159        );
160    }
161
162    #[test]
163    fn test_is_auto() {
164        assert_eq!(is_auto("auto"), Ok(InstMode::Automatic));
165        assert_eq!(is_auto("auto-legacy"), Ok(InstMode::AutoLegacy));
166        assert_eq!(is_auto("  "), Ok(InstMode::Manual));
167        assert_eq!(is_auto("anything else").is_err(),true);
168    }
169
170    #[test]
172    fn test_reg_inst() {
173        assert_eq!(
174            reg_inst("- reg_name[4] = reg_type (reg_group) @ 0x10 "),
175            Ok(RegInst {
176                inst_name: "reg_name".to_owned(),
177                type_name: "reg_type".to_owned(),
178                group_name: "reg_group".to_owned(),
179                addr_kind: AddressKind::Absolute,
180                addr: 0x10,
181                array: parse_expr("4").expect("Parse 4 cannot fail"),
182                reg_override: HashMap::new(),
183            })
184        );
185        assert_eq!(
186            reg_inst("- reg_name @ 0x04"),
187            Ok(RegInst {
188                inst_name: "reg_name".to_owned(),
189                type_name: "reg_name".to_owned(),
190                group_name: "".to_owned(),
191                addr_kind: AddressKind::Absolute,
192                addr: 0x04,
193                array: ExprTokens::new(0),
194                reg_override: HashMap::new(),
195            })
196        );
197        assert_eq!(
198            reg_inst_field_array(&mut "idx[0].reset = 0"),
199            Ok(Context::FieldIndex(("idx".to_owned(),0)))
200        );
201    }
202}