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