graphix_compiler/expr/
mod.rs

1use crate::typ::{TVar, Type};
2use anyhow::Result;
3use arcstr::ArcStr;
4use combine::stream::position::SourcePosition;
5use futures::future::try_join_all;
6pub use modpath::ModPath;
7use netidx::{path::Path, subscriber::Value, utils::Either};
8pub use pattern::{Pattern, StructurePattern};
9use regex::Regex;
10pub use resolver::ModuleResolver;
11use serde::{
12    de::{self, Visitor},
13    Deserialize, Deserializer, Serialize, Serializer,
14};
15use std::{
16    cell::RefCell,
17    cmp::{Ordering, PartialEq, PartialOrd},
18    fmt,
19    path::PathBuf,
20    result,
21    str::FromStr,
22    sync::LazyLock,
23};
24use triomphe::Arc;
25
26mod modpath;
27pub mod parser;
28mod pattern;
29mod print;
30mod resolver;
31#[cfg(test)]
32mod test;
33
34pub static VNAME: LazyLock<Regex> =
35    LazyLock::new(|| Regex::new("^[a-z][a-z0-9_]*$").unwrap());
36
37atomic_id!(ExprId);
38
39#[derive(Debug, Clone, PartialEq, PartialOrd)]
40pub struct Arg {
41    pub labeled: Option<Option<Expr>>,
42    pub pattern: StructurePattern,
43    pub constraint: Option<Type>,
44}
45
46#[derive(Debug, Clone, PartialEq, PartialOrd)]
47pub enum ModuleKind {
48    Inline(Arc<[Expr]>),
49    Resolved(Origin),
50    Unresolved,
51}
52
53#[derive(Debug, Clone, PartialEq, PartialOrd)]
54pub struct Bind {
55    pub doc: Option<ArcStr>,
56    pub pattern: StructurePattern,
57    pub typ: Option<Type>,
58    pub export: bool,
59    pub value: Expr,
60}
61
62#[derive(Debug, Clone, PartialEq, PartialOrd)]
63pub struct Lambda {
64    pub args: Arc<[Arg]>,
65    pub vargs: Option<Option<Type>>,
66    pub rtype: Option<Type>,
67    pub constraints: Arc<[(TVar, Type)]>,
68    pub body: Either<Expr, ArcStr>,
69}
70
71#[derive(Debug, Clone, PartialEq, PartialOrd)]
72pub enum ExprKind {
73    Constant(Value),
74    Module { name: ArcStr, export: bool, value: ModuleKind },
75    Do { exprs: Arc<[Expr]> },
76    Use { name: ModPath },
77    Bind(Arc<Bind>),
78    Ref { name: ModPath },
79    Connect { name: ModPath, value: Arc<Expr>, deref: bool },
80    StringInterpolate { args: Arc<[Expr]> },
81    StructRef { source: Arc<Expr>, field: ArcStr },
82    TupleRef { source: Arc<Expr>, field: usize },
83    ArrayRef { source: Arc<Expr>, i: Arc<Expr> },
84    ArraySlice { source: Arc<Expr>, start: Option<Arc<Expr>>, end: Option<Arc<Expr>> },
85    StructWith { source: Arc<Expr>, replace: Arc<[(ArcStr, Expr)]> },
86    Lambda(Arc<Lambda>),
87    TypeDef { name: ArcStr, params: Arc<[(TVar, Option<Type>)]>, typ: Type },
88    TypeCast { expr: Arc<Expr>, typ: Type },
89    Apply { args: Arc<[(Option<ArcStr>, Expr)]>, function: Arc<Expr> },
90    Any { args: Arc<[Expr]> },
91    Array { args: Arc<[Expr]> },
92    Tuple { args: Arc<[Expr]> },
93    Variant { tag: ArcStr, args: Arc<[Expr]> },
94    Struct { args: Arc<[(ArcStr, Expr)]> },
95    Select { arg: Arc<Expr>, arms: Arc<[(Pattern, Expr)]> },
96    Qop(Arc<Expr>),
97    ByRef(Arc<Expr>),
98    Deref(Arc<Expr>),
99    Eq { lhs: Arc<Expr>, rhs: Arc<Expr> },
100    Ne { lhs: Arc<Expr>, rhs: Arc<Expr> },
101    Lt { lhs: Arc<Expr>, rhs: Arc<Expr> },
102    Gt { lhs: Arc<Expr>, rhs: Arc<Expr> },
103    Lte { lhs: Arc<Expr>, rhs: Arc<Expr> },
104    Gte { lhs: Arc<Expr>, rhs: Arc<Expr> },
105    And { lhs: Arc<Expr>, rhs: Arc<Expr> },
106    Or { lhs: Arc<Expr>, rhs: Arc<Expr> },
107    Not { expr: Arc<Expr> },
108    Add { lhs: Arc<Expr>, rhs: Arc<Expr> },
109    Sub { lhs: Arc<Expr>, rhs: Arc<Expr> },
110    Mul { lhs: Arc<Expr>, rhs: Arc<Expr> },
111    Div { lhs: Arc<Expr>, rhs: Arc<Expr> },
112    Mod { lhs: Arc<Expr>, rhs: Arc<Expr> },
113    Sample { lhs: Arc<Expr>, rhs: Arc<Expr> },
114}
115
116impl ExprKind {
117    pub fn to_expr(self, pos: SourcePosition) -> Expr {
118        Expr { id: ExprId::new(), pos, kind: self }
119    }
120
121    /// does not provide any position information or comment
122    pub fn to_expr_nopos(self) -> Expr {
123        Expr { id: ExprId::new(), pos: Default::default(), kind: self }
124    }
125}
126
127#[derive(Debug, Clone)]
128pub struct Expr {
129    pub id: ExprId,
130    pub pos: SourcePosition,
131    pub kind: ExprKind,
132}
133
134impl fmt::Display for Expr {
135    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
136        write!(f, "{}", self.kind)
137    }
138}
139
140impl PartialOrd for Expr {
141    fn partial_cmp(&self, rhs: &Expr) -> Option<Ordering> {
142        self.kind.partial_cmp(&rhs.kind)
143    }
144}
145
146impl PartialEq for Expr {
147    fn eq(&self, rhs: &Expr) -> bool {
148        self.kind.eq(&rhs.kind)
149    }
150}
151
152impl Eq for Expr {}
153
154impl Serialize for Expr {
155    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
156    where
157        S: Serializer,
158    {
159        serializer.serialize_str(&self.to_string())
160    }
161}
162
163impl Default for Expr {
164    fn default() -> Self {
165        ExprKind::Constant(Value::Null).to_expr(Default::default())
166    }
167}
168
169impl FromStr for Expr {
170    type Err = anyhow::Error;
171
172    fn from_str(s: &str) -> result::Result<Self, Self::Err> {
173        parser::parse_one(s)
174    }
175}
176
177#[derive(Clone, Copy)]
178struct ExprVisitor;
179
180impl<'de> Visitor<'de> for ExprVisitor {
181    type Value = Expr;
182
183    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
184        write!(formatter, "expected expression")
185    }
186
187    fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
188    where
189        E: de::Error,
190    {
191        Expr::from_str(s).map_err(de::Error::custom)
192    }
193
194    fn visit_borrowed_str<E>(self, s: &'de str) -> Result<Self::Value, E>
195    where
196        E: de::Error,
197    {
198        Expr::from_str(s).map_err(de::Error::custom)
199    }
200
201    fn visit_string<E>(self, s: String) -> Result<Self::Value, E>
202    where
203        E: de::Error,
204    {
205        Expr::from_str(&s).map_err(de::Error::custom)
206    }
207}
208
209impl<'de> Deserialize<'de> for Expr {
210    fn deserialize<D>(de: D) -> Result<Self, D::Error>
211    where
212        D: Deserializer<'de>,
213    {
214        de.deserialize_str(ExprVisitor)
215    }
216}
217
218impl Expr {
219    pub fn new(kind: ExprKind, pos: SourcePosition) -> Self {
220        Expr { id: ExprId::new(), pos, kind }
221    }
222
223    pub fn to_string_pretty(&self, col_limit: usize) -> String {
224        self.kind.to_string_pretty(col_limit)
225    }
226
227    /// fold over self and all of self's sub expressions
228    pub fn fold<T, F: FnMut(T, &Self) -> T>(&self, init: T, f: &mut F) -> T {
229        let init = f(init, self);
230        match &self.kind {
231            ExprKind::Constant(_)
232            | ExprKind::Use { .. }
233            | ExprKind::Ref { .. }
234            | ExprKind::StructRef { .. }
235            | ExprKind::TupleRef { .. }
236            | ExprKind::TypeDef { .. } => init,
237            ExprKind::Module { value: ModuleKind::Inline(e), .. } => {
238                e.iter().fold(init, |init, e| e.fold(init, f))
239            }
240            ExprKind::Module { value: ModuleKind::Resolved(o), .. } => {
241                o.exprs.iter().fold(init, |init, e| e.fold(init, f))
242            }
243            ExprKind::Module { value: ModuleKind::Unresolved, .. } => init,
244            ExprKind::Do { exprs } => exprs.iter().fold(init, |init, e| e.fold(init, f)),
245            ExprKind::Bind(b) => b.value.fold(init, f),
246            ExprKind::StructWith { replace, .. } => {
247                replace.iter().fold(init, |init, (_, e)| e.fold(init, f))
248            }
249            ExprKind::Connect { value, .. } => value.fold(init, f),
250            ExprKind::Lambda(l) => match &l.body {
251                Either::Left(e) => e.fold(init, f),
252                Either::Right(_) => init,
253            },
254            ExprKind::TypeCast { expr, .. } => expr.fold(init, f),
255            ExprKind::Apply { args, function: _ } => {
256                args.iter().fold(init, |init, (_, e)| e.fold(init, f))
257            }
258            ExprKind::Any { args }
259            | ExprKind::Array { args }
260            | ExprKind::Tuple { args }
261            | ExprKind::Variant { args, .. }
262            | ExprKind::StringInterpolate { args } => {
263                args.iter().fold(init, |init, e| e.fold(init, f))
264            }
265            ExprKind::ArrayRef { source, i } => {
266                let init = source.fold(init, f);
267                i.fold(init, f)
268            }
269            ExprKind::ArraySlice { source, start, end } => {
270                let init = source.fold(init, f);
271                let init = match start {
272                    None => init,
273                    Some(e) => e.fold(init, f),
274                };
275                match end {
276                    None => init,
277                    Some(e) => e.fold(init, f),
278                }
279            }
280            ExprKind::Struct { args } => {
281                args.iter().fold(init, |init, (_, e)| e.fold(init, f))
282            }
283            ExprKind::Select { arg, arms } => {
284                let init = arg.fold(init, f);
285                arms.iter().fold(init, |init, (p, e)| {
286                    let init = match p.guard.as_ref() {
287                        None => init,
288                        Some(g) => g.fold(init, f),
289                    };
290                    e.fold(init, f)
291                })
292            }
293            ExprKind::Qop(e)
294            | ExprKind::ByRef(e)
295            | ExprKind::Deref(e)
296            | ExprKind::Not { expr: e } => e.fold(init, f),
297            ExprKind::Add { lhs, rhs }
298            | ExprKind::Sub { lhs, rhs }
299            | ExprKind::Mul { lhs, rhs }
300            | ExprKind::Div { lhs, rhs }
301            | ExprKind::Mod { lhs, rhs }
302            | ExprKind::And { lhs, rhs }
303            | ExprKind::Or { lhs, rhs }
304            | ExprKind::Eq { lhs, rhs }
305            | ExprKind::Ne { lhs, rhs }
306            | ExprKind::Gt { lhs, rhs }
307            | ExprKind::Lt { lhs, rhs }
308            | ExprKind::Gte { lhs, rhs }
309            | ExprKind::Lte { lhs, rhs }
310            | ExprKind::Sample { lhs, rhs } => {
311                let init = lhs.fold(init, f);
312                rhs.fold(init, f)
313            }
314        }
315    }
316}
317
318#[derive(Debug, Clone, PartialEq, PartialOrd)]
319pub enum SourceOrigin {
320    File(PathBuf),
321    Netidx(Path),
322    Internal(ArcStr),
323    Unspecified,
324}
325
326// hallowed are the ori
327#[derive(Debug, Clone, PartialEq, PartialOrd)]
328pub struct Origin {
329    pub origin: SourceOrigin,
330    pub source: ArcStr,
331    pub exprs: Arc<[Expr]>,
332}
333
334impl fmt::Display for Origin {
335    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336        match &self.origin {
337            SourceOrigin::Unspecified => write!(f, "in expr {}", self.source),
338            SourceOrigin::File(n) => write!(f, "in file {n:?}"),
339            SourceOrigin::Netidx(n) => write!(f, "in netidx {n}"),
340            SourceOrigin::Internal(n) => write!(f, "in module {n}"),
341        }
342    }
343}
344
345impl Origin {
346    pub async fn resolve_modules(
347        self,
348        resolvers: &Arc<[ModuleResolver]>,
349    ) -> Result<Self> {
350        let exprs = Arc::from_iter(
351            try_join_all(self.exprs.iter().map(|e| e.resolve_modules(resolvers))).await?,
352        );
353        Ok(Self { exprs, ..self })
354    }
355}
356
357pub struct ErrorContext(pub Expr);
358
359impl fmt::Display for ErrorContext {
360    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361        use std::fmt::Write;
362        const MAX: usize = 38;
363        thread_local! {
364            static BUF: RefCell<String> = RefCell::new(String::new());
365        }
366        BUF.with_borrow_mut(|buf| {
367            buf.clear();
368            write!(buf, "{}", self.0).unwrap();
369            if buf.len() <= MAX {
370                write!(f, "at: {}, in: {buf}", self.0.pos)
371            } else {
372                let mut end = MAX;
373                while !buf.is_char_boundary(end) {
374                    end += 1
375                }
376                let buf = &buf[0..end];
377                write!(f, "at: {}, in: {buf}..", self.0.pos)
378            }
379        })
380    }
381}