summaryrefslogtreecommitdiff
path: root/serde_dhall/src/value.rs
blob: a24f2112134410cbc295577bc066b498e0b82700 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use dhall::semantics::Hir;
use dhall::syntax::Expr;
use dhall::{Normalized, Parsed};

use crate::simple::{SimpleType, SimpleValue};
use crate::Error;

/// A Dhall value.
#[derive(Debug, Clone)]
pub struct Value {
    /// Invariant: in normal form
    pub(crate) hir: Hir,
    /// Cached conversions because they are annoying to construct from Hir.
    /// At most one of them will be `Some`.
    pub(crate) as_simple_val: Option<SimpleValue>,
    pub(crate) as_simple_ty: Option<SimpleType>,
}

impl Value {
    /// Parse a string into a Value, and optionally ensure that the value matches the provided type
    /// annotation.
    pub fn from_str_with_annot(
        s: &str,
        ty: Option<&Self>,
    ) -> Result<Self, Error> {
        Self::from_str_with_annot_dhall_error(s, ty).map_err(Error::Dhall)
    }
    fn from_normalized(x: &Normalized) -> Self {
        Value {
            hir: x.to_hir(),
            as_simple_val: SimpleValue::from_nir(x.as_nir()),
            as_simple_ty: SimpleType::from_nir(x.as_nir()),
        }
    }

    fn from_str_with_annot_dhall_error(
        s: &str,
        ty: Option<&Self>,
    ) -> Result<Self, dhall::error::Error> {
        let resolved = Parsed::parse_str(s)?.resolve()?;
        let typed = match ty {
            None => resolved.typecheck()?,
            Some(ty) => resolved.typecheck_with(&ty.hir)?,
        };
        Ok(Self::from_normalized(&typed.normalize()))
    }

    /// Converts a Value into a SimpleValue.
    pub fn to_simple_value(&self) -> Option<SimpleValue> {
        self.as_simple_val.clone()
    }
    /// Converts a Value into a SimpleType.
    pub fn to_simple_type(&self) -> Option<SimpleType> {
        self.as_simple_ty.clone()
    }

    /// Converts a value back to the corresponding AST expression.
    pub fn to_expr(&self) -> Expr {
        self.hir.to_expr(Default::default())
    }
}

impl Eq for Value {}
impl PartialEq for Value {
    fn eq(&self, other: &Self) -> bool {
        self.hir == other.hir
    }
}
impl std::fmt::Display for Value {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
        self.to_expr().fmt(f)
    }
}