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