Skip to main content

shape/
expr.rs

1//! The string form of a spec: `"String.Min(2)"`, `"Min(2, Number)"`,
2//! `"One(String, Number)"`. Builder names, type tokens, JSON literals and
3//! `/regexp/` tokens, chained with dots and given arguments in parentheses.
4
5use crate::algebra::{extend_node, omit_node, partial_node, pick_node, Names};
6use crate::builders::*;
7use crate::node::{Kind, Node, Token};
8use crate::normalize::{literal_node, nan_node, normalize, regexp_node_src};
9use crate::spec::Spec;
10use crate::value::Value;
11use regex::Regex;
12use std::fmt;
13use std::sync::OnceLock;
14
15/// An expression that does not parse.
16#[derive(Clone, Debug, PartialEq, Eq)]
17pub struct ExprError(pub String);
18
19impl fmt::Display for ExprError {
20    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
21        f.write_str(&self.0)
22    }
23}
24
25impl std::error::Error for ExprError {}
26
27fn err<T>(msg: String) -> Result<T, ExprError> {
28    Err(ExprError(msg))
29}
30
31/// Parse an expression into a node.
32pub fn expr(src: &str) -> Result<Node, ExprError> {
33    let tokens = tokenize(src)?;
34    let mut p = Parser::new(tokens, src);
35    p.parse_full()
36}
37
38/// Apply an expression to an existing carrier: every builder of the chain
39/// takes the carrier as its final argument, so `"Open"` opens an object
40/// rather than replacing it. What value expressions and key expressions do.
41pub fn expr_apply(src: &str, carrier: Spec) -> Result<Node, ExprError> {
42    let tokens = tokenize(src)?;
43    let mut p = Parser::new(tokens, src);
44    let mut val = carrier;
45    while !p.peek().is_empty() {
46        if p.peek() == "." {
47            p.take();
48        }
49        val = Spec::from(p.parse_chained(val)?);
50    }
51    Ok(normalize(val))
52}
53
54fn token_re() -> &'static Regex {
55    static RE: OnceLock<Regex> = OnceLock::new();
56    RE.get_or_init(|| {
57        Regex::new(
58            r#"\s*,?\s*(-?\d+\.\d+(?:[eE][+-]?\d+)?|[)(.]|"(?:\\.|[^"\\])*"|/(?:\\.|[^/\\])*/[a-z]?|[^)(,.\s]+)\s*"#,
59        )
60        .unwrap()
61    })
62}
63
64fn tokenize(src: &str) -> Result<Vec<String>, ExprError> {
65    if src.trim().is_empty() {
66        return err("Shape: empty expression".to_string());
67    }
68    let mut tokens = Vec::new();
69    let mut pos = 0;
70    for m in token_re().captures_iter(src) {
71        let whole = m.get(0).unwrap();
72        if whole.start() != pos {
73            return err(format!(
74                "Shape: unexpected character at offset {} in expression {:?}",
75                pos, src
76            ));
77        }
78        pos = whole.end();
79        tokens.push(m.get(1).unwrap().as_str().to_string());
80    }
81    if pos != src.len() {
82        return err(format!(
83            "Shape: unexpected trailing text in expression {:?}",
84            src
85        ));
86    }
87    Ok(tokens)
88}
89
90struct Parser<'s> {
91    tokens: Vec<String>,
92    src: &'s str,
93    i: usize,
94    /// The sidecars of a value expression ("$$0"), specs an expression
95    /// cannot spell inline, by their keys.
96    refs: std::collections::HashMap<String, Spec>,
97}
98
99impl<'s> Parser<'s> {
100    fn new(tokens: Vec<String>, src: &'s str) -> Parser<'s> {
101        Parser {
102            tokens,
103            src,
104            i: 0,
105            refs: std::collections::HashMap::new(),
106        }
107    }
108}
109
110fn type_token(name: &str) -> Option<Token> {
111    Some(match name {
112        "Any" => Token::Any,
113        "String" => Token::String,
114        "Number" => Token::Number,
115        "Boolean" => Token::Boolean,
116        "Object" => Token::Object,
117        "Array" => Token::Array,
118        "Function" => Token::Function,
119        "Integer" => Token::Integer,
120        "Date" => Token::Date,
121        "BigInt" => Token::BigInt,
122        _ => return None,
123    })
124}
125
126const BUILDERS: [&str; 45] = [
127    "Required",
128    "Optional",
129    "Open",
130    "Closed",
131    "Skip",
132    "Ignore",
133    "Empty",
134    "Never",
135    "Func",
136    "Nullable",
137    "Coerce",
138    "Email",
139    "Url",
140    "Uuid",
141    "DateTime",
142    "Ip",
143    "Ipv4",
144    "Ipv6",
145    "Default",
146    "Catch",
147    "Describe",
148    "Pick",
149    "Omit",
150    "Partial",
151    "Extend",
152    "Fault",
153    "Type",
154    "Exact",
155    "Min",
156    "Max",
157    "Above",
158    "Below",
159    "Len",
160    "Check",
161    "One",
162    "Some",
163    "All",
164    "Child",
165    "Rest",
166    "Define",
167    "Refer",
168    "Rename",
169    "Key",
170    "Transform",
171    "Discriminated",
172];
173
174fn is_builder(name: &str) -> bool {
175    BUILDERS.contains(&name)
176}
177
178/// A type token with arguments applies the type to them: `String(Min(2))`
179/// is `Type(String, Min(2))`. Bare, it is `Type(tok)` as well, so that a
180/// bare `Object` is closed, as `Type(Object)` is.
181fn type_node(tok: Token, args: Vec<Spec>) -> Node {
182    let spec = args.into_iter().next().unwrap_or_else(|| Spec::from(any()));
183    type_(tok, spec)
184}
185
186/// A `/re/` token: held to the shared subset here, so that a pattern
187/// outside it is a parse error, as in TypeScript. A flag letter after the
188/// closing slash is refused the same way. The body is carried as text; the
189/// node compiles the engine form.
190fn regexp_token(head: &str) -> Option<Result<String, ExprError>> {
191    let bytes = head.as_bytes();
192    if head.len() >= 3
193        && head.starts_with('/')
194        && bytes[head.len() - 1].is_ascii_lowercase()
195        && bytes[head.len() - 2] == b'/'
196    {
197        let body = &head[1..head.len() - 2];
198        return Some(Err(ExprError(crate::regexp::regexp_fault(
199            body,
200            "flags are not supported",
201        ))));
202    }
203    if head.len() >= 2 && head.starts_with('/') && head.ends_with('/') {
204        let body = &head[1..head.len() - 1];
205        Some(
206            crate::regexp::canonical_regexp(body)
207                .map(|_| body.to_string())
208                .map_err(ExprError),
209        )
210    } else {
211        None
212    }
213}
214
215fn json_literal(head: &str) -> Option<Value> {
216    serde_json::from_str::<serde_json::Value>(head)
217        .ok()
218        .map(Value::from)
219}
220
221impl<'s> Parser<'s> {
222    fn peek(&self) -> &str {
223        self.tokens.get(self.i).map(|s| s.as_str()).unwrap_or("")
224    }
225
226    fn take(&mut self) -> String {
227        let t = self.peek().to_string();
228        if !t.is_empty() {
229            self.i += 1;
230        }
231        t
232    }
233
234    fn unexpected<T>(&self, head: &str) -> Result<T, ExprError> {
235        err(format!(
236            "Shape: unexpected token {} in builder expression {}",
237            head, self.src
238        ))
239    }
240
241    fn parse_full(&mut self) -> Result<Node, ExprError> {
242        let mut val = self.parse_term()?;
243        // A chain: `. Builder(args)`, and continued tokens are sub-builders
244        // even without the dot.
245        while !self.peek().is_empty() {
246            if self.peek() == "." {
247                self.take();
248            }
249            val = self.parse_chained(Spec::from(val))?;
250        }
251        Ok(val)
252    }
253
254    /// The primary of an expression: a builder call, a type token, a
255    /// literal, a regexp. A literal here is a default value. There is
256    /// always a token: an empty source does not tokenize.
257    fn parse_term(&mut self) -> Result<Node, ExprError> {
258        let head = self.take();
259        if head == ")" || head == "(" || head == "." {
260            return self.unexpected(&head);
261        }
262        if is_builder(&head) {
263            let args = self.parse_args()?;
264            return call_builder(&head, args);
265        }
266        if let Some(tok) = type_token(&head) {
267            let args = self.parse_args()?;
268            return Ok(type_node(tok, args));
269        }
270        if head == "NaN" {
271            self.parse_args()?;
272            return Ok(nan_node());
273        }
274        if head == "undefined" || head == "null" {
275            self.parse_args()?;
276            return Ok(literal_node(Value::Null));
277        }
278        if let Some(re) = regexp_token(&head) {
279            // A bare /re/ is a type, not a check: a non-string fails as a
280            // type error. Check(/re/) is the explicit-check form.
281            return Ok(regexp_node_src(&re?));
282        }
283        if let Some(lit) = json_literal(&head) {
284            return Ok(default_of(lit));
285        }
286        self.unexpected(&head)
287    }
288
289    fn parse_chained(&mut self, carrier: Spec) -> Result<Node, ExprError> {
290        let head = self.take();
291        if head.is_empty() {
292            return Ok(normalize(carrier));
293        }
294        if let Some(r) = self.refs.get(&head) {
295            return Ok(normalize(r.clone()));
296        }
297        // Chained onto a node, Exact applies its values to it, since every
298        // argument of the call is a value. A carrier that is a value is the
299        // example of a key expression, which is an argument as any other.
300        if head == "Exact" {
301            if let Spec::Node(n) = carrier {
302                let args = self.parse_args()?;
303                return Ok(n.exact(exact_vals(args)?));
304            }
305        }
306        if is_builder(&head) {
307            let mut args = self.parse_args()?;
308            // The carrier is the final argument.
309            args.push(carrier);
310            return call_builder(&head, args);
311        }
312        // A type token in chain position sets the type on the carrier:
313        // `.Array` is `Type(Array)` applied to the current node.
314        if let Some(tok) = type_token(&head) {
315            self.parse_args()?;
316            return Ok(type_(tok, carrier));
317        }
318        self.unexpected(&head)
319    }
320
321    /// `( arg, arg, ... )` when the next token opens it.
322    fn parse_args(&mut self) -> Result<Vec<Spec>, ExprError> {
323        if self.peek() != "(" {
324            return Ok(Vec::new());
325        }
326        self.take();
327        let mut args = Vec::new();
328        loop {
329            if self.peek() == ")" {
330                self.take();
331                return Ok(args);
332            }
333            if self.peek().is_empty() {
334                return err(format!(
335                    "Shape: unclosed argument list in expression {:?}",
336                    self.src
337                ));
338            }
339            args.push(self.parse_arg()?);
340        }
341    }
342
343    /// One argument: a builder, a type token, a literal, a regexp; a builder
344    /// or token may continue as a chain. The list is known to be open and
345    /// not yet closed, so there is a token.
346    fn parse_arg(&mut self) -> Result<Spec, ExprError> {
347        let head = self.take();
348        if let Some(r) = self.refs.get(&head) {
349            return Ok(r.clone());
350        }
351        if is_builder(&head) {
352            let args = self.parse_args()?;
353            let node = call_builder(&head, args)?;
354            return self.chain_continuation(node);
355        }
356        if let Some(tok) = type_token(&head) {
357            let args = self.parse_args()?;
358            return self.chain_continuation(type_node(tok, args));
359        }
360        if head == "NaN" {
361            // NaN in an argument is the value, so Exact(NaN) reads it as one.
362            return Ok(Spec::Value(Value::Num(f64::NAN)));
363        }
364        if head == "undefined" || head == "null" {
365            return Ok(Spec::Value(Value::Null));
366        }
367        if let Some(re) = regexp_token(&head) {
368            return Ok(Spec::Regexp(re?));
369        }
370        if let Some(lit) = json_literal(&head) {
371            return Ok(Spec::Value(lit));
372        }
373        self.unexpected(&head)
374    }
375
376    fn chain_continuation(&mut self, mut node: Node) -> Result<Spec, ExprError> {
377        while self.peek() == "." {
378            self.take();
379            node = self.parse_chained(Spec::from(node))?;
380        }
381        Ok(Spec::from(node))
382    }
383}
384
385/// The argument in a shape position, or the bare form's start.
386fn shape_at(args: &mut Vec<Spec>, i: usize, bare: Spec) -> Spec {
387    if i < args.len() {
388        args.remove(i)
389    } else {
390        bare
391    }
392}
393
394fn value_at(args: &[Spec], i: usize) -> Option<Value> {
395    match args.get(i) {
396        Some(Spec::Value(v)) => Some(v.clone()),
397        _ => None,
398    }
399}
400
401fn string_at(name: &str, what: &str, args: &[Spec], i: usize) -> Result<String, ExprError> {
402    match args.get(i) {
403        None => err(format!("{}: missing {}", name, what)),
404        Some(Spec::Value(Value::Str(s))) => Ok(s.clone()),
405        Some(_) => err(format!("{}: {} must be a string", name, what)),
406    }
407}
408
409/// A builder by name with its parsed arguments.
410/// A builder call. A builder given a wrong argument makes a fault node that
411/// reports at validation; in the string form that is an error here, as the
412/// builder throws in TypeScript.
413fn call_builder(name: &str, args: Vec<Spec>) -> Result<Node, ExprError> {
414    let node = build_call(name, args)?;
415    if crate::builders::is_fault(&node) {
416        return err(node.fault_msg.clone().unwrap_or_default());
417    }
418    Ok(node)
419}
420
421/// The values of an Exact call: every argument is one.
422fn exact_vals(args: Vec<Spec>) -> Result<Vec<Value>, ExprError> {
423    let mut vals = Vec::with_capacity(args.len());
424    for a in args {
425        match a {
426            Spec::Value(v) => vals.push(v),
427            _ => return err("Exact: values expected".to_string()),
428        }
429    }
430    Ok(vals)
431}
432
433fn build_call(name: &str, mut args: Vec<Spec>) -> Result<Node, ExprError> {
434    let any_spec = || Spec::from(any());
435    let unary =
436        |args: &mut Vec<Spec>, f: fn(Spec) -> Node| Ok(f(shape_at(args, 0, Spec::from(any()))));
437    match name {
438        "Required" => unary(&mut args, required),
439        "Optional" => unary(&mut args, optional),
440        "Open" => Ok(open(shape_at(&mut args, 0, Spec::Obj(Vec::new())))),
441        "Closed" => unary(&mut args, closed),
442        "Skip" => unary(&mut args, skip),
443        "Ignore" => unary(&mut args, ignore),
444        "Empty" => unary(&mut args, empty),
445        "Never" => unary(&mut args, never),
446        "Func" => unary(&mut args, func),
447        "Nullable" => unary(&mut args, nullable),
448        "Coerce" => unary(&mut args, coerce),
449        "Email" => unary(&mut args, email),
450        "Url" => unary(&mut args, url),
451        "Uuid" => unary(&mut args, uuid),
452        "DateTime" => unary(&mut args, date_time),
453        "Ip" => unary(&mut args, ip),
454        "Ipv4" => unary(&mut args, ipv4),
455        "Ipv6" => unary(&mut args, ipv6),
456        "Default" => {
457            if args.is_empty() {
458                return err("Default: missing default value".to_string());
459            }
460            let Some(dval) = value_at(&args, 0) else {
461                return err("Default: default value must be a value".to_string());
462            };
463            if args.len() == 1 {
464                return Ok(default_of(dval));
465            }
466            Ok(default(dval, shape_at(&mut args, 1, any_spec())))
467        }
468        "Catch" => {
469            if args.is_empty() {
470                return err("Catch: missing fallback value".to_string());
471            }
472            let Some(fb) = value_at(&args, 0) else {
473                return err("Catch: fallback value must be a value".to_string());
474            };
475            Ok(catch(fb, shape_at(&mut args, 1, any_spec())))
476        }
477        "Describe" => {
478            let msg = string_at("Describe", "description", &args, 0)?;
479            Ok(describe(msg, shape_at(&mut args, 1, any_spec())))
480        }
481        "Fault" => {
482            let msg = string_at("Fault", "message", &args, 0)?;
483            Ok(fault(msg, shape_at(&mut args, 1, any_spec())))
484        }
485        "Type" => {
486            if args.is_empty() {
487                return err("Type: missing kind".to_string());
488            }
489            let kind = args.remove(0);
490            let spec = shape_at(&mut args, 0, any_spec());
491            Ok(match kind {
492                Spec::Node(n) => type_(*n, spec),
493                Spec::Token(t) => type_(t, spec),
494                Spec::Value(Value::Str(name)) => type_(name.as_str(), spec),
495                // Not a kind at all: the node stands as it is.
496                _ => normalize(spec),
497            })
498        }
499        "Exact" => Ok(exact(exact_vals(args)?)),
500        "Discriminated" => {
501            if args.len() < 2 {
502                return err("Discriminated: missing tag or branches".to_string());
503            }
504            let tag = string_at("Discriminated", "tag", &args, 0)?;
505            let Spec::Obj(branches) = args.remove(1) else {
506                return err("Discriminated: branches must be an object".to_string());
507            };
508            Ok(crate::discriminated::discriminated(tag, branches))
509        }
510        "Min" | "Max" | "Above" | "Below" => {
511            if args.is_empty() {
512                return err(format!("{}: missing limit", name));
513            }
514            // A bound that is not a value is a wrong argument, and the
515            // builder says so.
516            let bound = value_at(&args, 0).unwrap_or(Value::Undefined);
517            let spec = shape_at(&mut args, 1, any_spec());
518            Ok(match name {
519                "Min" => min(bound, spec),
520                "Max" => max(bound, spec),
521                "Above" => above(bound, spec),
522                _ => below(bound, spec),
523            })
524        }
525        "Len" => {
526            if args.is_empty() {
527                return err("Len: missing length".to_string());
528            }
529            let Some(Value::Num(f)) = value_at(&args, 0) else {
530                return err("Len: length must be integer".to_string());
531            };
532            if f != f.trunc() {
533                return err("Shape: Len needs a whole number of zero or more".to_string());
534            }
535            Ok(len(f, shape_at(&mut args, 1, any_spec())))
536        }
537        "Check" => {
538            if args.is_empty() {
539                return err("Check: missing checker".to_string());
540            }
541            let checker = args.remove(0);
542            let spec = shape_at(&mut args, 0, any_spec());
543            Ok(match checker {
544                Spec::Regexp(src) => check_re_src(&src, spec),
545                // Not a check the string form can express: the shape alone.
546                _ => normalize(spec),
547            })
548        }
549        "One" => Ok(one(args)),
550        "Some" => Ok(some(args)),
551        "All" => Ok(all(args)),
552        "Child" => {
553            if args.is_empty() {
554                return err("Child: missing child shape".to_string());
555            }
556            let c = args.remove(0);
557            // Bare, an open object with the empty default it stands for.
558            let spec = shape_at(
559                &mut args,
560                0,
561                Spec::from(default(
562                    Value::Obj(Default::default()),
563                    Spec::Obj(Vec::new()),
564                )),
565            );
566            Ok(child(c, spec))
567        }
568        "Rest" => {
569            if args.is_empty() {
570                return err("Rest: missing child shape".to_string());
571            }
572            let c = args.remove(0);
573            let spec = shape_at(&mut args, 0, Spec::Arr(Vec::new()));
574            Ok(rest(c, spec))
575        }
576        "Define" => {
577            let n = string_at("Define", "name", &args, 0)?;
578            Ok(define(n, shape_at(&mut args, 1, any_spec())))
579        }
580        "Refer" => {
581            let n = string_at("Refer", "name", &args, 0)?;
582            Ok(refer(n, shape_at(&mut args, 1, any_spec())))
583        }
584        "Rename" => {
585            let n = string_at("Rename", "name", &args, 0)?;
586            Ok(rename(n, shape_at(&mut args, 1, any_spec())))
587        }
588        "Key" => {
589            let vals: Vec<Value> = args
590                .into_iter()
591                .filter_map(|a| match a {
592                    Spec::Value(v) => Some(v),
593                    _ => None,
594                })
595                .collect();
596            Ok(key_args(&vals))
597        }
598        "Pick" | "Omit" => {
599            if args.is_empty() {
600                return err(format!("{}: missing property names", name));
601            }
602            let names = match value_at(&args, 0) {
603                Some(v) => {
604                    Names::from_value(&v, name).map_err(|e| ExprError(format!("Shape: {}", e)))?
605                }
606                None => return err(format!("Shape: {} needs a list of property names", name)),
607            };
608            let spec = shape_at(&mut args, 1, any_spec());
609            let built = if name == "Pick" {
610                pick_node(names, spec)
611            } else {
612                omit_node(names, spec)
613            };
614            built.map_err(|e| ExprError(format!("Shape: {}", e)))
615        }
616        "Partial" => partial_node(shape_at(&mut args, 0, any_spec()))
617            .map_err(|e| ExprError(format!("Shape: {}", e))),
618        "Extend" => {
619            if args.is_empty() {
620                return err("Extend: missing extension".to_string());
621            }
622            let extra = args.remove(0);
623            let spec = shape_at(&mut args, 0, any_spec());
624            extend_node(extra, spec).map_err(|e| ExprError(format!("Shape: {}", e)))
625        }
626        _ => err(format!(
627            "Shape: {} is not available in the string form",
628            name
629        )),
630    }
631}
632
633/// The structural comparison of the parts of a node a key expression's
634/// example could have influenced: the kind, the required and skippable
635/// flags, how many checks it carries, its default, and its child shapes. A
636/// builder's own arguments are not compared, so `Exact()` with an example
637/// reads as `Exact(example)`, just as `Exact()` does.
638fn same_shape_node(x: &Node, y: &Node) -> bool {
639    x.kind == y.kind
640        && x.required == y.required
641        && x.skippable == y.skippable
642        && x.befores.len() == y.befores.len()
643        && x.afters.len() == y.afters.len()
644        && x.has_default == y.has_default
645        && x.default == y.default
646        && x.obj_children.len() == y.obj_children.len()
647        && x.arr_children.len() == y.arr_children.len()
648        && x.obj_rest.is_some() == y.obj_rest.is_some()
649        && x.arr_child.is_some() == y.arr_child.is_some()
650        && x.arr_rest.is_some() == y.arr_rest.is_some()
651}
652
653/// The node of a key expression: the expression applied to the example
654/// value. The example is appended as the innermost builder call's final
655/// argument, so a builder that takes a shape consumes it: `Child(Number)`
656/// with `[]` becomes an array of numbers, `Min(2)` with `0` a bounded
657/// number. A builder whose arity is already satisfied drops it, and the
658/// example is the author's stated default, so where it made no difference
659/// to the node it is applied as the value instead. A bad expression is a
660/// node that accepts nothing and says why.
661pub(crate) fn key_expr_node(src: &str, example: Spec) -> Node {
662    let bare = expr(src);
663    let or_fault = |r: Result<Node, ExprError>| r.unwrap_or_else(|e| fault_node(e.0));
664    if matches!(example, Spec::Value(Value::Null)) {
665        return or_fault(bare);
666    }
667    let ex = normalize(example.clone());
668
669    // A chain that names its kind (String, Integer.Min(2), Optional(Number),
670    // Any) keeps it: the example is the value and the default, nothing more.
671    // Without this the example's own kind won (`"a: Integer.Min(2)"` with 0
672    // read as a number) and so did what its value implied (`"a: String"`
673    // with "" allowed the empty string).
674    if let Ok(bare) = &bare {
675        if bare.kind_set {
676            let mut b = bare.clone();
677            b.has_default = ex.has_default;
678            b.default = ex.default;
679            b.literal = ex.literal;
680            if b.kind == Kind::Object && ex.kind == Kind::Object {
681                b.obj_children = ex.obj_children;
682                if b.obj_rest.is_none() {
683                    b.obj_rest = ex.obj_rest;
684                }
685            } else if b.kind == Kind::Array && ex.kind == Kind::Array {
686                b.arr_children = ex.arr_children;
687                if b.arr_child.is_none() && b.arr_rest.is_none() {
688                    b.arr_child = ex.arr_child;
689                }
690            }
691            return b;
692        }
693    }
694
695    let Ok(mut node) = expr_apply(src, example.clone()) else {
696        // Not a builder chain at all, a bare literal such as `a: 5`, so
697        // there is nothing to hand the example to and the expression's own
698        // value stands.
699        return or_fault(bare);
700    };
701    let takes_example = match &bare {
702        // The expression cannot be built without the example. Where the
703        // example became the shape it plainly made a difference; where a
704        // value-taking builder read it as its argument, the bare build
705        // looks the same, so the example is the default too.
706        Err(_) => ex.kind != node.kind,
707        Ok(bare) => same_shape_node(&node, bare),
708    };
709    if takes_example {
710        if let Spec::Value(v) = example {
711            node.has_default = true;
712            node.default = v.clone();
713            node.literal = Some(v);
714        }
715    }
716    node
717}
718
719/// The rule of a key expression: a name (quoted, or without spaces), a
720/// colon, and the expression. An empty expression is a literal key.
721pub(crate) fn split_key_expr(key: &str) -> Option<(String, String)> {
722    static RE: OnceLock<Regex> = OnceLock::new();
723    let re =
724        RE.get_or_init(|| Regex::new(r#"^\s*("(?:\\.|[^"\\])*"|[^\s]+):\s*(.*?)\s*$"#).unwrap());
725    let m = re.captures(key)?;
726    let src = m.get(2).unwrap().as_str();
727    if src.is_empty() {
728        return None;
729    }
730    let mut name = m.get(1).unwrap().as_str().to_string();
731    if name.len() >= 2 && name.starts_with('"') && name.ends_with('"') {
732        // A quoted name decodes its escapes: "a\"b" declares a"b.
733        name = serde_json::from_str::<String>(&name)
734            .unwrap_or_else(|_| name[1..name.len() - 1].to_string());
735    }
736    Some((name, src.to_string()))
737}
738
739// The reader of declarative JSON
740// ==============================
741
742/// The builders that read every argument for themselves, so a mark of one
743/// is the whole node rather than a chain around the object holding it.
744const COMPOSITION: [&str; 5] = ["One", "Some", "All", "Exact", "Discriminated"];
745
746/// Read the declarative JSON of a shape, what `Schema::json` writes: every
747/// string is an expression (the example of a key expression is a value, so
748/// a string there is the string itself), and a `"$$"` key applies an
749/// expression to the object that holds it, with the `"$$0"`, `"$$1"`, ...
750/// sidecars beside it as the arguments an expression cannot spell inline.
751pub fn build(v: &Value) -> Result<Spec, ExprError> {
752    build_value(v, false)
753}
754
755/// One value; `example` is true for the value of a key expression, which a
756/// string is the literal of.
757fn build_value(v: &Value, example: bool) -> Result<Spec, ExprError> {
758    match v {
759        // The empty string is the empty example, as a required string's
760        // example is (`"a: String"` with "").
761        Value::Str(s) if example || s.is_empty() => Ok(Spec::Value(Value::Str(s.clone()))),
762        Value::Str(s) => expr(s).map(Spec::from),
763        Value::Obj(m) => {
764            let mut pairs: Vec<(String, Spec)> = Vec::with_capacity(m.len());
765            let mut mark: Option<String> = None;
766            for (k, sv) in m {
767                if k == "$$" {
768                    if let Value::Str(src) = sv {
769                        mark = Some(src.clone());
770                        continue;
771                    }
772                }
773                let is_key_expr = matches!(sv, Value::Str(_)) && split_key_expr(k).is_some();
774                pairs.push((k.clone(), build_value(sv, is_key_expr)?));
775            }
776            match mark {
777                Some(src) => build_mark(&src, pairs),
778                None => Ok(Spec::Obj(pairs)),
779            }
780        }
781        Value::Arr(a) => {
782            let mut out = Vec::with_capacity(a.len());
783            for sv in a {
784                out.push(build_value(sv, false)?);
785            }
786            Ok(Spec::Arr(out))
787        }
788        other => Ok(Spec::Value(other.clone())),
789    }
790}
791
792/// The expression under the mark applies to the object that holds it. The
793/// sidecars are its arguments; the object's own keys are the shape a chained
794/// builder takes, but a composition has no slot for a carrier and is read on
795/// its own, the node it becomes being the whole shape.
796fn build_mark(src: &str, pairs: Vec<(String, Spec)>) -> Result<Spec, ExprError> {
797    let mut refs = std::collections::HashMap::new();
798    let mut rest = Vec::with_capacity(pairs.len());
799    for (k, v) in pairs {
800        if k.starts_with("$$") {
801            refs.insert(k, v);
802        } else {
803            rest.push((k, v));
804        }
805    }
806    let tokens = tokenize(src)?;
807    let mut p = Parser::new(tokens, src);
808    p.refs = refs;
809    if COMPOSITION.contains(&p.peek()) {
810        return p.parse_full().map(Spec::from);
811    }
812    let mut val = Spec::Obj(rest);
813    while !p.peek().is_empty() {
814        if p.peek() == "." {
815            p.take();
816        }
817        val = Spec::from(p.parse_chained(val)?);
818    }
819    Ok(val)
820}
821
822#[cfg(test)]
823mod tests {
824    use super::*;
825    use crate::spec::{arr, obj};
826    use crate::stringify::stringify_node;
827    use crate::Schema;
828
829    fn render(src: &str) -> String {
830        stringify_node(
831            &expr(src).unwrap_or_else(|e| panic!("{}: {}", src, e)),
832            false,
833        )
834    }
835
836    fn fails(src: &str) -> String {
837        expr(src).unwrap_err().0
838    }
839
840    #[test]
841    fn a_wrong_builder_argument_is_a_parse_error() {
842        assert_eq!(fails("String.Min(\"x\")"), "Shape: Min needs a number");
843        assert_eq!(
844            fails("Len(-1)"),
845            "Shape: Len needs a whole number of zero or more"
846        );
847        assert_eq!(fails("Open(Define(\"\"))"), "Shape: Define needs a name");
848        assert_eq!(fails("Min(Number)"), "Shape: Min needs a number");
849        // A deliberate fault is not a wrong argument.
850        assert!(expr("Never.Fault(\"f\")").is_ok());
851        assert!(expr("Fault(\"f\", Never)").is_ok());
852    }
853
854    #[test]
855    fn parses_terms_chains_and_arguments() {
856        let cases = [
857            ("String.Min(2).Max(10)", "String.Min(2).Max(10)"),
858            ("Min(2, Number)", "Number.Min(2)"),
859            ("Number Min(2)", "Number.Min(2)"),
860            ("Min(2).Number", "Number.Min(2)"),
861            ("String.Array(1)", "[]"),
862            ("5", "5"),
863            ("\"x\"", "\"x\""),
864            ("null", "null"),
865            ("undefined", "null"),
866            ("null(1)", "null"),
867            ("NaN", "NaN"),
868            ("NaN(1)", "NaN"),
869            ("/^a/", "/^a/"),
870            ("Check(/^a/)", "Check.Check(/^a/)"),
871            ("Check(/^a/, String)", "String.Check(/^a/)"),
872            ("Check(1)", "Any"),
873            ("One(String, 1, NaN, /x/)", "One(String,1,NaN,/x/)"),
874            ("Some(Number)", "Some(Number)"),
875            ("All(Number)", "All(Number)"),
876            ("Optional(Number)", "0"),
877            ("Required()", "Any"),
878            ("Required(null)", "null"),
879            ("Open", "{}.Open()"),
880            ("Open(Number)", "Number"),
881            ("Closed", "Any"),
882            ("Child(Number)", "{}.Child(Number)"),
883            ("Rest(Number)", "[...Number]"),
884            // The rest replaces a plain element shape, as it does in TypeScript.
885            ("Rest(Number, [1])", "[...Number]"),
886            ("Type(Number)", "Number"),
887            ("Type(\"String\")", "String"),
888            ("Type(Min(2))", "Any"),
889            ("Type(1)", "Any"),
890            ("Exact(1, \"a\", null)", "Exact(1, a, null)"),
891            ("Len(2)", "Len(2)"),
892            ("Key(1, \"/\")", "String.Key()"),
893            ("Key(Number)", "String.Key()"),
894            ("Default(7)", "7"),
895            ("Default(7, Number)", "7"),
896            ("Default(null, Number)", "null"),
897            ("Catch(0, Number)", "Number.Catch(0)"),
898            ("Describe(\"d\", Number)", "Number"),
899            ("Fault(\"f\")", "Any"),
900            ("Email", "String.Email"),
901            ("Url", "String.Url"),
902            ("Uuid", "String.Uuid"),
903            ("DateTime", "String.DateTime"),
904            ("Ip", "String.Ip"),
905            ("Ipv4", "String.Ipv4"),
906            ("Ipv6", "String.Ipv6"),
907            ("Coerce(Number)", "Number"),
908            ("Nullable(Number)", "Number"),
909            ("Never", "Never"),
910            ("Func", "Function"),
911            ("Empty", "Any"),
912            ("Ignore(Number)", "0"),
913            ("Skip(Number)", "0"),
914            ("Define(\"d\")", "Define(\"d\")"),
915            ("Refer(\"d\")", "Refer(\"d\")"),
916            ("Rename(\"b\")", "Any"),
917            ("Min(\"2\")", "Min(2)"),
918            ("Above(1).Below(3)", "Above(1).Below(3)"),
919            ("Max(3, Integer)", "Integer.Max(3)"),
920            ("Object", "{}"),
921            ("Array", "[]"),
922            ("Any", "Any"),
923            ("Date", "Date"),
924            ("BigInt", "BigInt"),
925            ("Boolean", "Boolean"),
926            ("Function", "Function"),
927            ("String(Min(2))", "String.Min(2)"),
928            ("Min(2).", "Min(2)"),
929            ("One(Number.Min(2), String)", "One(Number.Min(2),String)"),
930            ("Optional(Min(2).Number)", "0.Min(2)"),
931            ("Optional(Number)", "0"),
932            ("Min(2, /^a/)", "/^a/.Min(2)"),
933        ];
934        for (src, want) in cases {
935            assert_eq!(render(src), want, "{}", src);
936        }
937        // A fractional length is refused, as it is in every language.
938        assert_eq!(
939            call_builder("Len", vec![Spec::Value(Value::Num(2.7))]).unwrap_err(),
940            ExprError("Shape: Len needs a whole number of zero or more".to_string())
941        );
942        // Type from a token, as a builder call sees it.
943        assert_eq!(
944            stringify_node(
945                &call_builder("Type", vec![Spec::Token(Token::Number)]).unwrap(),
946                false
947            ),
948            "Number"
949        );
950        let s = Schema::parse("Min(2).Array").unwrap();
951        assert!(s.valid(&Value::Arr(vec![Value::from(1), Value::from(2)])));
952        assert!(!s.valid(&Value::Arr(vec![Value::from(1)])));
953        assert!(Schema::parse("bogus").is_err());
954        assert_eq!(
955            stringify_node(&expr_apply(".Min(2)", Spec::from(1)).unwrap(), false),
956            "1.Min(2)"
957        );
958        assert_eq!(
959            stringify_node(
960                &expr_apply("Open", obj([("a", Spec::from(1))])).unwrap(),
961                false
962            ),
963            "{a: 1}.Open()"
964        );
965        assert!(expr_apply("bogus", Spec::from(1)).is_err());
966        assert_eq!(format!("{}", ExprError("x".into())), "x");
967    }
968
969    #[test]
970    fn rejects_what_it_cannot_read() {
971        let cases = [
972            ("", "Shape: empty expression"),
973            ("  ", "Shape: empty expression"),
974            (
975                ",,a",
976                "Shape: unexpected character at offset 0 in expression \",,a\"",
977            ),
978            (",", "Shape: unexpected trailing text in expression \",\""),
979            ("(", "Shape: unexpected token ( in builder expression ("),
980            (")", "Shape: unexpected token ) in builder expression )"),
981            (".", "Shape: unexpected token . in builder expression ."),
982            (
983                "bogus",
984                "Shape: unexpected token bogus in builder expression bogus",
985            ),
986            (
987                "Min(2).bogus",
988                "Shape: unexpected token bogus in builder expression Min(2).bogus",
989            ),
990            (
991                "Min(2) )",
992                "Shape: unexpected token ) in builder expression Min(2) )",
993            ),
994            (
995                "Min(()",
996                "Shape: unexpected token ( in builder expression Min(()",
997            ),
998            (
999                "Min(2",
1000                "Shape: unclosed argument list in expression \"Min(2\"",
1001            ),
1002            (
1003                "Min(",
1004                "Shape: unclosed argument list in expression \"Min(\"",
1005            ),
1006            ("/a/i", "Shape: invalid regexp /a/: flags are not supported"),
1007            ("Min()", "Min: missing limit"),
1008            ("Max()", "Max: missing limit"),
1009            ("Above()", "Above: missing limit"),
1010            ("Below()", "Below: missing limit"),
1011            ("Len()", "Len: missing length"),
1012            ("Len(\"x\")", "Len: length must be integer"),
1013            ("Default()", "Default: missing default value"),
1014            ("Default(Number)", "Default: default value must be a value"),
1015            ("Catch()", "Catch: missing fallback value"),
1016            ("Catch(Number)", "Catch: fallback value must be a value"),
1017            ("Describe()", "Describe: missing description"),
1018            ("Describe(1)", "Describe: description must be a string"),
1019            ("Fault()", "Fault: missing message"),
1020            ("Fault(1)", "Fault: message must be a string"),
1021            ("Type()", "Type: missing kind"),
1022            ("Exact(Number)", "Exact: values expected"),
1023            ("Check()", "Check: missing checker"),
1024            ("Child()", "Child: missing child shape"),
1025            ("Rest()", "Rest: missing child shape"),
1026            ("Define()", "Define: missing name"),
1027            ("Define(1)", "Define: name must be a string"),
1028            ("Refer()", "Refer: missing name"),
1029            ("Rename()", "Rename: missing name"),
1030            ("Pick([\"a\"])", "Shape: Pick needs an object shape"),
1031            ("Pick()", "Pick: missing property names"),
1032            ("Omit(1)", "Shape: Omit needs a list of property names"),
1033            ("Omit(Number)", "Shape: Omit needs a list of property names"),
1034            ("Partial", "Shape: Partial needs an object shape"),
1035            ("Extend()", "Extend: missing extension"),
1036            (
1037                "Extend(Number, Number)",
1038                "Shape: Extend needs an object shape",
1039            ),
1040            (
1041                "Transform",
1042                "Shape: Transform is not available in the string form",
1043            ),
1044        ];
1045        for (src, want) in cases {
1046            assert_eq!(fails(src), want, "{}", src);
1047        }
1048        assert_eq!(
1049            fails("/[/"),
1050            "Shape: invalid regexp /[/: unterminated character class"
1051        );
1052        assert_eq!(
1053            fails("Min(2, /[/)"),
1054            "Shape: invalid regexp /[/: unterminated character class"
1055        );
1056    }
1057
1058    #[test]
1059    fn key_expressions_take_the_example() {
1060        let s = |src: &str, ex: Spec| stringify_node(&key_expr_node(src, ex), false);
1061        // A null example leaves the expression alone.
1062        assert_eq!(s("Min(2)", Spec::Value(Value::Null)), "Min(2)");
1063        // A bare literal has no builder to hand the example to.
1064        assert_eq!(s("5", Spec::from(3)), "5");
1065        // A value-taking builder reads the example as its argument, and it
1066        // is the default too.
1067        assert_eq!(s("Min()", Spec::from(3)), "Any(3).Min(3)");
1068        // An expression that cannot be built either way is a fault.
1069        assert_eq!(s("bogus()", Spec::from(3)), "Never");
1070        // The example became the shape: no default.
1071        assert_eq!(
1072            s("Child()", arr([Spec::from(Token::Number)])),
1073            "{}.Child([Number])"
1074        );
1075        // A shape-taking builder consumes it.
1076        assert_eq!(s("Child(Number)", arr::<Spec>([])), "[Number]");
1077        // Arity already satisfied: the example is the value.
1078        assert_eq!(s("Optional(Number)", Spec::from(5)), "5");
1079        assert_eq!(s("Any", Spec::from(5)), "Any(5)");
1080        assert_eq!(
1081            split_key_expr("\"a\\\"b\": Min(1)"),
1082            Some(("a\"b".into(), "Min(1)".into()))
1083        );
1084        assert_eq!(
1085            split_key_expr("\"a\\q\": Min(1)"),
1086            Some(("a\\q".into(), "Min(1)".into()))
1087        );
1088        assert_eq!(split_key_expr("a:"), None);
1089        assert_eq!(split_key_expr("a b: Min(1)"), None);
1090        assert_eq!(
1091            split_key_expr("a: Min(1) "),
1092            Some(("a".into(), "Min(1)".into()))
1093        );
1094    }
1095}