graphix_compiler/expr/
mod.rs

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