sim_lib_pattern/
glob_dialect.rs1use sim_kernel::{Error, Result};
4
5use crate::lua_dialect::parse_set_body;
6use crate::{PatternDialect, TextOp};
7
8#[derive(Clone, Copy, Debug, Default)]
10pub struct GlobPatternDialect;
11
12impl PatternDialect for GlobPatternDialect {
13 fn compile(&self, pattern: &str) -> Result<Vec<TextOp>> {
14 let chars = pattern.chars().collect::<Vec<_>>();
15 let mut index = 0;
16 let mut ops = vec![TextOp::AnchorStart];
17 while let Some(ch) = chars.get(index).copied() {
18 index += 1;
19 match ch {
20 '*' => {
21 ops.push(TextOp::Any);
22 ops.push(TextOp::Repeat {
23 min: 0,
24 max: None,
25 greedy: true,
26 });
27 }
28 '?' => ops.push(TextOp::Any),
29 '[' => {
30 let negated = matches!(chars.get(index), Some('!') | Some('^'));
31 if negated {
32 index += 1;
33 }
34 ops.push(TextOp::Class(parse_set_body(
35 &chars,
36 &mut index,
37 negated,
38 "unterminated glob character set",
39 )?));
40 }
41 '\\' => {
42 let literal = chars
43 .get(index)
44 .copied()
45 .ok_or_else(|| malformed("dangling escape"))?;
46 index += 1;
47 ops.push(TextOp::Literal(literal));
48 }
49 literal => ops.push(TextOp::Literal(literal)),
50 }
51 }
52 ops.push(TextOp::AnchorEnd);
53 Ok(ops)
54 }
55}
56
57pub fn compile_glob_pattern(pattern: &str) -> Result<Vec<TextOp>> {
63 GlobPatternDialect.compile(pattern)
64}
65
66fn malformed(message: &str) -> Error {
67 Error::Eval(format!("malformed glob pattern: {message}"))
68}