1use crate::ast::*;
4use num_bigint::BigInt;
5use num_traits::{ToPrimitive, Zero};
6use regex::Regex;
7use std::cell::{Cell, RefCell};
8use std::collections::{BTreeMap, HashMap, HashSet};
9use std::fmt;
10use std::rc::Rc;
11use std::sync::LazyLock;
12
13static PATTERN_HOLE: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"\$\{([^}]*)\}").unwrap());
15static PATTERN_STR_LIT: LazyLock<Regex> =
16 LazyLock::new(|| Regex::new(r#"^"((?:[^"\\]|\\.)*)"$"#).unwrap());
17static PATTERN_INT_RANGE: LazyLock<Regex> =
18 LazyLock::new(|| Regex::new(r"^(-?[0-9]+)\.\.(<?)(-?[0-9]+)$").unwrap());
19static PATTERN_INT_LIT: LazyLock<Regex> = LazyLock::new(|| Regex::new(r"^-?[0-9]+$").unwrap());
20static PATTERN_IDENT: LazyLock<Regex> =
21 LazyLock::new(|| Regex::new(r"^[A-Za-z_][A-Za-z0-9_.]*$").unwrap());
22
23#[derive(Clone, Debug, PartialEq)]
25pub enum Seg {
26 Name(String),
28 Idx(usize),
29 Key(String),
31}
32pub type SegPath = Vec<Seg>;
33pub fn seg_text(s: &Seg) -> String {
34 match s {
35 Seg::Name(n) | Seg::Key(n) => n.clone(),
36 Seg::Idx(i) => i.to_string(),
37 }
38}
39pub fn dot_spellable(name: &str) -> bool {
41 let mut cs = name.chars();
42 let head = matches!(cs.next(), Some(c) if c == '_' || c.is_ascii_alphabetic());
43 head && cs.all(|c| c == '_' || c.is_ascii_alphanumeric())
44 && !matches!(name, "true" | "false" | "null")
45}
46
47#[derive(Clone)]
49pub enum Value {
50 Int(BigInt),
51 Float(f64),
52 Str(String),
53 Bool(bool),
54 Null,
55 Absent,
56 Undef,
57 Q {
58 dim: String,
59 value: f64,
60 },
61 Ref(Rc<SegPath>),
62 Rec(Rc<RefCell<RecInst>>),
63 Arr(Rc<RefCell<ArrV>>),
64 Map(Rc<RefCell<MapV>>),
65 Range {
66 lo: Box<Value>,
67 hi: Box<Value>,
68 excl: bool,
69 },
70 Clo(Rc<Closure>),
71 Nat(NatFn),
72 Std(Rc<Vec<String>>),
73 NsRef(Rc<NsRefV>),
74 Pat(String),
75 PreObj(Rc<Vec<(String, Value)>>),
76 PreArr(Rc<Vec<(bool, Value)>>),
77 PreVal(Rc<PreValV>),
78 JObj(Rc<Vec<(String, Value)>>),
79 JArr(Rc<Vec<Value>>),
80 Segs(Rc<SegPath>),
81}
82
83impl fmt::Debug for Value {
84 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85 match self {
86 Value::Int(i) => write!(f, "{i}"),
87 Value::Float(x) => write!(f, "{x}"),
88 Value::Str(s) => write!(f, "{s:?}"),
89 Value::Bool(b) => write!(f, "{b}"),
90 Value::Null => write!(f, "null"),
91 Value::Absent => write!(f, "ABSENT"),
92 Value::Undef => write!(f, "UNDEF"),
93 Value::Q { dim, value } => write!(f, "{value}<{dim}>"),
94 other => write!(f, "<{}>", other.tag()),
95 }
96 }
97}
98
99impl Value {
100 pub fn tag(&self) -> &'static str {
101 match self {
102 Value::Int(_) => "int",
103 Value::Float(_) => "float",
104 Value::Str(_) => "string",
105 Value::Bool(_) => "bool",
106 Value::Null => "null",
107 Value::Absent => "absent",
108 Value::Undef => "undef",
109 Value::Q { .. } => "quantity",
110 Value::Ref(_) => "ref",
111 Value::Rec(_) => "record",
112 Value::Arr(_) => "array",
113 Value::Map(_) => "map",
114 Value::Range { .. } => "range",
115 Value::Clo(_) => "closure",
116 Value::Nat(_) => "native",
117 Value::Std(_) => "std",
118 Value::NsRef(_) => "namespace",
119 Value::Pat(_) => "pattern",
120 Value::PreObj(_) => "pre-obj",
121 Value::PreArr(_) => "pre-arr",
122 Value::PreVal(_) => "pre-val",
123 Value::JObj(_) => "json-obj",
124 Value::JArr(_) => "json-arr",
125 Value::Segs(_) => "segs",
126 }
127 }
128 pub fn is_undef(&self) -> bool {
129 matches!(self, Value::Undef)
130 }
131 pub fn is_absent(&self) -> bool {
132 matches!(self, Value::Absent)
133 }
134 pub fn place(&self) -> Option<SegPath> {
135 match self {
136 Value::Ref(p) => Some((**p).clone()),
137 Value::Rec(r) => Some(r.borrow().path.clone()),
138 Value::Arr(a) => Some(a.borrow().path.clone()),
139 Value::Map(m) => Some(m.borrow().path.clone()),
140 _ => None,
141 }
142 }
143}
144
145pub type NatFn = Rc<dyn Fn(&[Value]) -> R<Value>>;
146
147pub struct Closure {
148 pub params: Vec<String>,
149 pub body: Rc<Expr>,
150 pub scope: Scope,
151}
152pub struct NsRefV {
153 pub exports: Rc<RefCell<HashMap<String, Export>>>,
154}
155pub struct PreValV {
156 pub expr: Rc<Expr>,
157 pub scope: Scope,
158}
159pub struct ArrV {
160 pub items: Vec<Value>,
161 pub path: SegPath,
162}
163pub struct MapV {
164 pub entries: Vec<(String, Value)>,
165 pub path: SegPath,
166}
167impl MapV {
168 pub fn get(&self, k: &str) -> Option<&Value> {
169 self.entries.iter().find(|(n, _)| n == k).map(|(_, v)| v)
170 }
171 pub fn has(&self, k: &str) -> bool {
172 self.entries.iter().any(|(n, _)| n == k)
173 }
174 pub fn set(&mut self, k: String, v: Value) {
175 if let Some(e) = self.entries.iter_mut().find(|(n, _)| *n == k) {
176 e.1 = v;
177 } else {
178 self.entries.push((k, v));
179 }
180 }
181}
182
183#[derive(Clone, Copy, PartialEq, Debug)]
184pub enum MKind {
185 Req,
186 Opt,
187 Dflt,
188 Der,
189}
190#[derive(Clone, Copy, PartialEq, Debug)]
191pub enum SlotState {
192 Unforced,
193 Forcing,
194 Ok,
195 Invalid,
196 Absent,
197}
198
199#[derive(Clone)]
200pub enum Compute {
201 Check {
202 raw: Value,
203 types: Vec<RT>,
204 name: String,
205 root_name: String,
206 menv: Option<Rc<Env>>,
207 },
208 Default {
209 expr: Rc<Expr>,
210 types: Vec<RT>,
211 name: String,
212 root_name: String,
213 menv: Option<Rc<Env>>,
214 },
215 Derived {
216 expr: Rc<Expr>,
217 ty: Option<RT>,
218 supplied: Option<Value>,
219 name: String,
220 root_name: String,
221 menv: Option<Rc<Env>>,
222 },
223}
224
225pub struct Slot {
226 pub kind: MKind,
227 pub hidden: bool,
229 pub state: SlotState,
230 pub value: Value,
231 pub compute: Option<Compute>,
232}
233
234pub struct RecInst {
235 pub type_name: Option<String>,
236 pub rt: RT,
237 pub path: SegPath,
238 pub parent: Option<Rc<RefCell<RecInst>>>,
239 pub slots: Vec<(String, Slot)>,
241 pub entry_order: Vec<String>,
242 pub extras: Vec<(String, Value)>,
243 pub menv: Option<Rc<Env>>,
244}
245impl RecInst {
246 pub fn extra(&self, n: &str) -> Option<&Value> {
247 self.extras.iter().find(|(k, _)| k == n).map(|(_, v)| v)
248 }
249 pub fn set_extra(&mut self, n: &str, v: Value) {
250 if let Some(e) = self.extras.iter_mut().find(|(k, _)| k == n) {
251 e.1 = v;
252 } else {
253 self.extras.push((n.to_string(), v));
254 }
255 }
256 pub fn slot(&self, n: &str) -> Option<&Slot> {
257 self.slots.iter().find(|(k, _)| k == n).map(|(_, s)| s)
258 }
259 pub fn slot_mut(&mut self, n: &str) -> Option<&mut Slot> {
260 self.slots.iter_mut().find(|(k, _)| k == n).map(|(_, s)| s)
261 }
262 pub fn has_slot(&self, n: &str) -> bool {
263 self.slots.iter().any(|(k, _)| k == n)
264 }
265}
266
267#[derive(Clone)]
268pub struct Scope {
269 pub inst: Option<Rc<RefCell<RecInst>>>,
270 pub locals: Rc<HashMap<String, Value>>,
271 pub root_name: String,
272 pub menv: Option<Rc<Env>>,
273}
274impl Scope {
275 pub fn new(root_name: &str, menv: Option<Rc<Env>>) -> Scope {
276 Scope {
277 inst: None,
278 locals: Rc::new(HashMap::new()),
279 root_name: root_name.to_string(),
280 menv,
281 }
282 }
283 pub fn with_locals(&self, locals: HashMap<String, Value>) -> Scope {
284 Scope {
285 inst: self.inst.clone(),
286 locals: Rc::new(locals),
287 root_name: self.root_name.clone(),
288 menv: self.menv.clone(),
289 }
290 }
291 pub fn with_inst(&self, inst: Option<Rc<RefCell<RecInst>>>) -> Scope {
292 Scope {
293 inst,
294 locals: self.locals.clone(),
295 root_name: self.root_name.clone(),
296 menv: self.menv.clone(),
297 }
298 }
299 pub fn with_menv(&self, menv: Option<Rc<Env>>) -> Scope {
300 Scope {
301 inst: self.inst.clone(),
302 locals: self.locals.clone(),
303 root_name: self.root_name.clone(),
304 menv,
305 }
306 }
307}
308
309pub struct EvalErr {
311 pub msg: String,
312 pub code: Option<String>,
313}
314pub enum Fail {
315 Taint,
316 Defer,
317 Eval(EvalErr),
318}
319pub type R<T> = Result<T, Fail>;
320pub fn err<T>(msg: impl Into<String>) -> R<T> {
321 Err(Fail::Eval(EvalErr {
322 msg: msg.into(),
323 code: None,
324 }))
325}
326pub fn err_code<T>(msg: impl Into<String>, code: &str) -> R<T> {
327 Err(Fail::Eval(EvalErr {
328 msg: msg.into(),
329 code: Some(code.to_string()),
330 }))
331}
332
333#[derive(Clone, Debug)]
334pub struct Diag {
335 pub severity: String,
336 pub id: Option<String>,
337 pub message: String,
338 pub path: String,
339 pub code: Option<String>,
340 pub loc: Option<Loc>,
342 pub by: Option<String>,
344}
345impl Diag {
346 pub fn error(message: impl Into<String>, path: String, code: Option<&str>) -> Diag {
347 Diag {
348 severity: "error".into(),
349 id: None,
350 message: message.into(),
351 path,
352 code: code.map(|c| c.to_string()),
353 loc: None,
354 by: None,
355 }
356 }
357 pub fn to_json(&self, file: Option<&str>) -> String {
358 let mut parts = Vec::new();
359 if let Some(f) = file {
363 parts.push(format!("\"file\":{}", json_str(f)));
364 }
365 if let Some(c) = &self.code {
366 parts.push(format!("\"code\":{}", json_str(c)));
367 }
368 if let Some(id) = &self.id {
369 parts.push(format!("\"id\":{}", json_str(id)));
370 }
371 parts.push(format!("\"severity\":{}", json_str(&self.severity)));
372 parts.push(format!("\"message\":{}", json_str(&self.message)));
373 parts.push(format!("\"path\":{}", json_str(&self.path)));
374 format!("{{{}}}", parts.join(","))
375 }
376}
377
378pub type RT = Rc<Ty>;
380
381pub struct Ty {
382 pub k: RTk,
383 pub name: RefCell<Option<String>>,
384 pub tail: RefCell<Option<Tail>>,
385}
386pub fn ty(k: RTk) -> RT {
387 Rc::new(Ty {
388 k,
389 name: RefCell::new(None),
390 tail: RefCell::new(None),
391 })
392}
393
394pub enum RTk {
395 Prim(String),
396 Lit(Value),
397 Range {
398 lo: Value,
399 hi: Value,
400 excl: bool,
401 base: String,
402 },
403 Pattern {
404 src: String,
405 re: Regex,
406 },
407 Arr {
408 elem: RT,
409 lo: Option<i64>,
410 hi: Option<i64>,
411 },
412 Map {
413 key: RT,
414 val: RT,
415 },
416 Union(Vec<RT>),
417 IsectN(Vec<RT>),
418 Rec(RecType),
419 Pred {
420 base: RT,
421 preds: Vec<Rc<Expr>>,
422 },
423 Ref(RT),
424 Quantity(String),
425 Func {
426 params: Vec<RT>,
427 ret: RT,
428 },
429 Any,
430}
431
432pub struct RecType {
433 pub open: Cell<bool>,
434 pub members: RefCell<Vec<Member>>,
435 pub asserts: RefCell<Vec<AssertItem>>,
436 pub ctx_decls: RefCell<Vec<(String, RT)>>,
438 pub filling: Cell<bool>,
440 pub pending: RefCell<Vec<(RT, RT)>>,
441}
442pub fn rec_type(open: bool) -> RecType {
443 RecType {
444 open: Cell::new(open),
445 members: RefCell::new(vec![]),
446 asserts: RefCell::new(vec![]),
447 ctx_decls: RefCell::new(vec![]),
448 filling: Cell::new(false),
449 pending: RefCell::new(vec![]),
450 }
451}
452
453#[derive(Clone)]
454pub struct Member {
455 pub kind: MKind,
456 pub name: String,
457 pub hidden: bool,
459 pub ty: Option<RT>,
460 pub conj: Option<Vec<RT>>,
461 pub dflt: Option<Rc<Expr>>,
462 pub expr: Option<Rc<Expr>>,
463 pub menv: Option<Rc<Env>>,
464}
465
466#[derive(Clone)]
467pub struct AssertItem {
468 pub when: bool,
469 pub name: String,
470 pub cond: Rc<Expr>,
471 pub tail: Option<Tail>,
472 pub body: Vec<MemberAst>,
473 pub origin: Option<String>,
474 pub menv: Option<Rc<Env>>,
475}
476
477pub fn rec_members(t: &RT) -> Vec<Member> {
478 match &t.k {
479 RTk::Rec(r) => r.members.borrow().clone(),
480 _ => vec![],
481 }
482}
483pub fn is_rec(t: &RT) -> bool {
484 matches!(t.k, RTk::Rec(_))
485}
486
487pub type DimVec = BTreeMap<String, i32>;
489pub fn key_of_vec(v: &DimVec) -> String {
490 v.iter()
491 .filter(|(_, e)| **e != 0)
492 .map(|(n, e)| {
493 if *e == 1 {
494 n.clone()
495 } else {
496 format!("{n}^{e}")
497 }
498 })
499 .collect::<Vec<_>>()
500 .join("*")
501}
502pub fn vec_of_key(key: &str) -> DimVec {
503 let mut v = DimVec::new();
504 if key.is_empty() {
505 return v;
506 }
507 for p in key.split('*') {
508 let (n, e) = match p.split_once('^') {
509 Some((n, e)) => (n.to_string(), e.parse::<i32>().unwrap_or(1)),
510 None => (p.to_string(), 1),
511 };
512 *v.entry(n).or_insert(0) += e;
513 }
514 v
515}
516pub fn vec_combine(a: &DimVec, b: &DimVec, sign: i32) -> DimVec {
517 let mut out = a.clone();
518 for (n, e) in b {
519 *out.entry(n.clone()).or_insert(0) += sign * e;
520 }
521 out
522}
523
524pub struct Export {
526 pub env: Rc<Env>,
527 pub name: String,
528}
529impl Clone for Export {
530 fn clone(&self) -> Self {
531 Export {
532 env: self.env.clone(),
533 name: self.name.clone(),
534 }
535 }
536}
537pub struct ConstEntry {
538 pub expr: Rc<Expr>,
539 pub ty: Option<TypeAst>,
540 pub state: Cell<bool>,
541 pub value: RefCell<Value>,
542}
543pub struct FuncEntry {
544 pub params: Vec<Param>,
545 pub ret: Option<TypeAst>,
546 pub body: Rc<Expr>,
547}
548pub struct TypeEntry {
549 pub ast: TypeAst,
550 pub tail: Option<Tail>,
551 pub params: Vec<Param>,
552}
553pub struct DiagDecl {
554 pub params: Vec<Param>,
555 pub severity: String,
556 pub template: Vec<TPart>,
557}
558pub struct UnitDecl {
559 pub dim: Option<String>,
560 pub factor: Option<Rc<Expr>>,
561 pub base: Option<String>,
562}
563pub type ConstEval = Rc<dyn Fn(&str) -> R<Value>>;
564pub type ExprEval = Rc<dyn Fn(&Rc<Expr>) -> R<Value>>;
565
566pub struct Env {
567 pub type_asts: RefCell<HashMap<String, Rc<TypeEntry>>>,
568 pub type_memo: RefCell<HashMap<String, RT>>,
569 pub pattern_visiting: RefCell<Vec<String>>,
572 pub consts: RefCell<HashMap<String, Rc<ConstEntry>>>,
573 pub funcs: RefCell<HashMap<String, Rc<FuncEntry>>>,
574 pub duplicates: RefCell<Vec<String>>,
575 pub outputs: RefCell<Vec<(String, TypeAst, Rc<Expr>)>>,
576 pub inputs: RefCell<HashMap<String, (TypeAst, Option<Rc<Expr>>)>>,
577 pub diags: RefCell<HashMap<String, Rc<DiagDecl>>>,
578 pub registry: RefCell<Rc<RefCell<Vec<Rc<RefCell<RecInst>>>>>>,
579 pub roots: RefCell<Rc<RefCell<Vec<(String, Value)>>>>,
580 pub diagnostics: RefCell<Rc<RefCell<Vec<Diag>>>>,
581 pub const_eval: RefCell<Option<ConstEval>>,
582 pub expr_eval: RefCell<Option<ExprEval>>,
583 pub imports: RefCell<HashMap<String, Export>>,
584 pub namespaces: RefCell<HashMap<String, (Rc<Env>, Rc<RefCell<HashMap<String, Export>>>)>>,
585 const_diag_seen: RefCell<HashSet<String>>,
586 pub dim_decls: RefCell<HashMap<String, Option<Vec<(String, i32)>>>>,
587 pub dim_memo: RefCell<HashMap<String, DimVec>>,
588 pub unit_decls: RefCell<HashMap<String, UnitDecl>>,
589 pub unit_memo: RefCell<HashMap<String, (String, f64)>>,
590 pub base_unit_of: RefCell<HashMap<String, String>>,
591 pub space_diags: RefCell<Vec<Diag>>,
592 pub type_order: RefCell<Vec<String>>,
594 pub unit_order: RefCell<Vec<String>>,
595 pub const_diag_sink: RefCell<Option<Rc<RefCell<Vec<Diag>>>>>,
597 pub tagger: RefCell<Option<Rc<dyn Fn() -> Option<String>>>>,
599}
600
601pub fn sort_diags(diags: Vec<Diag>) -> Vec<Diag> {
603 let segs_of = |p: &str| -> SegPath {
604 if p.is_empty() {
605 return vec![];
606 }
607 parse_path(p, "").unwrap_or_else(|_| vec![Seg::Name(p.to_string())])
608 };
609 let mut keyed: Vec<(usize, SegPath, Diag)> = diags
610 .into_iter()
611 .enumerate()
612 .map(|(i, d)| (i, segs_of(&d.path), d))
613 .collect();
614 keyed.sort_by(|a, b| {
615 cmp_path(&a.1, &b.1)
616 .then_with(|| {
617 a.2.id
618 .as_deref()
619 .unwrap_or("")
620 .cmp(b.2.id.as_deref().unwrap_or(""))
621 })
622 .then_with(|| a.0.cmp(&b.0))
623 });
624 keyed.into_iter().map(|(_, _, d)| d).collect()
625}
626
627const SI_PREFIXES: [(&str, f64); 20] = [
628 ("y", 1e-24),
629 ("z", 1e-21),
630 ("a", 1e-18),
631 ("f", 1e-15),
632 ("p", 1e-12),
633 ("n", 1e-9),
634 ("u", 1e-6),
635 ("m", 1e-3),
636 ("c", 1e-2),
637 ("d", 1e-1),
638 ("da", 1e1),
639 ("h", 1e2),
640 ("k", 1e3),
641 ("M", 1e6),
642 ("G", 1e9),
643 ("T", 1e12),
644 ("P", 1e15),
645 ("E", 1e18),
646 ("Z", 1e21),
647 ("Y", 1e24),
648];
649
650impl Env {
651 pub fn new() -> Rc<Env> {
652 let env = Env {
653 type_asts: RefCell::new(HashMap::new()),
654 type_memo: RefCell::new(HashMap::new()),
655 pattern_visiting: RefCell::new(vec![]),
656 consts: RefCell::new(HashMap::new()),
657 funcs: RefCell::new(HashMap::new()),
658 duplicates: RefCell::new(vec![]),
659 outputs: RefCell::new(vec![]),
660 inputs: RefCell::new(HashMap::new()),
661 diags: RefCell::new(HashMap::new()),
662 registry: RefCell::new(Rc::new(RefCell::new(vec![]))),
663 roots: RefCell::new(Rc::new(RefCell::new(vec![]))),
664 diagnostics: RefCell::new(Rc::new(RefCell::new(vec![]))),
665 const_eval: RefCell::new(None),
666 expr_eval: RefCell::new(None),
667 imports: RefCell::new(HashMap::new()),
668 namespaces: RefCell::new(HashMap::new()),
669 const_diag_seen: RefCell::new(HashSet::new()),
670 dim_decls: RefCell::new(HashMap::new()),
671 dim_memo: RefCell::new(HashMap::new()),
672 unit_decls: RefCell::new(HashMap::new()),
673 unit_memo: RefCell::new(HashMap::new()),
674 base_unit_of: RefCell::new(HashMap::new()),
675 space_diags: RefCell::new(vec![]),
676 type_order: RefCell::new(vec![]),
677 unit_order: RefCell::new(vec![]),
678 const_diag_sink: RefCell::new(None),
679 tagger: RefCell::new(None),
680 };
681 env.seed_units();
682 Rc::new(env)
683 }
684
685 fn seed_units(&self) {
687 let unit = |sym: &str, dim: Option<&str>, factor: f64, base: &str| {
688 let mut m = self.unit_decls.borrow_mut();
689 if m.contains_key(sym) {
690 return;
691 }
692 self.unit_order.borrow_mut().push(sym.to_string());
693 m.insert(
694 sym.to_string(),
695 match dim {
696 Some(d) => UnitDecl {
697 dim: Some(d.to_string()),
698 factor: None,
699 base: None,
700 },
701 None => UnitDecl {
702 dim: None,
703 factor: Some(Rc::new(Expr::Lit(Value::Float(factor)))),
704 base: Some(base.to_string()),
705 },
706 },
707 );
708 };
709 let bases = [
710 ("Time", "s"),
711 ("Length", "m"),
712 ("Mass", "kg"),
713 ("Current", "A"),
714 ("Temperature", "K"),
715 ("Amount", "mol"),
716 ("LuminousIntensity", "cd"),
717 ];
718 for (d, _) in bases {
719 self.dim_decls.borrow_mut().insert(d.to_string(), None);
720 }
721 let t = |n: &str, e: i32| (n.to_string(), e);
722 let derived: Vec<(&str, Option<Vec<(String, i32)>>, &str)> = vec![
723 ("Frequency", Some(vec![t("Time", -1)]), "Hz"),
724 (
725 "Force",
726 Some(vec![t("Mass", 1), t("Length", 1), t("Time", -2)]),
727 "N",
728 ),
729 (
730 "Pressure",
731 Some(vec![t("Mass", 1), t("Length", -1), t("Time", -2)]),
732 "Pa",
733 ),
734 (
735 "Energy",
736 Some(vec![t("Mass", 1), t("Length", 2), t("Time", -2)]),
737 "J",
738 ),
739 (
740 "Power",
741 Some(vec![t("Mass", 1), t("Length", 2), t("Time", -3)]),
742 "W",
743 ),
744 ("Charge", Some(vec![t("Current", 1), t("Time", 1)]), "C"),
745 (
746 "Voltage",
747 Some(vec![
748 t("Mass", 1),
749 t("Length", 2),
750 t("Time", -3),
751 t("Current", -1),
752 ]),
753 "V",
754 ),
755 (
756 "Resistance",
757 Some(vec![
758 t("Mass", 1),
759 t("Length", 2),
760 t("Time", -3),
761 t("Current", -2),
762 ]),
763 "Ohm",
764 ),
765 (
766 "Capacitance",
767 Some(vec![
768 t("Mass", -1),
769 t("Length", -2),
770 t("Time", 4),
771 t("Current", 2),
772 ]),
773 "F",
774 ),
775 ("DataSize", None, "bit"),
776 ];
777 for (d, terms, _) in &derived {
778 self.dim_decls
779 .borrow_mut()
780 .insert(d.to_string(), terms.clone());
781 }
782 for (d, s) in bases {
783 unit(s, Some(d), 1.0, "");
784 }
785 for (d, _, s) in &derived {
786 unit(s, Some(d), 1.0, "");
787 }
788 unit("B", None, 8.0, "bit");
789 unit("g", None, 1e-3, "kg");
790 let mut prefixable: Vec<&str> = bases
791 .iter()
792 .map(|(_, s)| *s)
793 .filter(|s| *s != "kg")
794 .collect();
795 prefixable.extend(derived.iter().map(|(_, _, s)| *s).filter(|s| *s != "bit"));
796 prefixable.push("g");
797 for u0 in prefixable {
798 for (p, f) in SI_PREFIXES {
799 unit(&format!("{p}{u0}"), None, f, u0);
800 }
801 }
802 for u0 in ["bit", "B"] {
803 for (p, f) in [
804 ("Ki", 1024f64),
805 ("Mi", 1024f64.powi(2)),
806 ("Gi", 1024f64.powi(3)),
807 ("Ti", 1024f64.powi(4)),
808 ("Pi", 1024f64.powi(5)),
809 ("Ei", 1024f64.powi(6)),
810 ] {
811 unit(&format!("{p}{u0}"), None, f, u0);
812 }
813 for (p, f) in SI_PREFIXES {
814 if ["k", "M", "G", "T", "P", "E"].contains(&p) {
815 unit(&format!("{p}{u0}"), None, f, u0);
816 }
817 }
818 }
819 }
820
821 pub fn load(&self, decls: &[Decl]) {
822 let mut seen: HashSet<String> = HashSet::new();
823 for d in decls {
824 if let Some(n) = d.name() {
825 if !matches!(d.body, DeclBody::Unit { .. } | DeclBody::Dimension { .. })
826 && !seen.insert(n.to_string())
827 {
828 self.duplicates.borrow_mut().push(n.to_string());
829 }
830 }
831 match &d.body {
832 DeclBody::Dimension { name, terms } => {
833 if self.dim_decls.borrow().contains_key(name) {
834 self.space_diags.borrow_mut().push(Diag::error(
835 format!("dimension {name} redeclared"),
836 String::new(),
837 Some("E3001"),
838 ));
839 } else {
840 self.dim_decls
841 .borrow_mut()
842 .insert(name.clone(), terms.clone());
843 }
844 }
845 DeclBody::Unit {
846 name,
847 dim,
848 factor,
849 base,
850 } => {
851 if self.unit_decls.borrow().contains_key(name) {
852 self.space_diags.borrow_mut().push(Diag::error(
853 format!("unit {name} redeclared"),
854 String::new(),
855 Some("E4073"),
856 ));
857 } else {
858 self.unit_order.borrow_mut().push(name.clone());
859 self.unit_decls.borrow_mut().insert(
860 name.clone(),
861 UnitDecl {
862 dim: dim.clone(),
863 factor: factor.clone(),
864 base: base.clone(),
865 },
866 );
867 }
868 }
869 DeclBody::Type {
870 name,
871 params,
872 ty,
873 tail,
874 } => {
875 if !self.type_asts.borrow().contains_key(name) {
876 self.type_order.borrow_mut().push(name.clone());
877 }
878 self.type_asts.borrow_mut().insert(
879 name.clone(),
880 Rc::new(TypeEntry {
881 ast: ty.clone(),
882 tail: tail.clone(),
883 params: params.clone(),
884 }),
885 );
886 }
887 DeclBody::Const { name, ty, expr } => {
888 self.consts.borrow_mut().insert(
889 name.clone(),
890 Rc::new(ConstEntry {
891 expr: expr.clone(),
892 ty: ty.clone(),
893 state: Cell::new(false),
894 value: RefCell::new(Value::Null),
895 }),
896 );
897 }
898 DeclBody::Func {
899 name,
900 params,
901 ret,
902 body,
903 } => {
904 self.funcs.borrow_mut().insert(
905 name.clone(),
906 Rc::new(FuncEntry {
907 params: params.clone(),
908 ret: ret.clone(),
909 body: body.clone(),
910 }),
911 );
912 }
913 DeclBody::Output { name, ty, expr } => {
914 self.outputs
915 .borrow_mut()
916 .push((name.clone(), ty.clone(), expr.clone()))
917 }
918 DeclBody::Input { name, ty, fallback } => {
919 self.inputs
920 .borrow_mut()
921 .insert(name.clone(), (ty.clone(), fallback.clone()));
922 }
923 DeclBody::Diagnostic {
924 name,
925 params,
926 severity,
927 template,
928 } => {
929 self.diags.borrow_mut().insert(
930 name.clone(),
931 Rc::new(DiagDecl {
932 params: params.clone(),
933 severity: severity.clone(),
934 template: template.clone(),
935 }),
936 );
937 }
938 _ => {}
939 }
940 }
941 }
942
943 pub fn report(&self, d: Diag) {
944 let by = self.tagger.borrow().as_ref().and_then(|t| t());
945 let mut d = d;
946 if by.is_some() {
947 d.by = by;
948 }
949 self.diagnostics.borrow().borrow_mut().push(d);
950 }
951 pub fn diag_set(&self, diags: Vec<Diag>) {
953 let rc = self.diagnostics.borrow().clone();
954 *rc.borrow_mut() = diags;
955 }
956 pub fn remove_root(&self, name: &str) {
957 let rc = self.roots.borrow().clone();
958 rc.borrow_mut().retain(|(n, _)| n != name);
959 }
960 pub fn root_names(&self) -> Vec<String> {
961 self.roots
962 .borrow()
963 .borrow()
964 .iter()
965 .map(|(n, _)| n.clone())
966 .collect()
967 }
968 pub fn registry_retain(&self, mut pred: impl FnMut(&Rc<RefCell<RecInst>>) -> bool) {
969 let rc = self.registry.borrow().clone();
970 rc.borrow_mut().retain(|i| pred(i));
971 }
972 pub fn diagnostics_vec(&self) -> Vec<Diag> {
973 self.diagnostics.borrow().borrow().clone()
974 }
975 pub fn diag_len(&self) -> usize {
976 self.diagnostics.borrow().borrow().len()
977 }
978 pub fn diag_truncate(&self, n: usize) {
979 self.diagnostics.borrow().borrow_mut().truncate(n);
980 }
981 pub fn root(&self, name: &str) -> Option<Value> {
982 self.roots
983 .borrow()
984 .borrow()
985 .iter()
986 .find(|(n, _)| n == name)
987 .map(|(_, v)| v.clone())
988 }
989 pub fn set_root(&self, name: &str, v: Value) {
990 let rc = self.roots.borrow().clone();
991 let mut roots = rc.borrow_mut();
992 if let Some(e) = roots.iter_mut().find(|(n, _)| n == name) {
993 e.1 = v;
994 } else {
995 roots.push((name.to_string(), v));
996 }
997 }
998 pub fn root_values(&self) -> Vec<Value> {
999 self.roots
1000 .borrow()
1001 .borrow()
1002 .iter()
1003 .map(|(_, v)| v.clone())
1004 .collect()
1005 }
1006 pub fn registry_push(&self, inst: Rc<RefCell<RecInst>>) {
1007 self.registry.borrow().borrow_mut().push(inst);
1008 }
1009 pub fn registry_snapshot(&self) -> Vec<Rc<RefCell<RecInst>>> {
1010 self.registry.borrow().borrow().clone()
1011 }
1012
1013 pub fn const_num(&self, v: &Value) -> Value {
1015 let name = match v {
1016 Value::Str(s) => s.clone(),
1017 other => return other.clone(),
1018 };
1019 let ce = self.const_eval.borrow().clone();
1020 let Some(ce) = ce else { return v.clone() };
1021 if !self.consts.borrow().contains_key(&name) {
1022 return v.clone();
1023 }
1024 let diag = |code: &str, message: String| {
1025 let key = format!("{name}{code}");
1026 if self.const_diag_seen.borrow().contains(&key) {
1027 return;
1028 }
1029 self.const_diag_seen.borrow_mut().insert(key);
1030 let d = Diag::error(message, String::new(), Some(code));
1031 match &*self.const_diag_sink.borrow() {
1032 Some(sink) => sink.borrow_mut().push(d),
1033 None => self.report(d),
1034 }
1035 };
1036 match ce(&name) {
1037 Ok(Value::Int(i)) => Value::Int(i),
1038 Ok(Value::Float(f)) => Value::Float(f),
1039 Ok(Value::Undef) | Ok(Value::Null) => v.clone(),
1040 Ok(_) => {
1041 diag(
1042 "E4021",
1043 format!("constant {name} is not numeric in a constant position"),
1044 );
1045 v.clone()
1046 }
1047 Err(Fail::Eval(e)) => {
1048 let code = if e.msg.contains("zero") {
1049 "E5001"
1050 } else if e.msg.contains("NaN") || e.msg.contains("Infinity") {
1051 "E5002"
1052 } else {
1053 "E5001"
1054 };
1055 diag(code, format!("evaluating constant {name}: {}", e.msg));
1056 v.clone()
1057 }
1058 Err(_) => v.clone(),
1059 }
1060 }
1061
1062 pub fn resolve_dim(&self, name: &str, visiting: &mut Vec<String>) -> Result<DimVec, String> {
1064 if let Some(v) = self.dim_memo.borrow().get(name) {
1065 return Ok(v.clone());
1066 }
1067 if visiting.iter().any(|v| v == name) {
1068 return Err(format!("circular dimension {name}"));
1069 }
1070 let decl = self
1071 .dim_decls
1072 .borrow()
1073 .get(name)
1074 .cloned()
1075 .ok_or_else(|| format!("unknown dimension {name}"))?;
1076 let mut vec = DimVec::new();
1077 match decl {
1078 None => {
1079 vec.insert(name.to_string(), 1);
1080 }
1081 Some(terms) => {
1082 visiting.push(name.to_string());
1083 for (tn, te) in terms {
1084 let sub = self.resolve_dim(&tn, visiting)?;
1085 for (n, e) in sub {
1086 *vec.entry(n).or_insert(0) += e * te;
1087 }
1088 }
1089 visiting.pop();
1090 }
1091 }
1092 self.dim_memo
1093 .borrow_mut()
1094 .insert(name.to_string(), vec.clone());
1095 Ok(vec)
1096 }
1097 pub fn unit_info(&self, sym: &str) -> Result<(String, f64), String> {
1098 self.unit_info_v(sym, &mut vec![])
1099 }
1100 pub fn finalize_unit_space(&self) -> Vec<Diag> {
1103 let mut out = self.space_diags.borrow().clone();
1104 let mut base_seen: HashMap<String, String> = HashMap::new();
1105 let syms = self.unit_order.borrow().clone();
1106 for sym in syms {
1107 let has_dim = self
1108 .unit_decls
1109 .borrow()
1110 .get(&sym)
1111 .map(|u| u.dim.is_some())
1112 .unwrap_or(false);
1113 match self.unit_info(&sym) {
1114 Ok((key, _)) => {
1115 if has_dim {
1116 if let Some(prev) = base_seen.get(&key) {
1117 out.push(Diag::error(
1118 format!(
1119 "second base unit {sym} for dimension {key} (base is {prev})"
1120 ),
1121 String::new(),
1122 Some("E4073"),
1123 ));
1124 } else {
1125 base_seen.insert(key, sym.clone());
1126 }
1127 }
1128 }
1129 Err(msg) => {
1130 let code = if msg.contains("unknown dimension")
1131 || msg.contains("circular dimension")
1132 {
1133 "E3003"
1134 } else {
1135 "E4073"
1136 };
1137 out.push(Diag::error(msg, String::new(), Some(code)));
1138 }
1139 }
1140 }
1141 out
1142 }
1143 fn unit_info_v(&self, sym: &str, visiting: &mut Vec<String>) -> Result<(String, f64), String> {
1144 if let Some(v) = self.unit_memo.borrow().get(sym) {
1145 return Ok(v.clone());
1146 }
1147 if visiting.iter().any(|v| v == sym) {
1148 return Err(format!("circular unit {sym}"));
1149 }
1150 let (dim, factor, base) = {
1151 let m = self.unit_decls.borrow();
1152 let u = m.get(sym).ok_or_else(|| format!("unknown unit {sym}"))?;
1153 (u.dim.clone(), u.factor.clone(), u.base.clone())
1154 };
1155 let info = if let Some(d) = dim {
1156 let key = key_of_vec(&self.resolve_dim(&d, &mut vec![])?);
1157 self.base_unit_of
1158 .borrow_mut()
1159 .entry(key.clone())
1160 .or_insert_with(|| sym.to_string());
1161 (key, 1.0)
1162 } else {
1163 visiting.push(sym.to_string());
1164 let b = self.unit_info_v(base.as_deref().unwrap_or(""), visiting)?;
1165 visiting.pop();
1166 let mut f: Option<f64> = match factor.as_deref() {
1167 Some(Expr::Lit(Value::Float(x))) => Some(*x),
1168 Some(Expr::Lit(Value::Int(i))) => i.to_f64(),
1169 _ => None,
1170 };
1171 if f.is_none() {
1172 if let (Some(fx), Some(ee)) = (factor.clone(), self.expr_eval.borrow().clone()) {
1173 f = match ee(&fx) {
1174 Ok(Value::Float(x)) => Some(x),
1175 Ok(Value::Int(i)) => i.to_f64(),
1176 _ => None,
1177 };
1178 }
1179 }
1180 let f = f.ok_or_else(|| format!("unit {sym}: factor is not a numeric constant"))?;
1181 (b.0, f * b.1)
1182 };
1183 self.unit_memo
1184 .borrow_mut()
1185 .insert(sym.to_string(), info.clone());
1186 Ok(info)
1187 }
1188
1189 pub fn resolve(self: &Rc<Env>, ast: &TypeAst, name: Option<&str>) -> Result<RT, String> {
1191 Ok(match ast {
1192 TypeAst::Prim { name: n, .. } => ty(RTk::Prim(n.clone())),
1193 TypeAst::Lit { v, .. } => ty(RTk::Lit(v.clone())),
1194 TypeAst::Range { lo, hi, excl, .. } => {
1195 let lo = self.const_num(lo);
1196 let hi = self.const_num(hi);
1197 let is_f = matches!(lo, Value::Float(_)) || matches!(hi, Value::Float(_));
1198 ty(RTk::Range {
1199 lo,
1200 hi,
1201 excl: *excl,
1202 base: if is_f { "float".into() } else { "int".into() },
1203 })
1204 }
1205 TypeAst::Pattern { re: src, .. } => {
1206 let expanded = self.expand_pattern(src)?;
1207 if let Some(bad) = pattern_error(&expanded) {
1208 return Err(format!("malformed pattern /{src}/: {bad}"));
1209 }
1210 let re = compile_pattern(&expanded)
1211 .map_err(|e| format!("malformed pattern /{src}/: {e}"))?;
1212 ty(RTk::Pattern { src: expanded, re })
1213 }
1214 TypeAst::Map { key, val, .. } => ty(RTk::Map {
1215 key: self.resolve(key, None)?,
1216 val: self.resolve(val, None)?,
1217 }),
1218 TypeAst::Array {
1219 elem, lo, hi, excl, ..
1220 } => {
1221 let lo = lo.as_ref().map(|v| self.const_num(v));
1222 let hi0 = hi.as_ref().map(|v| self.const_num(v));
1223 let to_i = |v: &Value| match v {
1224 Value::Int(i) => i.to_i64(),
1225 Value::Float(f) => Some(*f as i64),
1226 _ => None,
1227 };
1228 let lo_i = lo.as_ref().and_then(&to_i);
1229 let hi_i = hi0
1230 .as_ref()
1231 .and_then(to_i)
1232 .map(|h| if *excl { h - 1 } else { h });
1233 ty(RTk::Arr {
1234 elem: self.resolve(elem, None)?,
1235 lo: lo_i,
1236 hi: hi_i,
1237 })
1238 }
1239 TypeAst::Union { arms, .. } => ty(RTk::Union(
1240 arms.iter()
1241 .map(|a| self.resolve(a, None))
1242 .collect::<Result<_, _>>()?,
1243 )),
1244 TypeAst::Isect { arms, .. } => {
1245 let arms: Vec<RT> = arms
1246 .iter()
1247 .map(|a| self.resolve(a, None))
1248 .collect::<Result<_, _>>()?;
1249 if arms.iter().all(is_rec) {
1250 self.merge_isect(&arms, name)
1251 } else {
1252 ty(RTk::IsectN(arms))
1253 }
1254 }
1255 TypeAst::Record { members, open, .. } => {
1256 let rt = ty(RTk::Rec(rec_type(*open)));
1257 *rt.name.borrow_mut() = name.map(|s| s.to_string());
1258 self.fill_record(&rt, members)?;
1259 rt
1260 }
1261 TypeAst::Func { params, ret, .. } => ty(RTk::Func {
1262 params: params
1263 .iter()
1264 .map(|p| self.resolve(p, None))
1265 .collect::<Result<_, _>>()?,
1266 ret: self.resolve(ret, None)?,
1267 }),
1268 TypeAst::Named {
1269 name: n,
1270 args,
1271 preds,
1272 ext,
1273 ..
1274 } => {
1275 if let Some(preds) = preds {
1276 if !preds.is_empty() {
1277 let base = self.resolve(
1278 &TypeAst::Named {
1279 name: n.clone(),
1280 args: args.clone(),
1281 preds: None,
1282 ext: ext.clone(),
1283 loc: None,
1284 },
1285 name,
1286 )?;
1287 return Ok(ty(RTk::Pred {
1288 base,
1289 preds: preds.clone(),
1290 }));
1291 }
1292 }
1293 if n == "quantity" {
1294 let dn = match args.first() {
1295 Some(TypeAst::Named { name, .. }) | Some(TypeAst::Prim { name, .. }) => {
1296 name.clone()
1297 }
1298 _ => return Err("quantity needs a dimension".into()),
1299 };
1300 return Ok(ty(RTk::Quantity(key_of_vec(
1301 &self.resolve_dim(&dn, &mut vec![])?,
1302 ))));
1303 }
1304 if n == "map" && args.len() == 2 {
1305 return Ok(ty(RTk::Map {
1306 key: self.resolve(&args[0], None)?,
1307 val: self.resolve(&args[1], None)?,
1308 }));
1309 }
1310 if n == "ref" {
1311 return Ok(ty(RTk::Ref(self.resolve(&args[0], None)?)));
1312 }
1313 if ["int", "float", "bool", "string"].contains(&n.as_str())
1314 && args.is_empty()
1315 && ext.is_none()
1316 {
1317 return Ok(ty(RTk::Prim(n.clone())));
1318 }
1319 let decl = self.type_asts.borrow().get(n).cloned();
1320 let Some(decl) = decl else {
1321 let im = self.imports.borrow().get(n).cloned();
1322 if let Some(im) = im {
1323 return im.env.resolve(
1324 &TypeAst::Named {
1325 name: im.name.clone(),
1326 args: args.clone(),
1327 preds: None,
1328 ext: ext.clone(),
1329 loc: None,
1330 },
1331 name,
1332 );
1333 }
1334 if let Some((ns, rest)) = n.split_once('.') {
1335 let ex = self
1336 .namespaces
1337 .borrow()
1338 .get(ns)
1339 .and_then(|(_, exports)| exports.borrow().get(rest).cloned());
1340 if let Some(ex) = ex {
1341 return ex.env.resolve(
1342 &TypeAst::Named {
1343 name: ex.name.clone(),
1344 args: args.clone(),
1345 preds: None,
1346 ext: ext.clone(),
1347 loc: None,
1348 },
1349 name,
1350 );
1351 }
1352 }
1353 return Err(format!("unknown type {n}"));
1354 };
1355 let memo = self.type_memo.borrow().get(n).cloned();
1356 let base = if !decl.params.is_empty() {
1357 self.instantiate(n, args, &decl)?
1358 } else if let Some(b) = memo {
1359 b
1360 } else {
1361 match &decl.ast {
1362 TypeAst::Record { members, open, .. } => {
1363 let rt = ty(RTk::Rec(rec_type(*open)));
1364 *rt.name.borrow_mut() = Some(n.clone());
1365 *rt.tail.borrow_mut() = decl.tail.clone();
1366 self.type_memo.borrow_mut().insert(n.clone(), rt.clone());
1367 if let Err(e) = self.fill_record(&rt, members) {
1370 self.type_memo.borrow_mut().remove(n);
1371 return Err(e);
1372 }
1373 rt
1374 }
1375 TypeAst::Named {
1376 name: pn,
1377 args: pa,
1378 preds: pp,
1379 ext: Some(body),
1380 ..
1381 } => {
1382 let rt = ty(RTk::Rec(rec_type(false)));
1388 if let RTk::Rec(r) = &rt.k {
1389 r.filling.set(true);
1390 }
1391 *rt.name.borrow_mut() = Some(n.clone());
1392 *rt.tail.borrow_mut() = decl.tail.clone();
1393 self.type_memo.borrow_mut().insert(n.clone(), rt.clone());
1394 let parent_ast = TypeAst::Named {
1395 name: pn.clone(),
1396 args: pa.clone(),
1397 preds: pp.clone(),
1398 ext: None,
1399 loc: None,
1400 };
1401 let filled = self.resolve(&parent_ast, None).and_then(|parent| {
1402 let extr = self.resolve(body, None)?;
1403 self.extend_into(&rt, &parent, &extr);
1404 Ok(())
1405 });
1406 if let Err(e) = filled {
1407 self.type_memo.borrow_mut().remove(n);
1408 return Err(e);
1409 }
1410 rt
1411 }
1412 other => {
1413 let rt = self.resolve(other, Some(n))?;
1414 if matches!(rt.k, RTk::Rec(_) | RTk::Union(_)) {
1415 *rt.name.borrow_mut() = Some(n.clone());
1416 }
1417 if rt.tail.borrow().is_none() {
1418 *rt.tail.borrow_mut() = decl.tail.clone();
1419 }
1420 self.type_memo.borrow_mut().insert(n.clone(), rt.clone());
1421 rt
1422 }
1423 }
1424 };
1425 if let Some(ext) = ext {
1426 let extr = self.resolve(ext, None)?;
1428 if !is_rec(&base) {
1429 return Ok(base);
1430 }
1431 let merged = ty(RTk::Rec(rec_type(false)));
1432 if let RTk::Rec(r) = &merged.k {
1433 r.filling.set(true);
1434 }
1435 *merged.name.borrow_mut() = base.name.borrow().clone();
1436 self.extend_into(&merged, &base, &extr);
1437 return Ok(merged);
1438 }
1439 base
1440 }
1441 })
1442 }
1443
1444 fn extend_into(&self, target: &RT, base: &RT, extr: &RT) {
1451 let (RTk::Rec(tr), RTk::Rec(br), RTk::Rec(er)) = (&target.k, &base.k, &extr.k) else {
1452 if let RTk::Rec(tr) = &target.k {
1453 tr.filling.set(false);
1454 }
1455 return;
1456 };
1457 if br.filling.get() {
1458 br.pending.borrow_mut().push((target.clone(), extr.clone()));
1459 return;
1460 }
1461 tr.open.set(br.open.get());
1462 if let Some(t) = base.tail.borrow().clone() {
1463 *target.tail.borrow_mut() = Some(t);
1464 }
1465 let mut members: Vec<Member> = br.members.borrow().clone();
1466 for om in er.members.borrow().iter() {
1467 if let Some(i) = members.iter().position(|m| m.name == om.name) {
1468 members[i] = om.clone();
1469 } else {
1470 members.push(om.clone());
1471 }
1472 }
1473 let mut asserts = br.asserts.borrow().clone();
1474 asserts.extend(er.asserts.borrow().iter().cloned());
1475 let mut ctx_decls: Vec<(String, RT)> = br.ctx_decls.borrow().clone();
1476 for cd in er.ctx_decls.borrow().iter() {
1477 if let Some(i) = ctx_decls.iter().position(|(v, _)| *v == cd.0) {
1478 ctx_decls[i] = cd.clone();
1479 } else {
1480 ctx_decls.push(cd.clone());
1481 }
1482 }
1483 *tr.members.borrow_mut() = members;
1484 *tr.asserts.borrow_mut() = asserts;
1485 *tr.ctx_decls.borrow_mut() = ctx_decls;
1486 self.complete_record(target);
1487 }
1488
1489 fn complete_record(&self, rt: &RT) {
1491 let RTk::Rec(r) = &rt.k else { return };
1492 r.filling.set(false);
1493 let pending: Vec<(RT, RT)> = std::mem::take(&mut *r.pending.borrow_mut());
1494 for (target, extr) in pending {
1495 self.extend_into(&target, rt, &extr);
1496 }
1497 }
1498
1499 fn expand_pattern(self: &Rc<Env>, re: &str) -> Result<String, String> {
1504 let hole: &Regex = &PATTERN_HOLE;
1505 let mut out = String::new();
1506 let mut last = 0;
1507 for m in hole.captures_iter(re) {
1508 let whole = m.get(0).unwrap();
1509 out.push_str(&re[last..whole.start()]);
1510 last = whole.end();
1511 let text = m.get(1).unwrap().as_str().trim().to_string();
1512 let arms: Vec<String> = text.split('|').map(|a| a.trim().to_string()).collect();
1516 let mut frags: Vec<String> = vec![];
1517 let str_lit: &Regex = &PATTERN_STR_LIT;
1518 let int_range: &Regex = &PATTERN_INT_RANGE;
1519 let int_lit: &Regex = &PATTERN_INT_LIT;
1520 let ident: &Regex = &PATTERN_IDENT;
1521 for arm in &arms {
1522 if str_lit.is_match(arm) {
1523 let v = crate::parse::json_unquote(arm)?;
1524 frags.push(self.pattern_fragment(&ty(RTk::Lit(Value::Str(v))), &text)?);
1525 continue;
1526 }
1527 if let Some(c) = int_range.captures(arm) {
1528 let lo = c[1].parse::<BigInt>().map_err(|e| e.to_string())?;
1529 let hi = c[3].parse::<BigInt>().map_err(|e| e.to_string())?;
1530 let rt = ty(RTk::Range {
1531 lo: Value::Int(lo),
1532 hi: Value::Int(hi),
1533 excl: &c[2] == "<",
1534 base: "int".into(),
1535 });
1536 frags.push(self.pattern_fragment(&rt, &text)?);
1537 continue;
1538 }
1539 if int_lit.is_match(arm) {
1540 let v = arm.parse::<BigInt>().map_err(|e| e.to_string())?;
1541 frags.push(self.pattern_fragment(&ty(RTk::Lit(Value::Int(v))), &text)?);
1542 continue;
1543 }
1544 if !ident.is_match(arm) {
1545 return Err(format!(
1546 "pattern interpolation of {text}: not a type (§3.6)"
1547 ));
1548 }
1549 if self.pattern_visiting.borrow().iter().any(|v| v == arm) {
1550 return Err(format!("pattern interpolation of {arm} is circular"));
1551 }
1552 self.pattern_visiting.borrow_mut().push(arm.clone());
1553 let resolved = self.resolve(
1554 &TypeAst::Named {
1555 name: arm.clone(),
1556 args: vec![],
1557 preds: None,
1558 ext: None,
1559 loc: None,
1560 },
1561 None,
1562 );
1563 self.pattern_visiting.borrow_mut().retain(|v| v != arm);
1564 let rt = match resolved {
1565 Ok(rt) => rt,
1566 Err(e) => {
1567 if e.starts_with("unknown type") {
1568 return Err(format!("pattern interpolation of {arm}: unknown type"));
1569 }
1570 return Err(e);
1571 }
1572 };
1573 frags.push(self.pattern_fragment(&rt, arm)?);
1574 }
1575 if frags.len() == 1 {
1576 out.push_str(&frags[0]);
1577 } else {
1578 out.push_str(&format!("(?:{})", frags.join("|")));
1579 }
1580 }
1581 out.push_str(&re[last..]);
1582 Ok(out)
1583 }
1584 fn pattern_fragment(self: &Rc<Env>, rt: &RT, name: &str) -> Result<String, String> {
1585 let esc = |s: &str| -> String {
1586 let mut o = String::with_capacity(s.len());
1587 for c in s.chars() {
1588 if ".*+?^${}()|[]\\/".contains(c) {
1589 o.push('\\');
1590 }
1591 o.push(c);
1592 }
1593 o
1594 };
1595 let bad = || {
1596 Err(format!("pattern interpolation of {name}: type is neither string- nor integer-shaped (§3.6)"))
1597 };
1598 match &rt.k {
1599 RTk::Pattern { src, .. } => Ok(format!("(?:{src})")),
1600 RTk::Lit(Value::Str(s)) => Ok(esc(s)),
1601 RTk::Lit(Value::Int(i)) => Ok(i.to_string()),
1602 RTk::Lit(_) => bad(),
1603 RTk::Range { lo, hi, excl, base } => {
1604 let (Value::Int(lo), Value::Int(hi)) = (lo, hi) else {
1605 return bad();
1606 };
1607 if base != "int" {
1608 return bad();
1609 }
1610 let hi = if *excl { hi - 1 } else { hi.clone() };
1611 if &hi - lo >= BigInt::from(65536) {
1612 return Err(format!(
1613 "pattern interpolation of {name}: range too large (limit 65536 values)"
1614 ));
1615 }
1616 let mut alts: Vec<String> = vec![];
1617 let mut v = lo.clone();
1618 while v <= hi {
1619 alts.push(v.to_string());
1620 v += 1;
1621 }
1622 Ok(format!("(?:{})", alts.join("|")))
1623 }
1624 RTk::Union(arms) => {
1625 let parts = arms
1626 .iter()
1627 .map(|a| self.pattern_fragment(a, name))
1628 .collect::<Result<Vec<_>, _>>()?;
1629 Ok(format!("(?:{})", parts.join("|")))
1630 }
1631 RTk::Pred { base, .. } => self.pattern_fragment(base, name),
1632 RTk::Prim(n) if n == "string" => Ok(".*".into()),
1633 RTk::Prim(n) if n == "int" => Ok("-?[0-9]+".into()),
1634 _ => bad(),
1635 }
1636 }
1637
1638 fn instantiate(
1640 self: &Rc<Env>,
1641 name: &str,
1642 args: &[TypeAst],
1643 decl: &Rc<TypeEntry>,
1644 ) -> Result<RT, String> {
1645 let ps = &decl.params;
1646 if args.len() != ps.len() {
1647 return Err(format!(
1648 "generic arity: {name} expects {} argument(s), got {}",
1649 ps.len(),
1650 args.len()
1651 ));
1652 }
1653 let mut types: HashMap<String, TypeAst> = HashMap::new();
1654 let mut values: HashMap<String, Value> = HashMap::new();
1655 let mut label = Vec::new();
1656 for (p, a) in ps.iter().zip(args) {
1657 if let Some(pty) = &p.ty {
1658 let v = match a {
1659 TypeAst::Lit { v, .. } => v.clone(),
1660 TypeAst::Named {
1661 name: an,
1662 args: aa,
1663 ext: None,
1664 preds: None,
1665 ..
1666 } if aa.is_empty() => {
1667 let v = self.const_num(&Value::Str(an.clone()));
1668 if matches!(v, Value::Str(_)) {
1669 return Err(format!(
1670 "non-constant value argument {an} for {} of {name}",
1671 p.name
1672 ));
1673 }
1674 v
1675 }
1676 _ => {
1677 return Err(format!(
1678 "generic arity: parameter {} of {name} takes a constant value",
1679 p.name
1680 ))
1681 }
1682 };
1683 let bound = self.resolve(&subst_type(pty, &types, &values), None)?;
1684 if !crate::subsume::subsumes(self, &ty(RTk::Lit(v.clone())), &bound) {
1685 return Err(format!(
1686 "value argument {v:?} outside parameter {}'s type in {name}",
1687 p.name
1688 ));
1689 }
1690 label.push(format!("{v:?}"));
1691 values.insert(p.name.clone(), v);
1692 } else {
1693 label.push(match a {
1694 TypeAst::Named { name, .. } | TypeAst::Prim { name, .. } => name.clone(),
1695 _ => "type".into(),
1696 });
1697 types.insert(p.name.clone(), a.clone());
1698 }
1699 }
1700 let key = format!(
1701 "{name}<{}>",
1702 args.iter().map(type_key).collect::<Vec<_>>().join(",")
1703 );
1704 if let Some(rt) = self.type_memo.borrow().get(&key).cloned() {
1705 return Ok(rt);
1706 }
1707 let shown = format!("{name}<{}>", label.join(", "));
1708 let body = subst_type(&decl.ast, &types, &values);
1709 let rt = match &body {
1710 TypeAst::Record { members, open, .. } => {
1711 let rt = ty(RTk::Rec(rec_type(*open)));
1712 *rt.name.borrow_mut() = Some(shown);
1713 *rt.tail.borrow_mut() = decl.tail.clone();
1714 self.type_memo.borrow_mut().insert(key.clone(), rt.clone());
1715 if let Err(e) = self.fill_record(&rt, members) {
1716 self.type_memo.borrow_mut().remove(&key);
1717 return Err(e);
1718 }
1719 rt
1720 }
1721 other => {
1722 let rt = self.resolve(other, Some(&shown))?;
1723 if matches!(rt.k, RTk::Rec(_) | RTk::Union(_)) {
1724 *rt.name.borrow_mut() = Some(shown);
1725 }
1726 if rt.tail.borrow().is_none() {
1727 *rt.tail.borrow_mut() = decl.tail.clone();
1728 }
1729 self.type_memo.borrow_mut().insert(key, rt.clone());
1730 rt
1731 }
1732 };
1733 Ok(rt)
1734 }
1735
1736 fn fill_record(self: &Rc<Env>, rt: &RT, members: &[MemberAst]) -> Result<(), String> {
1737 let RTk::Rec(r) = &rt.k else { return Ok(()) };
1738 let origin = rt.name.borrow().clone();
1739 r.filling.set(true);
1740 for m in members {
1741 match m {
1742 MemberAst::Value {
1743 name,
1744 opt,
1745 ty: t,
1746 dflt,
1747 ..
1748 } => r.members.borrow_mut().push(Member {
1749 kind: if dflt.is_some() {
1750 MKind::Dflt
1751 } else if *opt {
1752 MKind::Opt
1753 } else {
1754 MKind::Req
1755 },
1756 name: name.clone(),
1757 hidden: false,
1758 ty: Some(self.resolve(t, None)?),
1759 conj: None,
1760 dflt: dflt.clone(),
1761 expr: None,
1762 menv: Some(self.clone()),
1763 }),
1764 MemberAst::Derived {
1765 name,
1766 ty: t,
1767 expr,
1768 hidden,
1769 ..
1770 } => r.members.borrow_mut().push(Member {
1771 kind: MKind::Der,
1772 name: name.clone(),
1773 hidden: *hidden,
1774 ty: match t {
1775 Some(t) => Some(self.resolve(t, None)?),
1776 None => None,
1777 },
1778 conj: None,
1779 dflt: None,
1780 expr: Some(expr.clone()),
1781 menv: Some(self.clone()),
1782 }),
1783 MemberAst::Assert {
1784 name, cond, tail, ..
1785 } => r.asserts.borrow_mut().push(AssertItem {
1786 when: false,
1787 name: name.clone(),
1788 cond: cond.clone(),
1789 tail: tail.clone(),
1790 body: vec![],
1791 origin: origin.clone(),
1792 menv: Some(self.clone()),
1793 }),
1794 MemberAst::When { cond, body, .. } => r.asserts.borrow_mut().push(AssertItem {
1795 when: true,
1796 name: String::new(),
1797 cond: cond.clone(),
1798 tail: None,
1799 body: body.clone(),
1800 origin: origin.clone(),
1801 menv: Some(self.clone()),
1802 }),
1803 MemberAst::Context {
1804 variable, ty: t, ..
1805 } => r
1806 .ctx_decls
1807 .borrow_mut()
1808 .push((variable.clone(), self.resolve(t, None)?)),
1809 }
1810 }
1811 self.complete_record(rt);
1812 Ok(())
1813 }
1814
1815 fn merge_isect(&self, arms: &[RT], name: Option<&str>) -> RT {
1816 let mut members: Vec<Member> = vec![];
1817 let mut asserts: Vec<AssertItem> = vec![];
1818 let mut open = true;
1819 for a in arms {
1820 let RTk::Rec(r) = &a.k else { continue };
1821 open = open && r.open.get();
1822 for m in r.members.borrow().iter() {
1823 if let Some(i) = members.iter().position(|x| x.name == m.name) {
1824 let prev = members[i].clone();
1825 let mut conj = prev
1826 .conj
1827 .clone()
1828 .unwrap_or_else(|| prev.ty.iter().cloned().collect());
1829 if let Some(t) = &m.ty {
1830 conj.push(t.clone());
1831 }
1832 members[i] = Member {
1833 conj: Some(conj),
1834 kind: if m.kind == MKind::Req {
1835 MKind::Req
1836 } else {
1837 prev.kind
1838 },
1839 ..prev
1840 };
1841 } else {
1842 members.push(m.clone());
1843 }
1844 }
1845 asserts.extend(r.asserts.borrow().iter().map(|x| AssertItem {
1846 origin: x.origin.clone().or_else(|| a.name.borrow().clone()),
1847 ..x.clone()
1848 }));
1849 }
1850 let rec = rec_type(open);
1851 *rec.members.borrow_mut() = members;
1852 *rec.asserts.borrow_mut() = asserts;
1853 let rt = ty(RTk::Rec(rec));
1854 *rt.name.borrow_mut() = name.map(|s| s.to_string());
1855 rt
1856 }
1857}
1858
1859fn type_key(t: &TypeAst) -> String {
1860 match t {
1861 TypeAst::Prim { name: n, .. } => format!("p:{n}"),
1862 TypeAst::Lit { v, .. } => format!("l:{v:?}"),
1863 TypeAst::Named { name, args, .. } => format!(
1864 "n:{name}<{}>",
1865 args.iter().map(type_key).collect::<Vec<_>>().join(",")
1866 ),
1867 TypeAst::Range { lo, hi, excl, .. } => format!("r:{lo:?}..{excl}{hi:?}"),
1868 TypeAst::Array { elem, lo, hi, .. } => format!("a:{}[{lo:?},{hi:?}]", type_key(elem)),
1869 TypeAst::Union { arms: a, .. } => {
1870 format!("u:{}", a.iter().map(type_key).collect::<Vec<_>>().join("|"))
1871 }
1872 TypeAst::Isect { arms: a, .. } => {
1873 format!("i:{}", a.iter().map(type_key).collect::<Vec<_>>().join("&"))
1874 }
1875 TypeAst::Map { key, val, .. } => format!("m:{}:{}", type_key(key), type_key(val)),
1876 TypeAst::Pattern { re: p, .. } => format!("pat:{p}"),
1877 TypeAst::Record { members, .. } => format!("rec:{}", members.len()),
1878 TypeAst::Func { params, ret, .. } => format!("f:{}->{}", params.len(), type_key(ret)),
1879 }
1880}
1881
1882pub fn subst_type(
1884 ast: &TypeAst,
1885 types: &HashMap<String, TypeAst>,
1886 values: &HashMap<String, Value>,
1887) -> TypeAst {
1888 let t = |a: &TypeAst| subst_type(a, types, values);
1889 match ast {
1890 TypeAst::Named {
1891 name,
1892 args,
1893 preds,
1894 ext,
1895 loc,
1896 } => {
1897 let plain = args.is_empty() && ext.is_none() && preds.is_none();
1898 if plain {
1899 if let Some(x) = types.get(name) {
1900 return x.clone();
1901 }
1902 if let Some(v) = values.get(name) {
1903 return TypeAst::Lit {
1904 v: v.clone(),
1905 loc: *loc,
1906 };
1907 }
1908 }
1909 TypeAst::Named {
1910 name: name.clone(),
1911 args: args.iter().map(t).collect(),
1912 preds: preds
1913 .as_ref()
1914 .map(|ps| ps.iter().map(|p| subst_expr(p, values)).collect()),
1915 ext: ext.as_ref().map(|e| Box::new(t(e))),
1916 loc: *loc,
1917 }
1918 }
1919 TypeAst::Range { lo, hi, excl, loc } => {
1920 let sub = |v: &Value| match v {
1921 Value::Str(s) if values.contains_key(s) => values[s].clone(),
1922 other => other.clone(),
1923 };
1924 TypeAst::Range {
1925 lo: sub(lo),
1926 hi: sub(hi),
1927 excl: *excl,
1928 loc: *loc,
1929 }
1930 }
1931 TypeAst::Array {
1932 elem,
1933 lo,
1934 hi,
1935 excl,
1936 loc,
1937 } => {
1938 let sub = |v: &Value| match v {
1939 Value::Str(s) if values.contains_key(s) => values[s].clone(),
1940 other => other.clone(),
1941 };
1942 TypeAst::Array {
1943 elem: Box::new(t(elem)),
1944 lo: lo.as_ref().map(sub),
1945 hi: hi.as_ref().map(sub),
1946 excl: *excl,
1947 loc: *loc,
1948 }
1949 }
1950 TypeAst::Record { members, open, loc } => TypeAst::Record {
1951 members: members
1952 .iter()
1953 .map(|m| subst_member(m, types, values))
1954 .collect(),
1955 open: *open,
1956 loc: *loc,
1957 },
1958 TypeAst::Map { key, val, loc } => TypeAst::Map {
1959 key: Box::new(t(key)),
1960 val: Box::new(t(val)),
1961 loc: *loc,
1962 },
1963 TypeAst::Union { arms: a, loc } => TypeAst::Union {
1964 arms: a.iter().map(t).collect(),
1965 loc: *loc,
1966 },
1967 TypeAst::Isect { arms: a, loc } => TypeAst::Isect {
1968 arms: a.iter().map(t).collect(),
1969 loc: *loc,
1970 },
1971 TypeAst::Func { params, ret, loc } => TypeAst::Func {
1972 params: params.iter().map(t).collect(),
1973 ret: Box::new(t(ret)),
1974 loc: *loc,
1975 },
1976 other => other.clone(),
1977 }
1978}
1979fn subst_member(
1980 m: &MemberAst,
1981 types: &HashMap<String, TypeAst>,
1982 values: &HashMap<String, Value>,
1983) -> MemberAst {
1984 let t = |a: &TypeAst| subst_type(a, types, values);
1985 match m {
1986 MemberAst::Value {
1987 name,
1988 opt,
1989 ty,
1990 dflt,
1991 loc,
1992 } => MemberAst::Value {
1993 name: name.clone(),
1994 opt: *opt,
1995 ty: t(ty),
1996 dflt: dflt.as_ref().map(|d| subst_expr(d, values)),
1997 loc: *loc,
1998 },
1999 MemberAst::Derived {
2000 name,
2001 ty,
2002 expr,
2003 hidden,
2004 loc,
2005 } => MemberAst::Derived {
2006 name: name.clone(),
2007 ty: ty.as_ref().map(t),
2008 expr: subst_expr(expr, values),
2009 hidden: *hidden,
2010 loc: *loc,
2011 },
2012 MemberAst::Context { variable, ty, loc } => MemberAst::Context {
2013 variable: variable.clone(),
2014 ty: t(ty),
2015 loc: *loc,
2016 },
2017 MemberAst::Assert {
2018 name,
2019 cond,
2020 tail,
2021 loc,
2022 } => MemberAst::Assert {
2023 name: name.clone(),
2024 cond: subst_expr(cond, values),
2025 tail: tail.clone(),
2026 loc: *loc,
2027 },
2028 MemberAst::When { cond, body, loc } => MemberAst::When {
2029 cond: subst_expr(cond, values),
2030 body: body
2031 .iter()
2032 .map(|b| subst_member(b, types, values))
2033 .collect(),
2034 loc: *loc,
2035 },
2036 }
2037}
2038pub fn subst_expr(e: &Rc<Expr>, values: &HashMap<String, Value>) -> Rc<Expr> {
2039 if values.is_empty() {
2040 return e.clone();
2041 }
2042 let s = |x: &Rc<Expr>| subst_expr(x, values);
2043 let cls = |c: &ForClause| ForClause {
2044 v: c.v.clone(),
2045 iter: s(&c.iter),
2046 filters: c.filters.iter().map(s).collect(),
2047 };
2048 let out = Rc::new(match &**e {
2049 Expr::Name(n) if values.contains_key(n) => Expr::Lit(values[n].clone()),
2050 Expr::Template(parts) => Expr::Template(
2051 parts
2052 .iter()
2053 .map(|p| match p {
2054 TPart::Expr(x) => TPart::Expr(s(x)),
2055 other => other.clone(),
2056 })
2057 .collect(),
2058 ),
2059 Expr::Obj(es) => Expr::Obj(es.iter().map(|(k, v)| (k.clone(), s(v))).collect()),
2060 Expr::Arr(items) => Expr::Arr(items.iter().map(|(sp, v)| (*sp, s(v))).collect()),
2061 Expr::Comp { head, clauses } => Expr::Comp {
2062 head: s(head),
2063 clauses: clauses.iter().map(cls).collect(),
2064 },
2065 Expr::MapComp { key, val, clauses } => Expr::MapComp {
2066 key: s(key),
2067 val: s(val),
2068 clauses: clauses.iter().map(cls).collect(),
2069 },
2070 Expr::Bin { op, l, r } => Expr::Bin {
2071 op: op.clone(),
2072 l: s(l),
2073 r: s(r),
2074 },
2075 Expr::Un { op, x } => Expr::Un {
2076 op: op.clone(),
2077 x: s(x),
2078 },
2079 Expr::Paren(x) => Expr::Paren(s(x)),
2080 Expr::If { c, t, f } => Expr::If {
2081 c: s(c),
2082 t: s(t),
2083 f: s(f),
2084 },
2085 Expr::Lambda { params, body } => Expr::Lambda {
2086 params: params.clone(),
2087 body: s(body),
2088 },
2089 Expr::Call { fun, args } => Expr::Call {
2090 fun: s(fun),
2091 args: args.iter().map(s).collect(),
2092 },
2093 Expr::Member { x, name, safe } => Expr::Member {
2094 x: s(x),
2095 name: name.clone(),
2096 safe: *safe,
2097 },
2098 Expr::Index { x, i } => Expr::Index { x: s(x), i: s(i) },
2099 Expr::With { base, patch } => Expr::With {
2100 base: s(base),
2101 patch: s(patch),
2102 },
2103 Expr::Match { subject, arms } => Expr::Match {
2104 subject: s(subject),
2105 arms: arms
2106 .iter()
2107 .map(|a| MatchArm {
2108 v: a.v.clone(),
2109 ty: a.ty.clone(),
2110 body: s(&a.body),
2111 })
2112 .collect(),
2113 },
2114 other => other.clone(),
2115 });
2116 if let Some(l) = expr_loc(e) {
2118 set_expr_loc(&out, l);
2119 }
2120 out
2121}
2122
2123const PATTERN_PUNCT: &str = "\\/.*+?()[]{}|^$-";
2130fn pattern_escape(cs: &[char], i: &mut usize) -> Result<i64, String> {
2131 if *i + 1 >= cs.len() {
2132 return Err("trailing backslash".into());
2133 }
2134 let e = cs[*i + 1];
2135 *i += 2;
2136 if "dwsDWS".contains(e) {
2137 return Ok(-1);
2138 }
2139 match e {
2140 'n' => return Ok(10),
2141 't' => return Ok(9),
2142 'r' => return Ok(13),
2143 _ => {}
2144 }
2145 if PATTERN_PUNCT.contains(e) {
2146 return Ok(e as i64);
2147 }
2148 if e.is_ascii_digit() {
2149 return Err(format!("backreference \\{e} is not supported"));
2150 }
2151 Err(format!("unsupported escape \\{e}"))
2152}
2153pub fn pattern_error(src: &str) -> Option<String> {
2154 let cs: Vec<char> = src.chars().collect();
2155 let n = cs.len();
2156 let (mut i, mut depth, mut can_repeat) = (0usize, 0i32, false);
2157 while i < n {
2158 match cs[i] {
2159 '\\' => {
2160 if let Err(r) = pattern_escape(&cs, &mut i) {
2161 return Some(r);
2162 }
2163 can_repeat = true;
2164 }
2165 '[' => {
2166 i += 1;
2167 if i < n && cs[i] == '^' {
2168 i += 1;
2169 }
2170 let mut items = 0;
2171 loop {
2172 if i >= n {
2173 return Some("unterminated character class".into());
2174 }
2175 if cs[i] == ']' {
2176 i += 1;
2177 break;
2178 }
2179 let lo = if cs[i] == '\\' {
2180 match pattern_escape(&cs, &mut i) {
2181 Ok(v) => v,
2182 Err(r) => return Some(r),
2183 }
2184 } else {
2185 let v = cs[i] as i64;
2186 i += 1;
2187 v
2188 };
2189 if i < n && cs[i] == '-' && i + 1 < n && cs[i + 1] != ']' {
2190 i += 1;
2191 let hi = if cs[i] == '\\' {
2192 match pattern_escape(&cs, &mut i) {
2193 Ok(v) => v,
2194 Err(r) => return Some(r),
2195 }
2196 } else {
2197 let v = cs[i] as i64;
2198 i += 1;
2199 v
2200 };
2201 if lo < 0 || hi < 0 || lo > hi {
2202 return Some("invalid range in character class".into());
2203 }
2204 }
2205 items += 1;
2206 }
2207 if items == 0 {
2208 return Some("empty character class".into());
2209 }
2210 can_repeat = true;
2211 }
2212 ']' => return Some("unbalanced bracket".into()),
2213 '(' => {
2214 i += 1;
2215 if i < n && cs[i] == '?' {
2216 if i + 1 < n && cs[i + 1] == ':' {
2217 i += 2;
2218 } else {
2219 return Some("unsupported construct (?".into());
2220 }
2221 }
2222 depth += 1;
2223 can_repeat = false;
2224 }
2225 ')' => {
2226 if depth == 0 {
2227 return Some("unbalanced parenthesis".into());
2228 }
2229 depth -= 1;
2230 i += 1;
2231 can_repeat = true;
2232 }
2233 '|' => {
2234 i += 1;
2235 can_repeat = false;
2236 }
2237 '*' | '+' | '?' => {
2238 if !can_repeat {
2239 return Some("nothing to repeat".into());
2240 }
2241 i += 1;
2242 can_repeat = false;
2243 }
2244 '{' => {
2245 if !can_repeat {
2246 return Some("nothing to repeat".into());
2247 }
2248 let mut j = i + 1;
2249 let start = j;
2250 while j < n && cs[j].is_ascii_digit() {
2251 j += 1;
2252 }
2253 if j == start {
2254 return Some("malformed repetition".into());
2255 }
2256 let m: String = cs[start..j].iter().collect();
2257 let mut hi: Option<String> = None;
2258 if j < n && cs[j] == ',' {
2259 j += 1;
2260 let s2 = j;
2261 while j < n && cs[j].is_ascii_digit() {
2262 j += 1;
2263 }
2264 if j > s2 {
2265 hi = Some(cs[s2..j].iter().collect());
2266 }
2267 }
2268 if j >= n || cs[j] != '}' {
2269 return Some("malformed repetition".into());
2270 }
2271 if let Some(h) = hi {
2272 if h.parse::<BigInt>().unwrap_or_default()
2273 < m.parse::<BigInt>().unwrap_or_default()
2274 {
2275 return Some("malformed repetition".into());
2276 }
2277 }
2278 i = j + 1;
2279 can_repeat = false;
2280 }
2281 '}' => return Some("malformed repetition".into()),
2282 '^' | '$' => {
2283 i += 1;
2284 can_repeat = false;
2285 }
2286 _ => {
2287 i += 1;
2288 can_repeat = true;
2289 }
2290 }
2291 }
2292 if depth > 0 {
2293 Some("unbalanced parenthesis".into())
2294 } else {
2295 None
2296 }
2297}
2298pub fn compile_pattern(src: &str) -> Result<Regex, String> {
2299 Regex::new(&format!("^(?:{src})$")).map_err(|e| e.to_string())
2300}
2301
2302pub fn path_str(segs: &[Seg], rel_root: Option<&str>) -> String {
2303 let mut out = String::new();
2304 for (i, s) in segs.iter().enumerate() {
2305 match s {
2306 _ if i == 0 => {
2307 let n = seg_text(s);
2308 if rel_root == Some(n.as_str()) {
2309 out.push('$');
2310 } else {
2311 out.push_str(&n);
2312 }
2313 }
2314 Seg::Idx(k) => out.push_str(&format!("[{k}]")),
2315 Seg::Key(n) => out.push_str(&format!("[{}]", json_str(n))),
2316 Seg::Name(n) if dot_spellable(n) => {
2317 out.push('.');
2318 out.push_str(n);
2319 }
2320 Seg::Name(n) => out.push_str(&format!("[{}]", json_str(n))),
2321 }
2322 }
2323 out
2324}
2325
2326pub fn parse_path(s: &str, root_name: &str) -> R<SegPath> {
2330 let id_re = Regex::new(r"^[_A-Za-z][_A-Za-z0-9]*").unwrap();
2331 let mut segs = vec![];
2332 let mut i = if s.starts_with('$') {
2333 segs.push(Seg::Name(root_name.to_string()));
2334 1
2335 } else {
2336 let m = id_re
2337 .find(s)
2338 .ok_or(())
2339 .or_else(|_| err(format!("bad path {s}")))?;
2340 segs.push(Seg::Name(m.as_str().to_string()));
2341 m.end()
2342 };
2343 while i < s.len() {
2344 let rest = &s[i..];
2345 if let Some(r) = rest.strip_prefix('.') {
2346 let m = id_re
2347 .find(r)
2348 .ok_or(())
2349 .or_else(|_| err(format!("bad path {s}")))?;
2350 segs.push(Seg::Name(m.as_str().to_string()));
2351 i += 1 + m.end();
2352 } else if rest.starts_with('[') {
2353 let j = rest
2354 .find(']')
2355 .ok_or(())
2356 .or_else(|_| err(format!("bad path {s}")))?;
2357 let inner = &rest[1..j];
2358 if inner.starts_with('"') {
2359 segs.push(Seg::Key(
2360 crate::parse::json_unquote(inner).unwrap_or_default(),
2361 ));
2362 } else {
2363 segs.push(Seg::Idx(inner.parse().unwrap_or(0)));
2364 }
2365 i += j + 1;
2366 } else {
2367 return err(format!("bad path {s}"));
2368 }
2369 }
2370 Ok(segs)
2371}
2372
2373pub fn cmp_path(a: &[Seg], b: &[Seg]) -> std::cmp::Ordering {
2376 for (x, y) in a.iter().zip(b) {
2377 match (x, y) {
2378 (Seg::Idx(i), Seg::Idx(j)) => {
2379 if i != j {
2380 return i.cmp(j);
2381 }
2382 }
2383 _ => {
2384 let xs = seg_text(x);
2385 let ys = seg_text(y);
2386 if xs != ys {
2387 return xs.cmp(&ys);
2388 }
2389 }
2390 }
2391 }
2392 a.len().cmp(&b.len())
2393}
2394
2395pub fn value_eq(a: &Value, b: &Value) -> bool {
2396 let (pa, pb) = (a.place(), b.place());
2397 if let (Some(pa), Some(pb)) = (&pa, &pb) {
2398 if matches!(a, Value::Ref(_)) || matches!(b, Value::Ref(_)) {
2399 return cmp_path(pa, pb) == std::cmp::Ordering::Equal;
2400 }
2401 }
2402 match (a, b) {
2403 (Value::Int(x), Value::Int(y)) => x == y,
2404 (Value::Float(x), Value::Float(y)) => x == y,
2405 (Value::Str(x), Value::Str(y)) => x == y,
2406 (Value::Bool(x), Value::Bool(y)) => x == y,
2407 (Value::Null, Value::Null) => true,
2408 (Value::Undef, Value::Undef) => true,
2410 (Value::Q { dim: d1, value: v1 }, Value::Q { dim: d2, value: v2 }) => d1 == d2 && v1 == v2,
2411 (Value::Arr(x), Value::Arr(y)) => {
2412 let (x, y) = (x.borrow(), y.borrow());
2413 x.items.len() == y.items.len()
2414 && x.items.iter().zip(&y.items).all(|(p, q)| value_eq(p, q))
2415 }
2416 (Value::Map(x), Value::Map(y)) => {
2417 let (x, y) = (x.borrow(), y.borrow());
2418 x.entries.len() == y.entries.len()
2419 && x.entries
2420 .iter()
2421 .all(|(k, v)| y.get(k).map(|w| value_eq(v, w)).unwrap_or(false))
2422 }
2423 (Value::Rec(x), Value::Rec(y)) => {
2424 if Rc::ptr_eq(x, y) {
2425 return true;
2426 }
2427 let (x, y) = (x.borrow(), y.borrow());
2428 for (n, s) in &x.slots {
2429 if s.hidden {
2430 continue; }
2432 let v1 = if s.state == SlotState::Absent {
2433 Value::Absent
2434 } else {
2435 s.value.clone()
2436 };
2437 let v2 = match y.slot(n) {
2438 Some(s2) if s2.state != SlotState::Absent => s2.value.clone(),
2439 _ => Value::Absent,
2440 };
2441 match (&v1, &v2) {
2442 (Value::Absent, Value::Absent) => continue,
2443 (Value::Absent, _) | (_, Value::Absent) => return false,
2444 _ => {
2445 if !value_eq(&v1, &v2) {
2446 return false;
2447 }
2448 }
2449 }
2450 }
2451 true
2452 }
2453 _ => false,
2454 }
2455}
2456
2457pub fn read_json(src: &str) -> R<Value> {
2459 let b = src.as_bytes();
2460 let mut i = 0usize;
2461 fn ws(b: &[u8], i: &mut usize) {
2462 while *i < b.len() && matches!(b[*i], b' ' | b'\t' | b'\r' | b'\n') {
2463 *i += 1;
2464 }
2465 }
2466 fn string(src: &str, b: &[u8], i: &mut usize) -> R<String> {
2467 let mut j = *i + 1;
2468 let mut out = String::new();
2469 while j < b.len() && b[j] != b'"' {
2470 if b[j] == b'\\' {
2471 let e = b[j + 1] as char;
2472 match e {
2473 'n' => out.push('\n'),
2474 't' => out.push('\t'),
2475 'r' => out.push('\r'),
2476 'b' => out.push('\u{8}'),
2477 'f' => out.push('\u{c}'),
2478 'u' => {
2479 let cp = u32::from_str_radix(&src[j + 2..j + 6], 16).unwrap_or(0xfffd);
2480 out.push(char::from_u32(cp).unwrap_or('\u{fffd}'));
2481 j += 4;
2482 }
2483 other => out.push(other),
2484 }
2485 j += 2;
2486 } else {
2487 let ch = src[j..].chars().next().unwrap();
2488 out.push(ch);
2489 j += ch.len_utf8();
2490 }
2491 }
2492 *i = j + 1;
2493 Ok(out)
2494 }
2495 fn val(src: &str, b: &[u8], i: &mut usize) -> R<Value> {
2496 ws(b, i);
2497 if *i >= b.len() {
2498 return err("bad JSON: unexpected end");
2499 }
2500 match b[*i] {
2501 b'{' => {
2502 *i += 1;
2503 let mut entries = vec![];
2504 ws(b, i);
2505 if b[*i] == b'}' {
2506 *i += 1;
2507 return Ok(Value::JObj(Rc::new(entries)));
2508 }
2509 loop {
2510 ws(b, i);
2511 let k = string(src, b, i)?;
2512 ws(b, i);
2513 *i += 1;
2514 let v = val(src, b, i)?;
2515 entries.push((k, v));
2516 ws(b, i);
2517 if b[*i] == b',' {
2518 *i += 1;
2519 continue;
2520 }
2521 *i += 1;
2522 return Ok(Value::JObj(Rc::new(entries)));
2523 }
2524 }
2525 b'[' => {
2526 *i += 1;
2527 let mut items = vec![];
2528 ws(b, i);
2529 if b[*i] == b']' {
2530 *i += 1;
2531 return Ok(Value::JArr(Rc::new(items)));
2532 }
2533 loop {
2534 items.push(val(src, b, i)?);
2535 ws(b, i);
2536 if b[*i] == b',' {
2537 *i += 1;
2538 continue;
2539 }
2540 *i += 1;
2541 return Ok(Value::JArr(Rc::new(items)));
2542 }
2543 }
2544 b'"' => Ok(Value::Str(string(src, b, i)?)),
2545 _ => {
2546 let rest = &src[*i..];
2547 if rest.starts_with("true") {
2548 *i += 4;
2549 return Ok(Value::Bool(true));
2550 }
2551 if rest.starts_with("false") {
2552 *i += 5;
2553 return Ok(Value::Bool(false));
2554 }
2555 if rest.starts_with("null") {
2556 *i += 4;
2557 return Ok(Value::Null);
2558 }
2559 let re = Regex::new(r"^-?(?:0|[1-9][0-9]*)(\.[0-9]+)?([eE][-+]?[0-9]+)?").unwrap();
2560 let m = re
2561 .captures(rest)
2562 .ok_or(())
2563 .or_else(|_| err(format!("bad JSON at {i}")))?;
2564 let whole = m.get(0).unwrap().as_str();
2565 *i += whole.len();
2566 if m.get(1).is_some() || m.get(2).is_some() {
2567 Ok(Value::Float(whole.parse::<f64>().unwrap_or(0.0)))
2568 } else {
2569 Ok(Value::Int(
2570 whole.parse::<BigInt>().unwrap_or_else(|_| BigInt::zero()),
2571 ))
2572 }
2573 }
2574 }
2575 }
2576 let v = val(src, b, &mut i)?;
2577 ws(b, &mut i);
2578 if i < b.len() {
2579 return err("bad JSON: trailing characters");
2580 }
2581 Ok(v)
2582}
2583
2584pub fn js_num_str(x: f64) -> String {
2587 if x == 0.0 {
2588 return "0".into();
2589 }
2590 let sci = format!("{:e}", x.abs());
2591 let (mant, exp) = sci.split_once('e').unwrap();
2592 let exp: i32 = exp.parse().unwrap();
2593 let digits: String = mant.chars().filter(|c| *c != '.').collect();
2594 let digits = digits.trim_end_matches('0');
2595 let digits = if digits.is_empty() { "0" } else { digits };
2596 let k = digits.len() as i32;
2597 let n = exp + 1;
2598 let body = if k <= n && n <= 21 {
2599 format!("{digits}{}", "0".repeat((n - k) as usize))
2600 } else if 0 < n && n <= 21 {
2601 format!("{}.{}", &digits[..n as usize], &digits[n as usize..])
2602 } else if -6 < n && n <= 0 {
2603 format!("0.{}{digits}", "0".repeat((-n) as usize))
2604 } else {
2605 let e = n - 1;
2606 let mant = if k > 1 {
2607 format!("{}.{}", &digits[..1], &digits[1..])
2608 } else {
2609 digits.to_string()
2610 };
2611 format!("{mant}e{}{}", if e > 0 { "+" } else { "-" }, e.abs())
2612 };
2613 if x < 0.0 {
2614 format!("-{body}")
2615 } else {
2616 body
2617 }
2618}
2619
2620pub fn json_str(s: &str) -> String {
2621 let mut out = String::with_capacity(s.len() + 2);
2622 out.push('"');
2623 for c in s.chars() {
2624 match c {
2625 '"' => out.push_str("\\\""),
2626 '\\' => out.push_str("\\\\"),
2627 '\n' => out.push_str("\\n"),
2628 '\r' => out.push_str("\\r"),
2629 '\t' => out.push_str("\\t"),
2630 '\u{8}' => out.push_str("\\b"),
2631 '\u{c}' => out.push_str("\\f"),
2632 c if (c as u32) < 0x20 => out.push_str(&format!("\\u{:04x}", c as u32)),
2633 c => out.push(c),
2634 }
2635 }
2636 out.push('"');
2637 out
2638}