graphix_compiler/expr/
mod.rs

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