Skip to main content

manabrew_engine/card/
svar_cache.rs

1use std::collections::BTreeMap;
2
3use forge_card_script::{parse_script_svar_numeric_expression, OwnedSVarNumericExpression};
4
5use crate::ability::ability_factory::AbilityRecordType;
6use crate::parsing::{Params, ParsedParams};
7
8#[derive(Debug, Clone)]
9pub struct ParsedSVar {
10    pub raw: String,
11    pub kind: ParsedSVarKind,
12}
13
14#[derive(Debug, Clone)]
15pub enum ParsedSVarKind {
16    Ability {
17        record: AbilityRecordType,
18        api: Option<String>,
19        params: Params,
20    },
21    NumericExpression {
22        expression: OwnedSVarNumericExpression,
23    },
24    ParamRecord {
25        params: Params,
26    },
27    Number {
28        value: String,
29    },
30    Count {
31        raw: String,
32    },
33    Raw {
34        value: String,
35    },
36}
37
38#[derive(Debug, Clone, Default)]
39pub struct ParsedSVarCache {
40    entries: BTreeMap<String, ParsedSVar>,
41}
42
43impl ParsedSVarCache {
44    pub fn get_or_parse(&mut self, name: &str, raw: &str) -> &ParsedSVar {
45        let needs_parse = self
46            .entries
47            .get(name)
48            .is_none_or(|cached| cached.raw != raw);
49        if needs_parse {
50            self.entries
51                .insert(name.to_string(), ParsedSVar::parse(raw));
52        }
53        self.entries
54            .get(name)
55            .expect("parsed SVar cache entry inserted before lookup")
56    }
57
58    pub fn remove(&mut self, name: &str) {
59        self.entries.remove(name);
60    }
61
62    pub fn clear(&mut self) {
63        self.entries.clear();
64    }
65}
66
67impl ParsedSVar {
68    pub fn parse(raw: &str) -> Self {
69        let trimmed = raw.trim();
70        let params = ParsedParams::parse(trimmed);
71        let kind = if let Some(record) = AbilityRecordType::from_parsed(&params) {
72            let api = params.get(record.prefix()).map(str::to_string);
73            ParsedSVarKind::Ability {
74                record,
75                api,
76                params: Params::from_parsed(&params),
77            }
78        } else if let Some(expression) = parse_script_svar_numeric_expression(trimmed) {
79            match expression.to_owned_expression() {
80                OwnedSVarNumericExpression::Number(value) => ParsedSVarKind::Number { value },
81                OwnedSVarNumericExpression::Count(raw) => ParsedSVarKind::Count { raw },
82                expression => ParsedSVarKind::NumericExpression { expression },
83            }
84        } else if trimmed.contains('$') {
85            ParsedSVarKind::ParamRecord {
86                params: Params::from_parsed(&params),
87            }
88        } else {
89            ParsedSVarKind::Raw {
90                value: trimmed.to_string(),
91            }
92        };
93
94        Self {
95            raw: trimmed.to_string(),
96            kind,
97        }
98    }
99}