fret_runtime/when_expr/
validate.rs1use 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}