Skip to main content

fret_runtime/when_expr/
validate.rs

1use crate::capabilities::{CapabilityValueKind, capability_key_kind};
2
3use super::ast::Value;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
6pub enum WhenValueKind {
7    Bool,
8    Str,
9}
10
11impl From<CapabilityValueKind> for WhenValueKind {
12    fn from(value: CapabilityValueKind) -> Self {
13        match value {
14            CapabilityValueKind::Bool => Self::Bool,
15            CapabilityValueKind::Str => Self::Str,
16        }
17    }
18}
19
20#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
21pub enum WhenExprValidationError {
22    #[error("unknown identifier: {name}")]
23    UnknownIdentifier { name: String },
24    #[error("identifier must be boolean in this context: {name}")]
25    IdentifierNotBool { name: String },
26    #[error("string literal is not a boolean expression")]
27    StrUsedAsBool,
28    #[error("type mismatch in comparison: left={left:?} right={right:?}")]
29    ComparisonTypeMismatch {
30        left: WhenValueKind,
31        right: WhenValueKind,
32    },
33}
34
35pub(super) fn ident_kind(name: &str) -> Result<WhenValueKind, WhenExprValidationError> {
36    if name.starts_with("keyctx.") {
37        return Ok(WhenValueKind::Bool);
38    }
39
40    match name {
41        "ui.has_modal" | "focus.is_text_input" => return Ok(WhenValueKind::Bool),
42        "edit.can_undo" | "edit.can_redo" => return Ok(WhenValueKind::Bool),
43        "router.can_back" | "router.can_forward" => return Ok(WhenValueKind::Bool),
44        "platform" => return Ok(WhenValueKind::Str),
45        _ => {}
46    }
47
48    let key = name.strip_prefix("cap.").unwrap_or(name);
49    match capability_key_kind(key) {
50        Some(kind) => Ok(kind.into()),
51        None => Err(WhenExprValidationError::UnknownIdentifier {
52            name: name.to_string(),
53        }),
54    }
55}
56
57pub(super) fn value_kind(v: &Value) -> Result<WhenValueKind, WhenExprValidationError> {
58    match v {
59        Value::Bool(_) => Ok(WhenValueKind::Bool),
60        Value::Str(_) => Ok(WhenValueKind::Str),
61        Value::Ident(id) => ident_kind(id),
62    }
63}