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