use syntax::Expr; use {Error, Result}; /// Returns a new expression that is guaranteed to never match the given /// ASCII character. /// /// If the expression contains the literal byte, then an error is returned. /// /// If `byte` is not an ASCII character (i.e., greater than `0x7F`), then this /// function panics. pub fn remove(expr: Expr, byte: u8) -> Result<Expr> { // TODO(burntsushi): There is a bug in this routine where only `\n` is // handled correctly. Namely, `AnyChar` and `AnyByte` need to be translated // to proper character classes instead of the special `AnyCharNoNL` and // `AnyByteNoNL` classes. use syntax::Expr::*; assert!(byte <= 0x7F); let chr = byte as char; assert!(chr.len_utf8() == 1); Ok(match expr { Literal { chars, casei } => { if chars.iter().position(|&c| c == chr).is_some() { return Err(Error::LiteralNotAllowed(chr)); } Literal { chars: chars, casei: casei } } LiteralBytes { bytes, casei } => { if bytes.iter().position(|&b| b == byte).is_some() { return Err(Error::LiteralNotAllowed(chr)); } LiteralBytes { bytes: bytes, casei: casei } } AnyChar => AnyCharNoNL, AnyByte => AnyByteNoNL, Class(mut cls) => { cls.remove(chr); Class(cls) } ClassBytes(mut cls) => { cls.remove(byte); ClassBytes(cls) } Group { e, i, name } => { Group { e: Box::new(try!(remove(*e, byte))), i: i, name: name, } } Repeat { e, r, greedy } => { Repeat { e: Box::new(try!(remove(*e, byte))), r: r, greedy: greedy, } } Concat(exprs) => { Concat(try!( exprs.into_iter().map(|e| remove(e, byte)).collect())) } Alternate(exprs) => { Alternate(try!( exprs.into_iter().map(|e| remove(e, byte)).collect())) } e => e, }) }