Skip to main content

manabrew_engine/parsing/
amount.rs

1#[derive(Debug, Clone, PartialEq, Eq)]
2pub enum AmountExpr {
3    Literal(i32),
4    X,
5    SVar(String),
6    Raw(String),
7}
8
9impl AmountExpr {
10    pub fn from_semantic(amount: &crate::parsing::SemanticAmount<'_>) -> Self {
11        match amount {
12            crate::parsing::SemanticAmount::Literal(value) => Self::Literal(*value),
13            crate::parsing::SemanticAmount::X => Self::X,
14            crate::parsing::SemanticAmount::SVar(name) => Self::SVar((*name).to_string()),
15            crate::parsing::SemanticAmount::Any
16            | crate::parsing::SemanticAmount::All
17            | crate::parsing::SemanticAmount::Expression(_) => Self::Raw(amount_to_raw(amount)),
18        }
19    }
20
21    pub fn parse(raw: &str) -> Self {
22        let trimmed = raw.trim();
23        if let Ok(value) = trimmed.parse::<i32>() {
24            Self::Literal(value)
25        } else if trimmed == "X" {
26            Self::X
27        } else if trimmed.is_empty() {
28            Self::Raw(String::new())
29        } else if is_svar_name(trimmed) {
30            Self::SVar(trimmed.to_string())
31        } else {
32            Self::Raw(trimmed.to_string())
33        }
34    }
35
36    pub fn resolve_for_spell_ability(
37        &self,
38        game: &crate::game::GameState,
39        sa: &crate::spellability::SpellAbility,
40        default: i32,
41    ) -> i32 {
42        match self {
43            Self::Literal(value) => *value,
44            Self::X => crate::svar::resolve_numeric_value(game, sa, "X", default),
45            Self::SVar(name) | Self::Raw(name) => {
46                crate::svar::resolve_numeric_value(game, sa, name, default)
47            }
48        }
49    }
50}
51
52fn amount_to_raw(amount: &crate::parsing::SemanticAmount<'_>) -> String {
53    match amount {
54        crate::parsing::SemanticAmount::Literal(value) => value.to_string(),
55        crate::parsing::SemanticAmount::X => "X".to_string(),
56        crate::parsing::SemanticAmount::Any => "Any".to_string(),
57        crate::parsing::SemanticAmount::All => "All".to_string(),
58        crate::parsing::SemanticAmount::SVar(name)
59        | crate::parsing::SemanticAmount::Expression(name) => (*name).to_string(),
60    }
61}
62
63fn is_svar_name(raw: &str) -> bool {
64    let mut chars = raw.chars();
65    let Some(first) = chars.next() else {
66        return false;
67    };
68    (first == '_' || first.is_ascii_alphabetic())
69        && chars.all(|c| c == '_' || c.is_ascii_alphanumeric())
70}