sim_shape/primitives/combinators/
parser.rs1use std::sync::Arc;
4
5use sim_kernel::{Cx, Error, Expr, Result, Value};
6
7use crate::base::{Shape, ShapeDoc, ShapeMatch};
8
9pub trait ShapeExprParser: Send + Sync {
15 fn label(&self) -> &str;
17
18 fn is_effectful(&self) -> bool {
20 false
21 }
22
23 fn parse_expr(&self, source: &str) -> Result<Expr>;
25}
26
27pub struct PrattShape {
34 parser: Arc<dyn ShapeExprParser>,
35 inner: Arc<dyn Shape>,
36}
37
38impl PrattShape {
39 pub fn new(parser: Arc<dyn ShapeExprParser>, inner: Arc<dyn Shape>) -> Self {
41 Self { parser, inner }
42 }
43
44 pub fn parser(&self) -> &Arc<dyn ShapeExprParser> {
46 &self.parser
47 }
48
49 pub fn inner(&self) -> &Arc<dyn Shape> {
51 &self.inner
52 }
53}
54
55impl Shape for PrattShape {
56 fn is_effectful(&self) -> bool {
57 self.parser.is_effectful() || self.inner.is_effectful()
58 }
59
60 fn check_value(&self, cx: &mut Cx, value: Value) -> Result<ShapeMatch> {
61 let expr = value.object().as_expr(cx)?;
62 self.check_expr(cx, &expr)
63 }
64
65 fn check_expr(&self, cx: &mut Cx, expr: &Expr) -> Result<ShapeMatch> {
66 let source = match expr {
67 Expr::String(text) => text.as_str(),
68 _ => {
69 return Ok(ShapeMatch::reject(
70 "expected string expression for Pratt parse",
71 ));
72 }
73 };
74 let parsed = match self.parser.parse_expr(source) {
75 Ok(parsed) => parsed,
76 Err(Error::Eval(message)) => return Ok(ShapeMatch::reject(message)),
77 Err(other) => return Err(other),
78 };
79 self.inner.check_expr(cx, &parsed)
80 }
81
82 fn describe(&self, cx: &mut Cx) -> Result<ShapeDoc> {
83 let inner = self.inner.describe(cx)?;
84 Ok(ShapeDoc::new("pratt shape")
85 .with_detail(self.parser.label().to_owned())
86 .with_detail(inner.name))
87 }
88}