Skip to main content

wpl/ast/syntax/
tag.rs

1use std::collections::BTreeMap;
2use std::io::Write;
3
4use smol_str::SmolStr;
5use winnow::stream::Accumulate;
6
7use crate::ast::WplTag;
8use crate::ast::debug::{DebugFormat, DepIndent};
9use crate::parser::MergeTags;
10
11pub type TagKvs = BTreeMap<SmolStr, SmolStr>;
12pub type CopyRaw = (SmolStr, SmolStr);
13
14#[derive(Debug, PartialEq, Clone)]
15pub enum AnnEnum {
16    Tags(TagKvs),
17    Copy(CopyRaw),
18    CopyEventParse(SmolStr),
19    NoMatch,
20}
21#[derive(Debug, PartialEq, Default, Clone)]
22pub struct AnnFun {
23    pub tags: TagKvs,
24    pub copy_raw: Option<CopyRaw>,
25    pub copy_event_parse: Option<SmolStr>,
26    /// 显式声明:该 rule 不参与 parse_event 自动匹配(仅作 copy_event_parse 等显式调用的目标)。
27    pub no_match: bool,
28}
29
30impl MergeTags for AnnFun {
31    fn merge_tags(&mut self, other_tags: &Option<AnnFun>) {
32        if let Some(atags) = other_tags {
33            for (other_k, other_v) in &atags.tags {
34                if self.tags.get_mut(other_k).is_none() {
35                    self.tags.insert(other_k.clone(), other_v.clone());
36                }
37            }
38
39            if self.copy_raw.is_none() {
40                self.copy_raw = atags.copy_raw.clone()
41            }
42            if self.copy_event_parse.is_none() {
43                self.copy_event_parse = atags.copy_event_parse.clone()
44            }
45            // no_match 取并集:任一层声明即生效
46            self.no_match = self.no_match || atags.no_match;
47        }
48    }
49}
50
51impl AnnFun {
52    pub fn export_tags(&self) -> Vec<WplTag> {
53        let mut tags = Vec::new();
54        for (k, v) in &self.tags {
55            tags.push(WplTag::new(k.clone(), v.clone()))
56        }
57        tags
58    }
59}
60
61impl DebugFormat for AnnFun {
62    fn write<W>(&self, w: &mut W) -> std::io::Result<()>
63    where
64        W: ?Sized + Write + DepIndent,
65    {
66        write!(w, "#[tag")?;
67        let tag_count = self.tags.len();
68
69        for (index, t) in self.tags.iter().enumerate() {
70            if tag_count == 1 && index == 0 {
71                self.write_open_parenthesis(w)?;
72                write!(w, "{}:\"{}\"", t.0, t.1)?;
73                self.write_close_parenthesis(w)?;
74
75                write!(w, "]")?;
76                self.write_new_line(w)?;
77                return Ok(());
78            }
79            if index == 0 {
80                self.write_open_parenthesis(w)?;
81            }
82            write!(w, "{}:\"{}\"", t.0, t.1)?;
83
84            if index == tag_count - 1 {
85                self.write_close_parenthesis(w)?;
86            } else {
87                write!(w, ", ")?;
88            }
89        }
90
91        if let Some((ck, cv)) = &self.copy_raw {
92            write!(w, ", copy_raw")?;
93            self.write_open_parenthesis(w)?;
94            write!(w, "{}:\"{}\"", ck, cv)?;
95            self.write_close_parenthesis(w)?;
96        }
97        if let Some(rule) = &self.copy_event_parse {
98            write!(w, ", copy_event_parse")?;
99            self.write_open_parenthesis(w)?;
100            write!(w, "rule:\"{}\"", rule)?;
101            self.write_close_parenthesis(w)?;
102        }
103        if self.no_match {
104            write!(w, ", no_match")?;
105        }
106        write!(w, "]")?;
107        self.write_new_line(w)?;
108        Ok(())
109    }
110}
111
112impl Accumulate<()> for AnnFun {
113    fn initial(_: Option<usize>) -> Self {
114        AnnFun::default()
115    }
116
117    fn accumulate(&mut self, _acc: ()) {}
118}