1use crate::{
2 expr::print::{PrettyBuf, PrettyDisplay},
3 typ::{TVar, Type},
4 PrintFlag, PRINT_FLAGS,
5};
6use anyhow::Result;
7use arcstr::{literal, ArcStr};
8use combine::stream::position::SourcePosition;
9pub use modpath::ModPath;
10use netidx::{path::Path, subscriber::Value, utils::Either};
11pub use pattern::{Pattern, StructurePattern};
12use regex::Regex;
13pub use resolver::ModuleResolver;
14use serde::{
15 de::{self, Visitor},
16 Deserialize, Deserializer, Serialize, Serializer,
17};
18use std::{
19 cell::RefCell,
20 cmp::{Ordering, PartialEq, PartialOrd},
21 fmt,
22 ops::Deref,
23 path::PathBuf,
24 result,
25 str::FromStr,
26 sync::LazyLock,
27};
28use triomphe::Arc;
29
30mod modpath;
31pub mod parser;
32mod pattern;
33pub mod print;
34mod resolver;
35#[cfg(test)]
36mod test;
37
38pub const VNAME: LazyLock<Regex> =
39 LazyLock::new(|| Regex::new("^[a-z][a-z0-9_]*$").unwrap());
40
41atomic_id!(ExprId);
42
43const DEFAULT_ORIGIN: LazyLock<Arc<Origin>> =
44 LazyLock::new(|| Arc::new(Origin::default()));
45
46thread_local! {
47 static ORIGIN: RefCell<Option<Arc<Origin>>> = RefCell::new(None);
48}
49
50pub(crate) fn set_origin(ori: Arc<Origin>) {
51 ORIGIN.with_borrow_mut(|global| *global = Some(ori))
52}
53
54pub(crate) fn get_origin() -> Arc<Origin> {
55 ORIGIN.with_borrow(|ori| {
56 ori.as_ref().cloned().unwrap_or_else(|| DEFAULT_ORIGIN.clone())
57 })
58}
59
60#[derive(Debug)]
61pub struct CouldNotResolve(ArcStr);
62
63impl fmt::Display for CouldNotResolve {
64 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
65 write!(f, "could not resolve module {}", self.0)
66 }
67}
68
69#[derive(Debug, Clone, PartialEq, PartialOrd)]
70pub struct Arg {
71 pub labeled: Option<Option<Expr>>,
72 pub pattern: StructurePattern,
73 pub constraint: Option<Type>,
74}
75
76#[derive(Debug, Clone, PartialEq, PartialOrd)]
77pub struct Doc(pub Option<ArcStr>);
78
79#[derive(Debug, Clone, PartialEq, PartialOrd)]
80pub struct TypeDefExpr {
81 pub name: ArcStr,
82 pub params: Arc<[(TVar, Option<Type>)]>,
83 pub typ: Type,
84}
85
86#[derive(Debug, Clone, PartialEq, PartialOrd)]
87pub struct BindSig {
88 pub name: ArcStr,
89 pub typ: Type,
90}
91
92#[derive(Debug, Clone, PartialEq, PartialOrd)]
93pub enum SigKind {
94 TypeDef(TypeDefExpr),
95 Bind(BindSig),
96 Module(ArcStr),
97 Use(ModPath),
98}
99
100#[derive(Debug, Clone, PartialEq, PartialOrd)]
101pub struct SigItem {
102 pub doc: Doc,
103 pub kind: SigKind,
104}
105
106#[derive(Debug, Clone, PartialEq, PartialOrd)]
107pub struct Sig {
108 pub items: Arc<[SigItem]>,
109 pub toplevel: bool,
110}
111
112impl Deref for Sig {
113 type Target = [SigItem];
114
115 fn deref(&self) -> &Self::Target {
116 &*self.items
117 }
118}
119
120#[derive(Debug, Clone, PartialEq, PartialOrd)]
121pub enum Sandbox {
122 Unrestricted,
123 Blacklist(Arc<[ModPath]>),
124 Whitelist(Arc<[ModPath]>),
125}
126
127#[derive(Debug, Clone, PartialEq, PartialOrd)]
128pub enum ModuleKind {
129 Dynamic { sandbox: Sandbox, sig: Sig, source: Arc<Expr> },
130 Resolved { exprs: Arc<[Expr]>, sig: Option<Sig>, from_interface: bool },
131 Unresolved { from_interface: bool },
132}
133
134#[derive(Debug, Clone, PartialEq, PartialOrd)]
135pub struct BindExpr {
136 pub rec: bool,
137 pub pattern: StructurePattern,
138 pub typ: Option<Type>,
139 pub value: Expr,
140}
141
142#[derive(Debug, Clone, PartialEq, PartialOrd)]
143pub struct LambdaExpr {
144 pub args: Arc<[Arg]>,
145 pub vargs: Option<Option<Type>>,
146 pub rtype: Option<Type>,
147 pub constraints: Arc<[(TVar, Type)]>,
148 pub throws: Option<Type>,
149 pub body: Either<Expr, ArcStr>,
150}
151
152#[derive(Debug, Clone, PartialEq, PartialOrd)]
153pub struct TryCatchExpr {
154 pub bind: ArcStr,
155 pub constraint: Option<Type>,
156 pub handler: Arc<Expr>,
157 pub exprs: Arc<[Expr]>,
158}
159
160#[derive(Debug, Clone, PartialEq, PartialOrd)]
161pub struct StructWithExpr {
162 pub source: Arc<Expr>,
163 pub replace: Arc<[(ArcStr, Expr)]>,
164}
165
166#[derive(Debug, Clone, PartialEq, PartialOrd)]
167pub struct StructExpr {
168 pub args: Arc<[(ArcStr, Expr)]>,
169}
170
171#[derive(Debug, Clone, PartialEq, PartialOrd)]
172pub struct ApplyExpr {
173 pub args: Arc<[(Option<ArcStr>, Expr)]>,
174 pub function: Arc<Expr>,
175}
176
177#[derive(Debug, Clone, PartialEq, PartialOrd)]
178pub struct SelectExpr {
179 pub arg: Arc<Expr>,
180 pub arms: Arc<[(Pattern, Expr)]>,
181}
182
183#[derive(Debug, Clone, PartialEq, PartialOrd)]
184pub enum ExprKind {
185 NoOp,
186 Constant(Value),
187 Module { name: ArcStr, value: ModuleKind },
188 ExplicitParens(Arc<Expr>),
189 Do { exprs: Arc<[Expr]> },
190 Use { name: ModPath },
191 Bind(Arc<BindExpr>),
192 Ref { name: ModPath },
193 Connect { name: ModPath, value: Arc<Expr>, deref: bool },
194 StringInterpolate { args: Arc<[Expr]> },
195 StructRef { source: Arc<Expr>, field: ArcStr },
196 TupleRef { source: Arc<Expr>, field: usize },
197 ArrayRef { source: Arc<Expr>, i: Arc<Expr> },
198 ArraySlice { source: Arc<Expr>, start: Option<Arc<Expr>>, end: Option<Arc<Expr>> },
199 MapRef { source: Arc<Expr>, key: Arc<Expr> },
200 StructWith(StructWithExpr),
201 Lambda(Arc<LambdaExpr>),
202 TypeDef(TypeDefExpr),
203 TypeCast { expr: Arc<Expr>, typ: Type },
204 Apply(ApplyExpr),
205 Any { args: Arc<[Expr]> },
206 Array { args: Arc<[Expr]> },
207 Map { args: Arc<[(Expr, Expr)]> },
208 Tuple { args: Arc<[Expr]> },
209 Variant { tag: ArcStr, args: Arc<[Expr]> },
210 Struct(StructExpr),
211 Select(SelectExpr),
212 Qop(Arc<Expr>),
213 OrNever(Arc<Expr>),
214 TryCatch(Arc<TryCatchExpr>),
215 ByRef(Arc<Expr>),
216 Deref(Arc<Expr>),
217 Eq { lhs: Arc<Expr>, rhs: Arc<Expr> },
218 Ne { lhs: Arc<Expr>, rhs: Arc<Expr> },
219 Lt { lhs: Arc<Expr>, rhs: Arc<Expr> },
220 Gt { lhs: Arc<Expr>, rhs: Arc<Expr> },
221 Lte { lhs: Arc<Expr>, rhs: Arc<Expr> },
222 Gte { lhs: Arc<Expr>, rhs: Arc<Expr> },
223 And { lhs: Arc<Expr>, rhs: Arc<Expr> },
224 Or { lhs: Arc<Expr>, rhs: Arc<Expr> },
225 Not { expr: Arc<Expr> },
226 Add { lhs: Arc<Expr>, rhs: Arc<Expr> },
227 CheckedAdd { lhs: Arc<Expr>, rhs: Arc<Expr> },
228 Sub { lhs: Arc<Expr>, rhs: Arc<Expr> },
229 CheckedSub { lhs: Arc<Expr>, rhs: Arc<Expr> },
230 Mul { lhs: Arc<Expr>, rhs: Arc<Expr> },
231 CheckedMul { lhs: Arc<Expr>, rhs: Arc<Expr> },
232 Div { lhs: Arc<Expr>, rhs: Arc<Expr> },
233 CheckedDiv { lhs: Arc<Expr>, rhs: Arc<Expr> },
234 Mod { lhs: Arc<Expr>, rhs: Arc<Expr> },
235 CheckedMod { lhs: Arc<Expr>, rhs: Arc<Expr> },
236 Sample { lhs: Arc<Expr>, rhs: Arc<Expr> },
237}
238
239impl ExprKind {
240 pub fn to_expr(self, pos: SourcePosition) -> Expr {
241 Expr { id: ExprId::new(), ori: get_origin(), pos, kind: self }
242 }
243
244 pub fn to_expr_nopos(self) -> Expr {
246 Expr { id: ExprId::new(), ori: get_origin(), pos: Default::default(), kind: self }
247 }
248}
249
250#[derive(Debug, Clone, PartialEq, PartialOrd)]
251pub enum Source {
252 File(PathBuf),
253 Netidx(Path),
254 Internal(ArcStr),
255 Unspecified,
256}
257
258impl Default for Source {
259 fn default() -> Self {
260 Self::Unspecified
261 }
262}
263
264impl Source {
265 pub fn has_filename(&self, name: &str) -> bool {
266 match self {
267 Self::File(buf) => match buf.file_name() {
268 None => false,
269 Some(os) => match os.to_str() {
270 None => false,
271 Some(s) => s == name,
272 },
273 },
274 Self::Netidx(_) | Self::Internal(_) | Self::Unspecified => false,
275 }
276 }
277
278 pub fn is_file(&self) -> bool {
279 match self {
280 Self::File(_) => true,
281 Self::Netidx(_) | Self::Internal(_) | Self::Unspecified => false,
282 }
283 }
284
285 pub fn to_value(&self) -> Value {
286 match self {
287 Self::File(pb) => {
288 let s = pb.as_os_str().to_string_lossy();
289 (literal!("File"), ArcStr::from(s)).into()
290 }
291 Self::Netidx(p) => (literal!("Netidx"), p.clone()).into(),
292 Self::Internal(s) => (literal!("Internal"), s.clone()).into(),
293 Self::Unspecified => literal!("Unspecified").into(),
294 }
295 }
296}
297
298#[derive(Debug, Clone, PartialEq, PartialOrd, Default)]
300pub struct Origin {
301 pub parent: Option<Arc<Origin>>,
302 pub source: Source,
303 pub text: ArcStr,
304}
305
306impl fmt::Display for Origin {
307 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
308 let flags = PRINT_FLAGS.with(|f| f.get());
309 match &self.source {
310 Source::Unspecified => {
311 if flags.contains(PrintFlag::NoSource) {
312 write!(f, "in expr")?
313 } else {
314 write!(f, "in expr {}", self.text)?
315 }
316 }
317 Source::File(n) => write!(f, "in file {n:?}")?,
318 Source::Netidx(n) => write!(f, "in netidx {n}")?,
319 Source::Internal(n) => write!(f, "in module {n}")?,
320 }
321 let mut p = &self.parent;
322 if flags.contains(PrintFlag::NoParents) {
323 Ok(())
324 } else {
325 loop {
326 match p {
327 None => break Ok(()),
328 Some(parent) => {
329 writeln!(f, "")?;
330 write!(f, " ")?;
331 match &parent.source {
332 Source::Unspecified => {
333 if flags.contains(PrintFlag::NoSource) {
334 write!(f, "included from expr")?
335 } else {
336 write!(f, "included from expr {}", parent.text)?
337 }
338 }
339 Source::File(n) => write!(f, "included from file {n:?}")?,
340 Source::Netidx(n) => write!(f, "included from netidx {n}")?,
341 Source::Internal(n) => write!(f, "included from module {n}")?,
342 }
343 p = &parent.parent;
344 }
345 }
346 }
347 }
348 }
349}
350
351impl Origin {
352 pub fn to_value(&self) -> Value {
353 let p = Value::from(self.parent.as_ref().map(|p| p.to_value()));
354 [
355 (literal!("parent"), p),
356 (literal!("source"), self.source.to_value()),
357 (literal!("text"), Value::from(self.text.clone())),
358 ]
359 .into()
360 }
361}
362
363#[derive(Debug, Clone)]
364pub struct Expr {
365 pub id: ExprId,
366 pub ori: Arc<Origin>,
367 pub pos: SourcePosition,
368 pub kind: ExprKind,
369}
370
371impl fmt::Display for Expr {
372 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
373 write!(f, "{}", self.kind)
374 }
375}
376
377impl PrettyDisplay for Expr {
378 fn fmt_pretty_inner(&self, buf: &mut PrettyBuf) -> fmt::Result {
379 self.kind.fmt_pretty(buf)
380 }
381}
382
383impl PartialOrd for Expr {
384 fn partial_cmp(&self, rhs: &Expr) -> Option<Ordering> {
385 self.kind.partial_cmp(&rhs.kind)
386 }
387}
388
389impl PartialEq for Expr {
390 fn eq(&self, rhs: &Expr) -> bool {
391 self.kind.eq(&rhs.kind)
392 }
393}
394
395impl Eq for Expr {}
396
397impl Serialize for Expr {
398 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
399 where
400 S: Serializer,
401 {
402 serializer.serialize_str(&self.to_string())
403 }
404}
405
406impl Default for Expr {
407 fn default() -> Self {
408 ExprKind::Constant(Value::Null).to_expr(Default::default())
409 }
410}
411
412impl FromStr for Expr {
413 type Err = anyhow::Error;
414
415 fn from_str(s: &str) -> result::Result<Self, Self::Err> {
416 parser::parse_one(s)
417 }
418}
419
420#[derive(Clone, Copy)]
421struct ExprVisitor;
422
423impl<'de> Visitor<'de> for ExprVisitor {
424 type Value = Expr;
425
426 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
427 write!(formatter, "expected expression")
428 }
429
430 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
431 where
432 E: de::Error,
433 {
434 Expr::from_str(s).map_err(de::Error::custom)
435 }
436
437 fn visit_borrowed_str<E>(self, s: &'de str) -> Result<Self::Value, E>
438 where
439 E: de::Error,
440 {
441 Expr::from_str(s).map_err(de::Error::custom)
442 }
443
444 fn visit_string<E>(self, s: String) -> Result<Self::Value, E>
445 where
446 E: de::Error,
447 {
448 Expr::from_str(&s).map_err(de::Error::custom)
449 }
450}
451
452impl<'de> Deserialize<'de> for Expr {
453 fn deserialize<D>(de: D) -> Result<Self, D::Error>
454 where
455 D: Deserializer<'de>,
456 {
457 de.deserialize_str(ExprVisitor)
458 }
459}
460
461impl Expr {
462 pub fn new(kind: ExprKind, pos: SourcePosition) -> Self {
463 Expr { id: ExprId::new(), ori: get_origin(), pos, kind }
464 }
465
466 pub fn fold<T, F: FnMut(T, &Self) -> T>(&self, init: T, f: &mut F) -> T {
468 let init = f(init, self);
469 match &self.kind {
470 ExprKind::Constant(_)
471 | ExprKind::NoOp
472 | ExprKind::Use { .. }
473 | ExprKind::Ref { .. }
474 | ExprKind::TypeDef { .. } => init,
475 ExprKind::ExplicitParens(e) => e.fold(init, f),
476 ExprKind::StructRef { source, .. } | ExprKind::TupleRef { source, .. } => {
477 source.fold(init, f)
478 }
479
480 ExprKind::Map { args } => args.iter().fold(init, |init, (k, v)| {
481 let init = k.fold(init, f);
482 v.fold(init, f)
483 }),
484 ExprKind::MapRef { source, key } => {
485 let init = source.fold(init, f);
486 key.fold(init, f)
487 }
488 ExprKind::Module { value: ModuleKind::Resolved { exprs, .. }, .. } => {
489 exprs.iter().fold(init, |init, e| e.fold(init, f))
490 }
491 ExprKind::Module {
492 value: ModuleKind::Dynamic { sandbox: _, sig: _, source },
493 ..
494 } => source.fold(init, f),
495 ExprKind::Module { value: ModuleKind::Unresolved { .. }, .. } => init,
496 ExprKind::Do { exprs } => exprs.iter().fold(init, |init, e| e.fold(init, f)),
497 ExprKind::Bind(b) => b.value.fold(init, f),
498 ExprKind::StructWith(StructWithExpr { replace, .. }) => {
499 replace.iter().fold(init, |init, (_, e)| e.fold(init, f))
500 }
501 ExprKind::Connect { value, .. } => value.fold(init, f),
502 ExprKind::Lambda(l) => match &l.body {
503 Either::Left(e) => e.fold(init, f),
504 Either::Right(_) => init,
505 },
506 ExprKind::TypeCast { expr, .. } => expr.fold(init, f),
507 ExprKind::Apply(ApplyExpr { args, function: _ }) => {
508 args.iter().fold(init, |init, (_, e)| e.fold(init, f))
509 }
510 ExprKind::Any { args }
511 | ExprKind::Array { args }
512 | ExprKind::Tuple { args }
513 | ExprKind::Variant { args, .. }
514 | ExprKind::StringInterpolate { args } => {
515 args.iter().fold(init, |init, e| e.fold(init, f))
516 }
517 ExprKind::ArrayRef { source, i } => {
518 let init = source.fold(init, f);
519 i.fold(init, f)
520 }
521 ExprKind::ArraySlice { source, start, end } => {
522 let init = source.fold(init, f);
523 let init = match start {
524 None => init,
525 Some(e) => e.fold(init, f),
526 };
527 match end {
528 None => init,
529 Some(e) => e.fold(init, f),
530 }
531 }
532 ExprKind::Struct(StructExpr { args }) => {
533 args.iter().fold(init, |init, (_, e)| e.fold(init, f))
534 }
535 ExprKind::Select(SelectExpr { arg, arms }) => {
536 let init = arg.fold(init, f);
537 arms.iter().fold(init, |init, (p, e)| {
538 let init = match p.guard.as_ref() {
539 None => init,
540 Some(g) => g.fold(init, f),
541 };
542 e.fold(init, f)
543 })
544 }
545 ExprKind::TryCatch(tc) => {
546 let init = tc.exprs.iter().fold(init, |init, e| e.fold(init, f));
547 tc.handler.fold(init, f)
548 }
549 ExprKind::Qop(e)
550 | ExprKind::OrNever(e)
551 | ExprKind::ByRef(e)
552 | ExprKind::Deref(e)
553 | ExprKind::Not { expr: e } => e.fold(init, f),
554 ExprKind::Add { lhs, rhs }
555 | ExprKind::CheckedAdd { lhs, rhs }
556 | ExprKind::Sub { lhs, rhs }
557 | ExprKind::CheckedSub { lhs, rhs }
558 | ExprKind::Mul { lhs, rhs }
559 | ExprKind::CheckedMul { lhs, rhs }
560 | ExprKind::Div { lhs, rhs }
561 | ExprKind::CheckedDiv { lhs, rhs }
562 | ExprKind::Mod { lhs, rhs }
563 | ExprKind::CheckedMod { lhs, rhs }
564 | ExprKind::And { lhs, rhs }
565 | ExprKind::Or { lhs, rhs }
566 | ExprKind::Eq { lhs, rhs }
567 | ExprKind::Ne { lhs, rhs }
568 | ExprKind::Gt { lhs, rhs }
569 | ExprKind::Lt { lhs, rhs }
570 | ExprKind::Gte { lhs, rhs }
571 | ExprKind::Lte { lhs, rhs }
572 | ExprKind::Sample { lhs, rhs } => {
573 let init = lhs.fold(init, f);
574 rhs.fold(init, f)
575 }
576 }
577 }
578}
579
580pub struct ErrorContext(pub Expr);
581
582impl fmt::Display for ErrorContext {
583 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
584 use std::fmt::Write;
585 const MAX: usize = 38;
586 thread_local! {
587 static BUF: RefCell<String> = RefCell::new(String::new());
588 }
589 BUF.with_borrow_mut(|buf| {
590 buf.clear();
591 write!(buf, "{}", self.0).unwrap();
592 if buf.len() <= MAX {
593 write!(f, "at: {}, in: {buf}", self.0.pos)
594 } else {
595 let mut end = MAX;
596 while !buf.is_char_boundary(end) {
597 end += 1
598 }
599 let buf = &buf[0..end];
600 write!(f, "at: {}, in: {buf}..", self.0.pos)
601 }
602 })
603 }
604}