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 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 rec: bool,
119 pub doc: Option<ArcStr>,
120 pub pattern: StructurePattern,
121 pub typ: Option<Type>,
122 pub export: bool,
123 pub value: Expr,
124}
125
126#[derive(Debug, Clone, PartialEq, PartialOrd)]
127pub struct Lambda {
128 pub args: Arc<[Arg]>,
129 pub vargs: Option<Option<Type>>,
130 pub rtype: Option<Type>,
131 pub constraints: Arc<[(TVar, Type)]>,
132 pub body: Either<Expr, ArcStr>,
133}
134
135#[derive(Debug, Clone, PartialEq, PartialOrd)]
136pub enum ExprKind {
137 Constant(Value),
138 Module { name: ArcStr, export: bool, value: ModuleKind },
139 Do { exprs: Arc<[Expr]> },
140 Use { name: ModPath },
141 Bind(Arc<Bind>),
142 Ref { name: ModPath },
143 Connect { name: ModPath, value: Arc<Expr>, deref: bool },
144 StringInterpolate { args: Arc<[Expr]> },
145 StructRef { source: Arc<Expr>, field: ArcStr },
146 TupleRef { source: Arc<Expr>, field: usize },
147 ArrayRef { source: Arc<Expr>, i: Arc<Expr> },
148 ArraySlice { source: Arc<Expr>, start: Option<Arc<Expr>>, end: Option<Arc<Expr>> },
149 StructWith { source: Arc<Expr>, replace: Arc<[(ArcStr, Expr)]> },
150 Lambda(Arc<Lambda>),
151 TypeDef(TypeDef),
152 TypeCast { expr: Arc<Expr>, typ: Type },
153 Apply { args: Arc<[(Option<ArcStr>, Expr)]>, function: Arc<Expr> },
154 Any { args: Arc<[Expr]> },
155 Array { args: Arc<[Expr]> },
156 Tuple { args: Arc<[Expr]> },
157 Variant { tag: ArcStr, args: Arc<[Expr]> },
158 Struct { args: Arc<[(ArcStr, Expr)]> },
159 Select { arg: Arc<Expr>, arms: Arc<[(Pattern, Expr)]> },
160 Qop(Arc<Expr>),
161 ByRef(Arc<Expr>),
162 Deref(Arc<Expr>),
163 Eq { lhs: Arc<Expr>, rhs: Arc<Expr> },
164 Ne { lhs: Arc<Expr>, rhs: Arc<Expr> },
165 Lt { lhs: Arc<Expr>, rhs: Arc<Expr> },
166 Gt { lhs: Arc<Expr>, rhs: Arc<Expr> },
167 Lte { lhs: Arc<Expr>, rhs: Arc<Expr> },
168 Gte { lhs: Arc<Expr>, rhs: Arc<Expr> },
169 And { lhs: Arc<Expr>, rhs: Arc<Expr> },
170 Or { lhs: Arc<Expr>, rhs: Arc<Expr> },
171 Not { expr: Arc<Expr> },
172 Add { lhs: Arc<Expr>, rhs: Arc<Expr> },
173 Sub { lhs: Arc<Expr>, rhs: Arc<Expr> },
174 Mul { lhs: Arc<Expr>, rhs: Arc<Expr> },
175 Div { lhs: Arc<Expr>, rhs: Arc<Expr> },
176 Mod { lhs: Arc<Expr>, rhs: Arc<Expr> },
177 Sample { lhs: Arc<Expr>, rhs: Arc<Expr> },
178}
179
180impl ExprKind {
181 pub fn to_expr(self, pos: SourcePosition) -> Expr {
182 Expr { id: ExprId::new(), ori: get_origin(), pos, kind: self }
183 }
184
185 pub fn to_expr_nopos(self) -> Expr {
187 Expr { id: ExprId::new(), ori: get_origin(), pos: Default::default(), kind: self }
188 }
189}
190
191#[derive(Debug, Clone, PartialEq, PartialOrd)]
192pub enum Source {
193 File(PathBuf),
194 Netidx(Path),
195 Internal(ArcStr),
196 Unspecified,
197}
198
199impl Default for Source {
200 fn default() -> Self {
201 Self::Unspecified
202 }
203}
204
205impl Source {
206 pub fn is_file(&self) -> bool {
207 match self {
208 Self::File(_) => true,
209 Self::Netidx(_) | Self::Internal(_) | Self::Unspecified => false,
210 }
211 }
212}
213
214#[derive(Debug, Clone, PartialEq, PartialOrd, Default)]
216pub struct Origin {
217 pub parent: Option<Arc<Origin>>,
218 pub source: Source,
219 pub text: ArcStr,
220}
221
222impl fmt::Display for Origin {
223 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224 let flags = PRINT_FLAGS.with(|f| f.get());
225 match &self.source {
226 Source::Unspecified => {
227 if flags.contains(PrintFlag::NoSource) {
228 write!(f, "in expr")?
229 } else {
230 write!(f, "in expr {}", self.text)?
231 }
232 }
233 Source::File(n) => write!(f, "in file {n:?}")?,
234 Source::Netidx(n) => write!(f, "in netidx {n}")?,
235 Source::Internal(n) => write!(f, "in module {n}")?,
236 }
237 let mut p = &self.parent;
238 if flags.contains(PrintFlag::NoParents) {
239 Ok(())
240 } else {
241 loop {
242 match p {
243 None => break Ok(()),
244 Some(parent) => {
245 writeln!(f, "")?;
246 write!(f, " ")?;
247 match &parent.source {
248 Source::Unspecified => {
249 if flags.contains(PrintFlag::NoSource) {
250 write!(f, "included from expr")?
251 } else {
252 write!(f, "included from expr {}", parent.text)?
253 }
254 }
255 Source::File(n) => write!(f, "included from file {n:?}")?,
256 Source::Netidx(n) => write!(f, "included from netidx {n}")?,
257 Source::Internal(n) => write!(f, "included from module {n}")?,
258 }
259 p = &parent.parent;
260 }
261 }
262 }
263 }
264 }
265}
266
267#[derive(Debug, Clone)]
268pub struct Expr {
269 pub id: ExprId,
270 pub ori: Arc<Origin>,
271 pub pos: SourcePosition,
272 pub kind: ExprKind,
273}
274
275impl fmt::Display for Expr {
276 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
277 write!(f, "{}", self.kind)
278 }
279}
280
281impl PartialOrd for Expr {
282 fn partial_cmp(&self, rhs: &Expr) -> Option<Ordering> {
283 self.kind.partial_cmp(&rhs.kind)
284 }
285}
286
287impl PartialEq for Expr {
288 fn eq(&self, rhs: &Expr) -> bool {
289 self.kind.eq(&rhs.kind)
290 }
291}
292
293impl Eq for Expr {}
294
295impl Serialize for Expr {
296 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
297 where
298 S: Serializer,
299 {
300 serializer.serialize_str(&self.to_string())
301 }
302}
303
304impl Default for Expr {
305 fn default() -> Self {
306 ExprKind::Constant(Value::Null).to_expr(Default::default())
307 }
308}
309
310impl FromStr for Expr {
311 type Err = anyhow::Error;
312
313 fn from_str(s: &str) -> result::Result<Self, Self::Err> {
314 parser::parse_one(s)
315 }
316}
317
318#[derive(Clone, Copy)]
319struct ExprVisitor;
320
321impl<'de> Visitor<'de> for ExprVisitor {
322 type Value = Expr;
323
324 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
325 write!(formatter, "expected expression")
326 }
327
328 fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
329 where
330 E: de::Error,
331 {
332 Expr::from_str(s).map_err(de::Error::custom)
333 }
334
335 fn visit_borrowed_str<E>(self, s: &'de str) -> Result<Self::Value, E>
336 where
337 E: de::Error,
338 {
339 Expr::from_str(s).map_err(de::Error::custom)
340 }
341
342 fn visit_string<E>(self, s: String) -> Result<Self::Value, E>
343 where
344 E: de::Error,
345 {
346 Expr::from_str(&s).map_err(de::Error::custom)
347 }
348}
349
350impl<'de> Deserialize<'de> for Expr {
351 fn deserialize<D>(de: D) -> Result<Self, D::Error>
352 where
353 D: Deserializer<'de>,
354 {
355 de.deserialize_str(ExprVisitor)
356 }
357}
358
359impl Expr {
360 pub fn new(kind: ExprKind, pos: SourcePosition) -> Self {
361 Expr { id: ExprId::new(), ori: get_origin(), pos, kind }
362 }
363
364 pub fn to_string_pretty(&self, col_limit: usize) -> String {
365 self.kind.to_string_pretty(col_limit)
366 }
367
368 pub fn fold<T, F: FnMut(T, &Self) -> T>(&self, init: T, f: &mut F) -> T {
370 let init = f(init, self);
371 match &self.kind {
372 ExprKind::Constant(_)
373 | ExprKind::Use { .. }
374 | ExprKind::Ref { .. }
375 | ExprKind::StructRef { .. }
376 | ExprKind::TupleRef { .. }
377 | ExprKind::TypeDef { .. } => init,
378 ExprKind::Module { value: ModuleKind::Inline(e), .. } => {
379 e.iter().fold(init, |init, e| e.fold(init, f))
380 }
381 ExprKind::Module { value: ModuleKind::Resolved(exprs), .. } => {
382 exprs.iter().fold(init, |init, e| e.fold(init, f))
383 }
384 ExprKind::Module {
385 value: ModuleKind::Dynamic { sandbox: _, sig: _, source },
386 ..
387 } => source.fold(init, f),
388 ExprKind::Module { value: ModuleKind::Unresolved, .. } => init,
389 ExprKind::Do { exprs } => exprs.iter().fold(init, |init, e| e.fold(init, f)),
390 ExprKind::Bind(b) => b.value.fold(init, f),
391 ExprKind::StructWith { replace, .. } => {
392 replace.iter().fold(init, |init, (_, e)| e.fold(init, f))
393 }
394 ExprKind::Connect { value, .. } => value.fold(init, f),
395 ExprKind::Lambda(l) => match &l.body {
396 Either::Left(e) => e.fold(init, f),
397 Either::Right(_) => init,
398 },
399 ExprKind::TypeCast { expr, .. } => expr.fold(init, f),
400 ExprKind::Apply { args, function: _ } => {
401 args.iter().fold(init, |init, (_, e)| e.fold(init, f))
402 }
403 ExprKind::Any { args }
404 | ExprKind::Array { args }
405 | ExprKind::Tuple { args }
406 | ExprKind::Variant { args, .. }
407 | ExprKind::StringInterpolate { args } => {
408 args.iter().fold(init, |init, e| e.fold(init, f))
409 }
410 ExprKind::ArrayRef { source, i } => {
411 let init = source.fold(init, f);
412 i.fold(init, f)
413 }
414 ExprKind::ArraySlice { source, start, end } => {
415 let init = source.fold(init, f);
416 let init = match start {
417 None => init,
418 Some(e) => e.fold(init, f),
419 };
420 match end {
421 None => init,
422 Some(e) => e.fold(init, f),
423 }
424 }
425 ExprKind::Struct { args } => {
426 args.iter().fold(init, |init, (_, e)| e.fold(init, f))
427 }
428 ExprKind::Select { arg, arms } => {
429 let init = arg.fold(init, f);
430 arms.iter().fold(init, |init, (p, e)| {
431 let init = match p.guard.as_ref() {
432 None => init,
433 Some(g) => g.fold(init, f),
434 };
435 e.fold(init, f)
436 })
437 }
438 ExprKind::Qop(e)
439 | ExprKind::ByRef(e)
440 | ExprKind::Deref(e)
441 | ExprKind::Not { expr: e } => e.fold(init, f),
442 ExprKind::Add { lhs, rhs }
443 | ExprKind::Sub { lhs, rhs }
444 | ExprKind::Mul { lhs, rhs }
445 | ExprKind::Div { lhs, rhs }
446 | ExprKind::Mod { lhs, rhs }
447 | ExprKind::And { lhs, rhs }
448 | ExprKind::Or { lhs, rhs }
449 | ExprKind::Eq { lhs, rhs }
450 | ExprKind::Ne { lhs, rhs }
451 | ExprKind::Gt { lhs, rhs }
452 | ExprKind::Lt { lhs, rhs }
453 | ExprKind::Gte { lhs, rhs }
454 | ExprKind::Lte { lhs, rhs }
455 | ExprKind::Sample { lhs, rhs } => {
456 let init = lhs.fold(init, f);
457 rhs.fold(init, f)
458 }
459 }
460 }
461}
462
463pub struct ErrorContext(pub Expr);
464
465impl fmt::Display for ErrorContext {
466 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
467 use std::fmt::Write;
468 const MAX: usize = 38;
469 thread_local! {
470 static BUF: RefCell<String> = RefCell::new(String::new());
471 }
472 BUF.with_borrow_mut(|buf| {
473 buf.clear();
474 write!(buf, "{}", self.0).unwrap();
475 if buf.len() <= MAX {
476 write!(f, "at: {}, in: {buf}", self.0.pos)
477 } else {
478 let mut end = MAX;
479 while !buf.is_char_boundary(end) {
480 end += 1
481 }
482 let buf = &buf[0..end];
483 write!(f, "at: {}, in: {buf}..", self.0.pos)
484 }
485 })
486 }
487}