1use crate::semantics::Value;
4use std::cell::RefCell;
5use std::collections::HashMap;
6use std::rc::Rc;
7
8#[derive(Debug, Clone, Copy, PartialEq)]
11pub struct Loc {
12 pub sl: usize,
13 pub sc: usize,
14 pub el: usize,
15 pub ec: usize,
16}
17
18thread_local! {
23 static EXPR_LOCS: RefCell<HashMap<usize, Loc>> = RefCell::new(HashMap::new());
24}
25fn expr_key(e: &Rc<Expr>) -> usize {
26 Rc::as_ptr(e) as *const u8 as usize
27}
28pub fn set_expr_loc(e: &Rc<Expr>, loc: Loc) {
29 EXPR_LOCS.with(|t| t.borrow_mut().insert(expr_key(e), loc));
30}
31pub fn expr_loc(e: &Rc<Expr>) -> Option<Loc> {
32 EXPR_LOCS.with(|t| t.borrow().get(&expr_key(e)).copied())
33}
34
35#[derive(Debug, Clone)]
36pub enum TypeAst {
37 Prim {
38 name: String,
39 loc: Option<Loc>,
40 },
41 Lit {
42 v: Value,
43 loc: Option<Loc>,
44 },
45 Range {
46 lo: Value,
47 hi: Value,
48 excl: bool,
49 loc: Option<Loc>,
50 },
51 Pattern {
52 re: String,
53 loc: Option<Loc>,
54 },
55 Record {
56 members: Vec<MemberAst>,
57 open: bool,
58 loc: Option<Loc>,
59 },
60 Map {
61 key: Box<TypeAst>,
62 val: Box<TypeAst>,
63 loc: Option<Loc>,
64 },
65 Array {
66 elem: Box<TypeAst>,
67 lo: Option<Value>,
68 hi: Option<Value>,
69 excl: bool,
70 loc: Option<Loc>,
71 },
72 Union {
73 arms: Vec<TypeAst>,
74 loc: Option<Loc>,
75 },
76 Isect {
77 arms: Vec<TypeAst>,
78 loc: Option<Loc>,
79 },
80 Func {
81 params: Vec<TypeAst>,
82 ret: Box<TypeAst>,
83 loc: Option<Loc>,
84 },
85 Named {
86 name: String,
87 args: Vec<TypeAst>,
88 preds: Option<Vec<Rc<Expr>>>,
89 ext: Option<Box<TypeAst>>,
90 loc: Option<Loc>,
91 },
92}
93impl TypeAst {
94 pub fn loc(&self) -> Option<Loc> {
95 match self {
96 TypeAst::Prim { loc, .. }
97 | TypeAst::Lit { loc, .. }
98 | TypeAst::Range { loc, .. }
99 | TypeAst::Pattern { loc, .. }
100 | TypeAst::Record { loc, .. }
101 | TypeAst::Map { loc, .. }
102 | TypeAst::Array { loc, .. }
103 | TypeAst::Union { loc, .. }
104 | TypeAst::Isect { loc, .. }
105 | TypeAst::Func { loc, .. }
106 | TypeAst::Named { loc, .. } => *loc,
107 }
108 }
109 pub fn set_loc(&mut self, l: Loc) {
110 match self {
111 TypeAst::Prim { loc, .. }
112 | TypeAst::Lit { loc, .. }
113 | TypeAst::Range { loc, .. }
114 | TypeAst::Pattern { loc, .. }
115 | TypeAst::Record { loc, .. }
116 | TypeAst::Map { loc, .. }
117 | TypeAst::Array { loc, .. }
118 | TypeAst::Union { loc, .. }
119 | TypeAst::Isect { loc, .. }
120 | TypeAst::Func { loc, .. }
121 | TypeAst::Named { loc, .. } => *loc = Some(l),
122 }
123 }
124}
125
126#[derive(Debug, Clone)]
127pub enum MemberAst {
128 Value {
129 name: String,
130 opt: bool,
131 ty: TypeAst,
132 dflt: Option<Rc<Expr>>,
133 loc: Option<Loc>,
134 },
135 Derived {
137 name: String,
138 ty: Option<TypeAst>,
139 expr: Rc<Expr>,
140 hidden: bool,
141 loc: Option<Loc>,
142 },
143 Context {
144 variable: String,
145 ty: TypeAst,
146 loc: Option<Loc>,
147 },
148 Assert {
149 name: String,
150 cond: Rc<Expr>,
151 tail: Option<Tail>,
152 loc: Option<Loc>,
153 },
154 When {
155 cond: Rc<Expr>,
156 body: Vec<MemberAst>,
157 loc: Option<Loc>,
158 },
159}
160impl MemberAst {
161 pub fn loc(&self) -> Option<Loc> {
162 match self {
163 MemberAst::Value { loc, .. }
164 | MemberAst::Derived { loc, .. }
165 | MemberAst::Context { loc, .. }
166 | MemberAst::Assert { loc, .. }
167 | MemberAst::When { loc, .. } => *loc,
168 }
169 }
170 pub fn set_loc(&mut self, l: Loc) {
171 match self {
172 MemberAst::Value { loc, .. }
173 | MemberAst::Derived { loc, .. }
174 | MemberAst::Context { loc, .. }
175 | MemberAst::Assert { loc, .. }
176 | MemberAst::When { loc, .. } => *loc = Some(l),
177 }
178 }
179 pub fn name(&self) -> Option<&str> {
181 match self {
182 MemberAst::Value { name, .. }
183 | MemberAst::Derived { name, .. }
184 | MemberAst::Assert { name, .. } => Some(name),
185 _ => None,
186 }
187 }
188}
189
190#[derive(Debug, Clone)]
191pub enum TPart {
192 Text(String),
193 Expr(Rc<Expr>),
194}
195
196#[derive(Debug, Clone)]
197pub enum Tail {
198 Inline {
199 severity: String,
200 template: Vec<TPart>,
201 },
202 Ref {
203 name: String,
204 args: Vec<Rc<Expr>>,
205 },
206}
207
208#[derive(Debug, Clone)]
209pub struct ForClause {
210 pub v: String,
211 pub iter: Rc<Expr>,
212 pub filters: Vec<Rc<Expr>>,
213}
214
215#[derive(Debug, Clone)]
216pub struct MatchArm {
217 pub v: String,
218 pub ty: Option<TypeAst>,
219 pub body: Rc<Expr>,
220}
221
222#[derive(Debug, Clone)]
223pub enum Expr {
224 Lit(Value),
225 UnitLit {
226 num: f64,
227 unit: String,
228 },
229 Template(Vec<TPart>),
230 Name(String),
231 Ctx(String),
232 Referrers {
233 ty: String,
234 member: String,
235 },
236 Obj(Vec<(String, Rc<Expr>)>),
237 Arr(Vec<(bool, Rc<Expr>)>),
238 Comp {
239 head: Rc<Expr>,
240 clauses: Vec<ForClause>,
241 },
242 MapComp {
243 key: Rc<Expr>,
244 val: Rc<Expr>,
245 clauses: Vec<ForClause>,
246 },
247 Bin {
248 op: String,
249 l: Rc<Expr>,
250 r: Rc<Expr>,
251 },
252 Un {
253 op: String,
254 x: Rc<Expr>,
255 },
256 Paren(Rc<Expr>),
257 If {
258 c: Rc<Expr>,
259 t: Rc<Expr>,
260 f: Rc<Expr>,
261 },
262 Lambda {
263 params: Vec<String>,
264 body: Rc<Expr>,
265 },
266 Call {
267 fun: Rc<Expr>,
268 args: Vec<Rc<Expr>>,
269 },
270 Member {
271 x: Rc<Expr>,
272 name: String,
273 safe: bool,
274 },
275 Index {
276 x: Rc<Expr>,
277 i: Rc<Expr>,
278 },
279 With {
280 base: Rc<Expr>,
281 patch: Rc<Expr>,
282 },
283 Pattern(String),
284 Match {
285 subject: Rc<Expr>,
286 arms: Vec<MatchArm>,
287 },
288}
289
290#[derive(Debug, Clone)]
291pub struct Param {
292 pub name: String,
293 pub ty: Option<TypeAst>,
294}
295
296#[derive(Debug, Clone)]
297pub struct ImportItem {
298 pub name: String,
299 pub alias: Option<String>,
300}
301
302#[allow(dead_code)]
305#[derive(Debug, Clone)]
306pub enum DeclBody {
307 Type {
308 name: String,
309 params: Vec<Param>,
310 ty: TypeAst,
311 tail: Option<Tail>,
312 },
313 Const {
314 name: String,
315 ty: Option<TypeAst>,
316 expr: Rc<Expr>,
317 },
318 Func {
319 name: String,
320 params: Vec<Param>,
321 ret: Option<TypeAst>,
322 body: Rc<Expr>,
323 },
324 Output {
325 name: String,
326 ty: TypeAst,
327 expr: Rc<Expr>,
328 },
329 Input {
330 name: String,
331 ty: TypeAst,
332 fallback: Option<Rc<Expr>>,
333 },
334 Diagnostic {
335 name: String,
336 params: Vec<Param>,
337 severity: String,
338 template: Vec<TPart>,
339 },
340 Dimension {
341 name: String,
342 terms: Option<Vec<(String, i32)>>,
343 },
344 Unit {
345 name: String,
346 dim: Option<String>,
347 factor: Option<Rc<Expr>>,
348 base: Option<String>,
349 },
350 Import {
351 from: String,
352 names: Option<Vec<ImportItem>>,
353 ns: Option<String>,
354 },
355 ReExport {
356 from: String,
357 names: Vec<ImportItem>,
358 },
359}
360
361#[derive(Debug, Clone)]
362pub struct Decl {
363 pub body: DeclBody,
364 pub exported: bool,
365 pub loc: Option<Loc>,
367}
368
369impl Decl {
370 pub fn name(&self) -> Option<&str> {
371 match &self.body {
372 DeclBody::Type { name, .. }
373 | DeclBody::Const { name, .. }
374 | DeclBody::Func { name, .. }
375 | DeclBody::Output { name, .. }
376 | DeclBody::Input { name, .. }
377 | DeclBody::Diagnostic { name, .. }
378 | DeclBody::Dimension { name, .. }
379 | DeclBody::Unit { name, .. } => Some(name),
380 _ => None,
381 }
382 }
383}
384
385pub fn mentions_referrers(e: &Expr) -> bool {
387 match e {
388 Expr::Referrers { .. } => true,
389 Expr::Lit(_) | Expr::UnitLit { .. } | Expr::Name(_) | Expr::Ctx(_) | Expr::Pattern(_) => {
390 false
391 }
392 Expr::Template(parts) => parts
393 .iter()
394 .any(|p| matches!(p, TPart::Expr(x) if mentions_referrers(x))),
395 Expr::Obj(es) => es.iter().any(|(_, v)| mentions_referrers(v)),
396 Expr::Arr(items) => items.iter().any(|(_, v)| mentions_referrers(v)),
397 Expr::Comp { head, clauses } => {
398 mentions_referrers(head) || clauses.iter().any(clause_mentions)
399 }
400 Expr::MapComp { key, val, clauses } => {
401 mentions_referrers(key)
402 || mentions_referrers(val)
403 || clauses.iter().any(clause_mentions)
404 }
405 Expr::Bin { l, r, .. } => mentions_referrers(l) || mentions_referrers(r),
406 Expr::Un { x, .. } | Expr::Paren(x) => mentions_referrers(x),
407 Expr::If { c, t, f } => {
408 mentions_referrers(c) || mentions_referrers(t) || mentions_referrers(f)
409 }
410 Expr::Lambda { body, .. } => mentions_referrers(body),
411 Expr::Call { fun, args } => {
412 mentions_referrers(fun) || args.iter().any(|a| mentions_referrers(a))
413 }
414 Expr::Member { x, .. } => mentions_referrers(x),
415 Expr::Index { x, i } => mentions_referrers(x) || mentions_referrers(i),
416 Expr::With { base, patch } => mentions_referrers(base) || mentions_referrers(patch),
417 Expr::Match { subject, arms } => {
418 mentions_referrers(subject) || arms.iter().any(|a| mentions_referrers(&a.body))
419 }
420 }
421}
422
423fn clause_mentions(c: &ForClause) -> bool {
424 mentions_referrers(&c.iter) || c.filters.iter().any(|f| mentions_referrers(f))
425}
426
427pub fn expr_name(e: &Expr) -> String {
428 match e {
429 Expr::Name(n) => n.clone(),
430 Expr::Call { fun, .. } => expr_name(fun),
431 _ => "<predicate>".into(),
432 }
433}