1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//! The expression head: a query may open with `= expr` — sugar
//! for `^ | (expr)`, one row from the root anchor (spec: The
//! Expression Head). Calculator detection (`is_calculator`) gates
//! the no-target invocation in qua/quai. Ruling #12 rides along:
//! shaped literals type themselves in arithmetic position.
use quarb::Defs;
use quarb::{expand, is_calculator};
fn canon(q: &str) -> String {
expand(q, &Defs::default()).unwrap()
}
fn refuse(q: &str) -> String {
expand(q, &Defs::default()).unwrap_err().to_string()
}
#[test]
fn head_desugars_to_root_anchor() {
// The head and its spelled-out form canonicalize identically.
assert_eq!(canon("= 2 + 2"), canon("^ | (2 + 2)"));
// Pipe from the head — commands compose.
canon("= 2 + 2 | %(answer = $_)");
// Parenthesized sub-expressions stay ordinary operands.
canon("= (2 + 2) * 3");
// An aggregate over the one-row stream.
canon("= 3 @| count");
}
#[test]
fn head_composes_with_fragments() {
// A command fragment applies to the head's row.
canon("def &twice: | ($_ * 2); = 21 | &twice");
// A query fragment may itself be expression-headed.
canon("def &four: = 2 + 2; &four");
}
#[test]
fn head_stands_alone() {
assert!(refuse("= 1 || /x").contains("expression head stands alone"));
}
#[test]
fn parens_keep_their_navigational_meanings() {
// Group alternation, quantified walks, mark anchors — all as
// before the head existed; a leading paren is never a head.
canon("(/a|/b)");
canon("(/a/(x.rs|y.txt)|/b/z.rs)");
// (mark anchors print in double parentheses)
assert_eq!(canon("/a.m | $$.m/address"), "/a.m | $$.m/address");
assert!(refuse("(|/a)").contains("at least one hop"));
}
#[test]
fn calculator_detection() {
// Expression heads and the lone root anchor qualify.
assert!(is_calculator("= 2 + 2"));
assert!(is_calculator("= 2 + 2 | %(x = $_)"));
assert!(is_calculator("^ | count"));
assert!(is_calculator("def &four: = 2 + 2; &four"));
// Anything that navigates does not.
assert!(!is_calculator("/a"));
assert!(!is_calculator("//x::y"));
assert!(!is_calculator("= 2 || /x"));
// A literal opens a head without the sigil (draft 166).
assert!(is_calculator("1 + 1"));
// Unparseable text answers false; the run path owns the error.
assert!(!is_calculator("+ 1"));
}