Skip to main content

ferrobridge_fhirpath/
expression.rs

1// SPDX-FileCopyrightText: Cadasto B.V.
2// SPDX-License-Identifier: BUSL-1.1
3
4//! A parsed expression: parsed once, then checked and evaluated many times.
5
6use std::fmt;
7use std::str::FromStr;
8
9use crate::ast::Expr;
10use crate::check::{SemanticError, check, check_any};
11use crate::eval::error::EvalError;
12use crate::eval::{Environment, Focus, evaluate};
13use crate::model::{FhirType, Model};
14use crate::parse::{ParseError, parse};
15use crate::value::Collection;
16
17/// A FHIRPath expression, parsed.
18#[derive(Debug, Clone, PartialEq, Eq)]
19pub struct Expression {
20    source: String,
21    tree: Expr,
22}
23
24impl Expression {
25    /// Parses `text`.
26    ///
27    /// # Errors
28    ///
29    /// Returns [`ParseError`] when `text` is no N1 expression.
30    pub fn parse(text: &str) -> Result<Self, ParseError> {
31        Ok(Self {
32            source: String::from(text),
33            tree: parse(text)?,
34        })
35    }
36
37    /// The text the expression was parsed from.
38    #[must_use]
39    pub fn source(&self) -> &str {
40        &self.source
41    }
42
43    /// The syntax tree.
44    #[must_use]
45    pub const fn tree(&self) -> &Expr {
46        &self.tree
47    }
48
49    /// Checks the expression against the type its context will have: every
50    /// member a path names must be one the types along the path define, and
51    /// a path that starts with a type name must start with the context's (N1
52    /// §3, §11).
53    ///
54    /// # Errors
55    ///
56    /// Returns [`SemanticError`] for the first member or type name the model
57    /// refuses.
58    pub fn check(&self, model: &dyn Model, context: FhirType) -> Result<(), SemanticError> {
59        check(&self.tree, model, context)
60    }
61
62    /// Checks the expression against a context that may hold any of the
63    /// types `contexts`, as an occurrence of a choice element does (R4
64    /// §2.9.1.1, [`crate::model::path_types`]): a member is accepted when one
65    /// of them defines it, and refused when none does.
66    ///
67    /// # Errors
68    ///
69    /// Returns [`SemanticError`] for the first member or type name the model
70    /// refuses.
71    pub fn check_any(&self, model: &dyn Model, contexts: &[FhirType]) -> Result<(), SemanticError> {
72        check_any(&self.tree, model, contexts)
73    }
74
75    /// Evaluates the expression in `env` on `focus`.
76    ///
77    /// # Errors
78    ///
79    /// Returns [`EvalError`] when the evaluation signals an error; an empty
80    /// result is `Ok` with an empty collection.
81    pub fn evaluate<'a>(
82        &self,
83        env: &Environment<'a>,
84        focus: Focus<'a>,
85    ) -> Result<Collection<'a>, EvalError> {
86        evaluate(&self.tree, env, focus)
87    }
88}
89
90impl FromStr for Expression {
91    type Err = ParseError;
92
93    fn from_str(text: &str) -> Result<Self, Self::Err> {
94        Self::parse(text)
95    }
96}
97
98impl fmt::Display for Expression {
99    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100        f.write_str(&self.source)
101    }
102}