Skip to main content

wpl/ast/rule/
types.rs

1use std::{
2    collections::VecDeque,
3    fmt::{Display, Formatter},
4    io::Write,
5};
6
7use contracts::debug_requires;
8use derive_getters::Getters;
9use smol_str::SmolStr;
10
11use crate::{
12    ast::{
13        AnnFun, WplField,
14        debug::{DebugFormat, DepIndent},
15        group::WplGroup,
16    },
17    compat::New1,
18    parser::MergeTags,
19};
20
21#[derive(Default, Clone, Getters, Debug)]
22pub struct WplRule {
23    pub name: SmolStr,
24    pub statement: WplStatementType,
25}
26
27#[derive(Debug, PartialEq, Clone)]
28pub enum WplStatementType {
29    Express(WplExpress),
30}
31
32impl DebugFormat for WplStatementType {
33    fn write<W>(&self, w: &mut W) -> std::io::Result<()>
34    where
35        W: ?Sized + Write + DepIndent,
36    {
37        match self {
38            WplStatementType::Express(define) => define.write(w),
39        }
40    }
41}
42
43impl Display for WplStatementType {
44    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
45        write!(f, "{}", self.fmt_string().unwrap_or_default())
46    }
47}
48
49impl Default for WplStatementType {
50    fn default() -> Self {
51        WplStatementType::Express(WplExpress::default())
52    }
53}
54
55/*
56impl From<Vec<WPLField>> for WPLStatement {
57    fn from(fields: Vec<WPLField>) -> Self {
58        WPLStatement::Express(STMExpress::new(fields))
59    }
60}
61
62 */
63
64impl WplStatementType {
65    pub fn first_group(&self) -> Option<&WplGroup> {
66        match self {
67            WplStatementType::Express(rule) => rule.group.first(),
68        }
69    }
70    pub fn first_field(&self) -> Option<&WplField> {
71        match self {
72            WplStatementType::Express(rule) => rule.group.first().and_then(|x| x.first()),
73        }
74    }
75
76    pub fn tags(&self) -> &Option<AnnFun> {
77        match self {
78            WplStatementType::Express(rule) => &rule.tags,
79        }
80    }
81}
82
83#[derive(Default, Debug, PartialEq, Clone)]
84pub struct WplExpress {
85    // 管道预处理
86    pub pipe_process: Vec<SmolStr>,
87    pub group: Vec<WplGroup>,
88    pub tags: Option<AnnFun>,
89}
90
91impl MergeTags for WplExpress {
92    fn merge_tags(&mut self, other_tags: &Option<AnnFun>) {
93        if let Some(tags) = &mut self.tags {
94            tags.merge_tags(other_tags)
95        } else {
96            self.tags = other_tags.clone()
97        }
98    }
99}
100
101impl Display for WplExpress {
102    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
103        write!(f, "{}", self.fmt_string().unwrap_or_default())
104    }
105}
106
107impl DebugFormat for WplExpress {
108    fn write<W>(&self, w: &mut W) -> std::io::Result<()>
109    where
110        W: ?Sized + Write + DepIndent,
111    {
112        let depth = w.add_indent();
113        for (index, pipe) in self.pipe_process.iter().enumerate() {
114            if index == 0 {
115                self.write_indent(w, depth)?;
116                write!(w, "|")?;
117            }
118            write!(w, "{}|", pipe)?;
119        }
120
121        for (index, field) in self.group.iter().enumerate() {
122            if index != 0 {
123                write!(w, ",")?;
124                self.write_new_line(w)?;
125            }
126            self.write_indent(w, depth)?;
127            field.write(w)?;
128        }
129        w.sub_indent();
130        Ok(())
131    }
132}
133
134impl New1<Vec<WplGroup>> for WplExpress {
135    fn new(group: Vec<WplGroup>) -> Self {
136        WplExpress {
137            pipe_process: Vec::new(),
138            group,
139            tags: None,
140        }
141    }
142}
143
144impl New1<Vec<WplField>> for WplExpress {
145    fn new(fields: Vec<WplField>) -> Self {
146        let group = vec![WplGroup::new(fields)];
147        WplExpress {
148            pipe_process: Vec::new(),
149            group,
150            tags: None,
151        }
152    }
153}
154
155impl WplRule {
156    pub fn add_tags(mut self, tags: Option<AnnFun>) -> Self {
157        match self.statement {
158            WplStatementType::Express(mut define) => {
159                define.tags = tags;
160                self.statement = WplStatementType::Express(define);
161                self
162            }
163        }
164    }
165}
166
167impl DebugFormat for WplRule {
168    fn write<W>(&self, w: &mut W) -> std::io::Result<()>
169    where
170        W: ?Sized + Write + DepIndent,
171    {
172        let depth = w.add_indent();
173
174        if let Some(tags) = &self.statement.tags() {
175            self.write_indent(w, depth)?;
176            tags.write(w)?;
177        }
178        self.write_indent(w, depth)?;
179
180        write!(w, "rule {} ", &self.name)?;
181        self.write_open_brace(w)?;
182        self.write_new_line(w)?;
183        self.statement.write(w)?;
184        self.write_new_line(w)?;
185        self.write_indent(w, depth)?;
186        self.write_close_brace(w)?;
187        w.sub_indent();
188        Ok(())
189    }
190}
191
192impl Display for WplRule {
193    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
194        write!(f, "{}", self.fmt_string().unwrap_or_default())
195    }
196}
197
198impl PartialEq for WplRule {
199    fn eq(&self, other: &Self) -> bool {
200        self.name == other.name && self.statement == other.statement
201    }
202}
203
204impl WplRule {
205    #[debug_requires(! name.is_empty(), "lang rule name is empty")]
206    pub fn new(name: String, rule: WplStatementType) -> Self {
207        WplRule {
208            name: SmolStr::from(name),
209            statement: rule,
210        }
211    }
212
213    pub fn get_name(&self) -> &SmolStr {
214        &self.name
215    }
216    pub fn path(&self, pkg_name: &str) -> String {
217        format!("{}/{}", pkg_name, self.get_name())
218    }
219}
220
221impl MergeTags for VecDeque<WplRule> {
222    fn merge_tags(&mut self, other_tags: &Option<AnnFun>) {
223        for r in self.iter_mut() {
224            match &mut r.statement {
225                WplStatementType::Express(define) => {
226                    if let Some(tags) = &mut define.tags {
227                        tags.merge_tags(other_tags);
228                    } else {
229                        define.tags = other_tags.clone()
230                    }
231                }
232            }
233        }
234    }
235}
236
237#[test]
238fn test_lang_rule() {
239    let rule = WplRule {
240        statement: WplStatementType::Express(WplExpress {
241            pipe_process: vec![SmolStr::from("decode/base64"), SmolStr::from("zip")],
242            group: vec![],
243            tags: None,
244        }),
245        name: SmolStr::from("hello"),
246    };
247    assert_eq!(
248        rule.to_string(),
249        "  rule hello {\n    |decode/base64|zip|\n  }"
250    );
251}