pub const CCT_UNUSED: i32 = 0; pub const CCT_POS: i32 = 1; pub const CCT_CURSTR: i32 = 2; pub const CCT_CURPAT: i32 = 3; pub const CCT_WORDSTR: i32 = 4; pub const CCT_WORDPAT: i32 = 5; pub const CCT_CURSUF: i32 = 6; pub const CCT_CURPRE: i32 = 7; pub const CCT_CURSUB: i32 = 8; pub const CCT_CURSUBC: i32 = 9; pub const CCT_NUMWORDS: i32 = 10; pub const CCT_RANGESTR: i32 = 11; pub const CCT_RANGEPAT: i32 = 12; pub const CCT_QUOTE: i32 = 13;
pub const CC_FILES: u64 = 1 << 0; pub const CC_COMMPATH: u64 = 1 << 1; pub const CC_REMOVE: u64 = 1 << 2; pub const CC_OPTIONS: u64 = 1 << 3; pub const CC_VARS: u64 = 1 << 4; pub const CC_BINDINGS: u64 = 1 << 5; pub const CC_ARRAYS: u64 = 1 << 6; pub const CC_INTVARS: u64 = 1 << 7; pub const CC_SHFUNCS: u64 = 1 << 8; pub const CC_PARAMS: u64 = 1 << 9; pub const CC_ENVVARS: u64 = 1 << 10; pub const CC_JOBS: u64 = 1 << 11; pub const CC_RUNNING: u64 = 1 << 12; pub const CC_STOPPED: u64 = 1 << 13; pub const CC_BUILTINS: u64 = 1 << 14; pub const CC_ALREG: u64 = 1 << 15; pub const CC_ALGLOB: u64 = 1 << 16; pub const CC_USERS: u64 = 1 << 17; pub const CC_DISCMDS: u64 = 1 << 18; pub const CC_EXCMDS: u64 = 1 << 19; pub const CC_SCALARS: u64 = 1 << 20; pub const CC_READONLYS: u64 = 1 << 21; pub const CC_SPECIALS: u64 = 1 << 22; pub const CC_DELETE: u64 = 1 << 23; pub const CC_NAMED: u64 = 1 << 24; pub const CC_QUOTEFLAG: u64 = 1 << 25; pub const CC_EXTCMDS: u64 = 1 << 26; pub const CC_RESWDS: u64 = 1 << 27; pub const CC_DIRS: u64 = 1 << 28; pub const CC_EXPANDEXPL: u64 = 1 << 30; pub const CC_RESERVED: u64 = 1 << 31;
pub const CC_NOSORT: u64 = 1 << 0; pub const CC_XORCONT: u64 = 1 << 1; pub const CC_CCCONT: u64 = 1 << 2; pub const CC_PATCONT: u64 = 1 << 3; pub const CC_DEFCONT: u64 = 1 << 4; pub const CC_UNIQCON: u64 = 1 << 5; pub const CC_UNIQALL: u64 = 1 << 6;
#[derive(Debug, Clone)]
#[allow(non_camel_case_types)]
pub struct Compctlp {
pub cc: std::sync::Arc<Compctl>, }
#[derive(Debug, Clone)]
#[allow(non_camel_case_types)]
pub struct Patcomp {
pub next: Option<Box<Patcomp>>, pub pat: String, pub cc: std::sync::Arc<Compctl>, }
#[derive(Debug, Clone, Default)]
#[allow(non_camel_case_types)]
pub struct Compcond {
pub and: Option<Box<Compcond>>, pub or: Option<Box<Compcond>>, pub typ: i32, pub n: i32, pub u: CompcondData, }
#[derive(Debug, Clone, Default)]
#[allow(non_camel_case_types)]
pub enum CompcondData {
R { a: Vec<i32>, b: Vec<i32> },
S { p: Vec<i32>, s: Vec<String> },
L { a: Vec<String>, b: Vec<String> },
#[default]
Unused,
}
#[derive(Debug, Clone, Default)]
#[allow(non_camel_case_types)]
pub struct Compctl {
pub refc: i32, pub next: Option<std::sync::Arc<Compctl>>, pub mask: u64, pub mask2: u64, pub keyvar: Option<String>, pub glob: Option<String>, pub str: Option<String>, pub func: Option<String>, pub explain: Option<String>, pub ylist: Option<String>, pub prefix: Option<String>, pub suffix: Option<String>, pub subcmd: Option<String>, pub substr: Option<String>, pub withd: Option<String>, pub hpat: Option<String>, pub hnum: i32, pub gname: Option<String>, pub ext: Option<std::sync::Arc<Compctl>>, pub cond: Option<Box<Compcond>>, pub xor: Option<std::sync::Arc<Compctl>>, pub matcher: Option<Box<crate::ported::zle::comp_h::Cmatcher>>, pub mstr: Option<String>, }
#[cfg(test)]
mod tests {
use super::*;
use crate::ported::zle::zle_main::zle_test_setup;
#[test]
fn cct_constants_correct() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
assert_eq!(CCT_UNUSED, 0);
assert_eq!(CCT_POS, 1);
assert_eq!(CCT_CURSTR, 2);
assert_eq!(CCT_QUOTE, 13);
}
#[test]
fn cc_primary_mask_bits_distinct() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let all = CC_FILES
| CC_COMMPATH
| CC_REMOVE
| CC_OPTIONS
| CC_VARS
| CC_BINDINGS
| CC_ARRAYS
| CC_INTVARS
| CC_SHFUNCS
| CC_PARAMS
| CC_ENVVARS
| CC_JOBS
| CC_RUNNING
| CC_STOPPED
| CC_BUILTINS
| CC_ALREG
| CC_ALGLOB
| CC_USERS
| CC_DISCMDS
| CC_EXCMDS
| CC_SCALARS
| CC_READONLYS
| CC_SPECIALS
| CC_DELETE
| CC_NAMED
| CC_QUOTEFLAG
| CC_EXTCMDS
| CC_RESWDS
| CC_DIRS
| CC_EXPANDEXPL
| CC_RESERVED;
assert_eq!(all.count_ones(), 31); }
#[test]
fn cc_secondary_mask_values() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
assert_eq!(CC_NOSORT, 1);
assert_eq!(CC_XORCONT, 2);
assert_eq!(CC_UNIQALL, 1 << 6);
}
#[test]
fn compctl_default_zeros_fields() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let cc = Compctl::default();
assert_eq!(cc.refc, 0);
assert!(cc.next.is_none());
assert_eq!(cc.mask, 0);
assert_eq!(cc.mask2, 0);
assert!(cc.keyvar.is_none());
assert!(cc.cond.is_none());
assert!(cc.xor.is_none());
assert_eq!(cc.hnum, 0);
}
#[test]
fn compcond_default_is_unused() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let c = Compcond::default();
assert_eq!(c.typ, CCT_UNUSED);
assert!(matches!(c.u, CompcondData::Unused));
}
#[test]
fn compcond_data_variants() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let r = CompcondData::R {
a: vec![0, 1],
b: vec![2, 3],
};
if let CompcondData::R { a, b } = r {
assert_eq!(a, vec![0, 1]);
assert_eq!(b, vec![2, 3]);
} else {
panic!("expected R variant");
}
let s = CompcondData::S {
p: vec![1],
s: vec!["x".into()],
};
assert!(matches!(s, CompcondData::S { .. }));
let l = CompcondData::L {
a: vec!["lo".into()],
b: vec!["hi".into()],
};
assert!(matches!(l, CompcondData::L { .. }));
}
#[test]
fn cct_constants_are_unique() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let all = [
CCT_UNUSED,
CCT_POS,
CCT_CURSTR,
CCT_CURPAT,
CCT_WORDSTR,
CCT_WORDPAT,
CCT_CURSUF,
CCT_CURPRE,
CCT_CURSUB,
CCT_CURSUBC,
CCT_NUMWORDS,
CCT_RANGESTR,
CCT_RANGEPAT,
CCT_QUOTE,
];
let unique: std::collections::HashSet<_> = all.iter().copied().collect();
assert_eq!(unique.len(), all.len(), "duplicate CCT_* constant detected");
for &v in &all {
assert!(v >= 0, "CCT_* constants must be non-negative");
}
}
#[test]
fn cct_unused_is_zero() {
let _g = crate::test_util::global_state_lock();
assert_eq!(CCT_UNUSED, 0, "CCT_UNUSED must be the zero-init sentinel");
}
#[test]
fn cc_primary_mask_bits_are_distinct_singletons() {
let _g = crate::test_util::global_state_lock();
let primary = [
CC_FILES,
CC_COMMPATH,
CC_REMOVE,
CC_OPTIONS,
CC_VARS,
CC_BINDINGS,
CC_ARRAYS,
CC_INTVARS,
CC_SHFUNCS,
CC_PARAMS,
CC_ENVVARS,
];
for &m in &primary {
assert_eq!(
m.count_ones(),
1,
"primary CC_ mask {} has {} bits set",
m,
m.count_ones()
);
}
let mut all: u64 = 0;
for &m in &primary {
assert_eq!(all & m, 0, "primary CC_ mask {} overlaps", m);
all |= m;
}
}
#[test]
fn compctl_default_partial_population_doesnt_clobber_other_fields() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let mut cc = Compctl::default();
cc.mask = CC_FILES;
assert_eq!(cc.mask, CC_FILES);
assert_eq!(cc.refc, 0);
assert!(cc.next.is_none());
assert_eq!(cc.mask2, 0);
assert!(cc.keyvar.is_none());
assert!(cc.cond.is_none());
assert_eq!(cc.hnum, 0);
}
#[test]
fn compcond_default_typ_and_data_are_consistent() {
let _g = crate::test_util::global_state_lock();
let _g = zle_test_setup();
let c = Compcond::default();
assert_eq!(c.typ, CCT_UNUSED, "tag must be UNUSED");
assert!(
matches!(c.u, CompcondData::Unused),
"data must be CompcondData::Unused"
);
}
#[test]
fn cc_primary_mask_full_sweep_no_overlap() {
let _g = crate::test_util::global_state_lock();
let primary = [
CC_FILES,
CC_COMMPATH,
CC_REMOVE,
CC_OPTIONS,
CC_VARS,
CC_BINDINGS,
CC_ARRAYS,
CC_INTVARS,
CC_SHFUNCS,
CC_PARAMS,
CC_ENVVARS,
CC_STOPPED,
CC_BUILTINS,
CC_ALREG,
CC_ALGLOB,
CC_USERS,
CC_DISCMDS,
CC_EXCMDS,
CC_SCALARS,
CC_READONLYS,
CC_SPECIALS,
CC_DELETE,
CC_NAMED,
CC_QUOTEFLAG,
CC_EXTCMDS,
CC_RESWDS,
CC_DIRS,
CC_EXPANDEXPL,
CC_RESERVED,
];
for &m in &primary {
assert_eq!(
m.count_ones(),
1,
"primary CC_ mask {:#x} must be single bit",
m
);
}
let mut all: u64 = 0;
for &m in &primary {
assert_eq!(all & m, 0, "CC_ mask {:#x} overlaps with previous flags", m);
all |= m;
}
}
#[test]
fn cc_expandexpl_at_bit_30_skips_bit_29() {
let _g = crate::test_util::global_state_lock();
assert_eq!(
CC_EXPANDEXPL,
1 << 30,
"c:148 — CC_EXPANDEXPL must be at bit 30 (bit 29 is the gap)"
);
let all_primary = [
CC_FILES,
CC_COMMPATH,
CC_REMOVE,
CC_OPTIONS,
CC_VARS,
CC_BINDINGS,
CC_ARRAYS,
CC_INTVARS,
CC_SHFUNCS,
CC_PARAMS,
CC_ENVVARS,
CC_STOPPED,
CC_BUILTINS,
CC_ALREG,
CC_ALGLOB,
CC_USERS,
CC_DISCMDS,
CC_EXCMDS,
CC_SCALARS,
CC_READONLYS,
CC_SPECIALS,
CC_DELETE,
CC_NAMED,
CC_QUOTEFLAG,
CC_EXTCMDS,
CC_RESWDS,
CC_DIRS,
CC_EXPANDEXPL,
CC_RESERVED,
];
let bit_29: u64 = 1 << 29;
for &m in &all_primary {
assert_ne!(
m, bit_29,
"no primary mask should occupy bit 29 (the documented gap)"
);
}
}
#[test]
fn cc_reserved_is_bit_31() {
let _g = crate::test_util::global_state_lock();
assert_eq!(CC_RESERVED, 1u64 << 31);
}
#[test]
fn secondary_mask_collides_with_primary_by_design() {
let _g = crate::test_util::global_state_lock();
assert_eq!(
CC_NOSORT, CC_FILES,
"collision is intentional — different mask fields"
);
assert_eq!(CC_XORCONT, CC_COMMPATH);
let secondary = [
CC_NOSORT, CC_XORCONT, CC_CCCONT, CC_PATCONT, CC_DEFCONT, CC_UNIQCON, CC_UNIQALL,
];
let mut all: u64 = 0;
for &m in &secondary {
assert_eq!(
m.count_ones(),
1,
"secondary CC_ mask {:#x} must be single bit",
m
);
assert_eq!(
all & m,
0,
"secondary {:#x} overlaps within mask2 namespace",
m
);
all |= m;
}
}
#[test]
fn cct_values_are_sequential_zero_through_thirteen() {
let _g = crate::test_util::global_state_lock();
let in_order = [
CCT_UNUSED,
CCT_POS,
CCT_CURSTR,
CCT_CURPAT,
CCT_WORDSTR,
CCT_WORDPAT,
CCT_CURSUF,
CCT_CURPRE,
CCT_CURSUB,
CCT_CURSUBC,
CCT_NUMWORDS,
CCT_RANGESTR,
CCT_RANGEPAT,
CCT_QUOTE,
];
for (i, &v) in in_order.iter().enumerate() {
assert_eq!(
v, i as i32,
"CCT_ at position {} must be {}, got {}",
i, i, v
);
}
}
}