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 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 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#[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}