manabrew_engine/card/
svar_cache.rs1use 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(¶ms) {
72 let api = params.get(record.prefix()).map(str::to_string);
73 ParsedSVarKind::Ability {
74 record,
75 api,
76 params: Params::from_parsed(¶ms),
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(¶ms),
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}