onig/
syntax.rs

1#![allow(clippy::transmute_ptr_to_ptr)]
2#![allow(clippy::transmute_ptr_to_ref)]
3
4use super::{MetaCharType, RegexOptions, SyntaxBehavior, SyntaxOperator};
5use std::mem::transmute;
6
7/// Meta Character State
8///
9/// Defines if a given meta character is enabled or not within a given
10/// syntax. If the character is enabled it also contains the rust
11/// `char` that it is set to.
12#[derive(Copy, Clone)]
13pub enum MetaChar {
14    /// The meta character is set to the chosen `char`
15    Character(char),
16    /// The meta character is not enabled
17    Ineffective,
18}
19
20/// Onig Syntax Wrapper
21///
22/// Each syntax dfines a flavour of regex syntax. This type allows
23/// interaction with the built-in syntaxes through the static accessor
24/// functions (`Syntax::emacs()`, `Syntax::default()` etc.) and the
25/// creation of custom syntaxes.
26///
27/// For a demonstration of creating a custom syntax see
28/// `examples/syntax.rs` in the main onig crate.
29#[derive(Debug, Clone, Copy)]
30#[repr(transparent)]
31pub struct Syntax {
32    raw: onig_sys::OnigSyntaxType,
33}
34
35impl Syntax {
36    /// Python syntax
37    pub fn python() -> &'static Syntax {
38        unsafe { transmute(&onig_sys::OnigSyntaxPython) }
39    }
40    /// Plain text syntax
41    pub fn asis() -> &'static Syntax {
42        unsafe { transmute(&onig_sys::OnigSyntaxASIS) }
43    }
44
45    /// POSIX Basic RE syntax
46    pub fn posix_basic() -> &'static Syntax {
47        unsafe { transmute(&onig_sys::OnigSyntaxPosixBasic) }
48    }
49
50    /// POSIX Extended RE syntax
51    pub fn posix_extended() -> &'static Syntax {
52        unsafe { transmute(&onig_sys::OnigSyntaxPosixExtended) }
53    }
54
55    /// Emacs syntax
56    pub fn emacs() -> &'static Syntax {
57        unsafe { transmute(&onig_sys::OnigSyntaxEmacs) }
58    }
59
60    /// Grep syntax
61    pub fn grep() -> &'static Syntax {
62        unsafe { transmute(&onig_sys::OnigSyntaxGrep) }
63    }
64
65    /// GNU regex syntax
66    pub fn gnu_regex() -> &'static Syntax {
67        unsafe { transmute(&onig_sys::OnigSyntaxGnuRegex) }
68    }
69
70    /// Java (Sun java.util.regex) syntax
71    pub fn java() -> &'static Syntax {
72        unsafe { transmute(&onig_sys::OnigSyntaxJava) }
73    }
74
75    /// Perl syntax
76    pub fn perl() -> &'static Syntax {
77        unsafe { transmute(&onig_sys::OnigSyntaxPerl) }
78    }
79
80    /// Perl + named group syntax
81    pub fn perl_ng() -> &'static Syntax {
82        unsafe { transmute(&onig_sys::OnigSyntaxPerl_NG) }
83    }
84
85    /// Ruby syntax
86    pub fn ruby() -> &'static Syntax {
87        unsafe { transmute(&onig_sys::OnigSyntaxRuby) }
88    }
89
90    /// Oniguruma Syntax
91    pub fn oniguruma() -> &'static Syntax {
92        unsafe { transmute(&onig_sys::OnigSyntaxOniguruma) }
93    }
94
95    /// Default syntax (Ruby syntax)
96    pub fn default() -> &'static Syntax {
97        unsafe { transmute(onig_sys::OnigDefaultSyntax) }
98    }
99
100    /// Retrieve the operators for this syntax
101    pub fn operators(&self) -> SyntaxOperator {
102        SyntaxOperator::from_bits_truncate(self.operators_bits())
103    }
104
105    /// Retrieve the raw operator bits
106    fn operators_bits(&self) -> u64 {
107        unsafe {
108            let op = onig_sys::onig_get_syntax_op(self.raw_mut());
109            let op2 = onig_sys::onig_get_syntax_op2(self.raw_mut());
110            u64::from(op) + (u64::from(op2) << 32)
111        }
112    }
113
114    /// Replace the operators for this syntax
115    pub fn set_operators(&mut self, operators: SyntaxOperator) {
116        self.set_operators_bits(operators.bits())
117    }
118
119    /// Replace the operators for this syntax with the given raw bits
120    fn set_operators_bits(&mut self, operators_bits: u64) {
121        let op = operators_bits as onig_sys::OnigSyntaxOp;
122        let op2 = (operators_bits >> 32) as onig_sys::OnigSyntaxOp2;
123        unsafe {
124            onig_sys::onig_set_syntax_op(&mut self.raw, op);
125            onig_sys::onig_set_syntax_op2(&mut self.raw, op2)
126        }
127    }
128
129    /// Enable Operators for this Syntax
130    ///
131    /// Updates the operators for this syntax to enable the chosen
132    /// ones.
133    pub fn enable_operators(&mut self, operators: SyntaxOperator) {
134        let operators = self.operators_bits() | operators.bits();
135        self.set_operators_bits(operators)
136    }
137
138    /// Disable Operators for this Syntax
139    ///
140    /// Updates the operators for this syntax to remove the specified
141    /// operators.
142    pub fn disable_operators(&mut self, operators: SyntaxOperator) {
143        let operators = self.operators_bits() & !operators.bits();
144        self.set_operators_bits(operators)
145    }
146
147    /// Retrieves the syntax behaviours
148    pub fn behavior(&self) -> SyntaxBehavior {
149        SyntaxBehavior::from_bits_truncate(unsafe {
150            onig_sys::onig_get_syntax_behavior(self.raw_mut())
151        })
152    }
153
154    /// Overwrite the syntax behaviour for this syntax.
155    pub fn set_behavior(&mut self, behavior: SyntaxBehavior) {
156        let behavior = behavior.bits() as onig_sys::OnigSyntaxBehavior;
157        unsafe {
158            onig_sys::onig_set_syntax_behavior(&mut self.raw, behavior);
159        }
160    }
161
162    /// Enable a given behaviour for this syntax
163    pub fn enable_behavior(&mut self, behavior: SyntaxBehavior) {
164        let behavior = self.behavior() | behavior;
165        self.set_behavior(behavior)
166    }
167
168    /// Disable a given behaviour for this syntax
169    pub fn disable_behavior(&mut self, behavior: SyntaxBehavior) {
170        let behavior = self.behavior() & !behavior;
171        self.set_behavior(behavior)
172    }
173
174    /// Retireve the syntax options for this syntax
175    pub fn options(&self) -> RegexOptions {
176        RegexOptions::from_bits_truncate(unsafe {
177            onig_sys::onig_get_syntax_options(self.raw_mut())
178        })
179    }
180
181    /// Replace the syntax options for this syntax
182    pub fn set_options(&mut self, options: RegexOptions) {
183        let options = options.bits() as onig_sys::OnigOptionType;
184        unsafe {
185            onig_sys::onig_set_syntax_options(&mut self.raw, options);
186        }
187    }
188
189    /// Set a given meta character's state
190    ///
191    /// Arguments:
192    ///  - `what`: The meta character to update
193    ///  - `meta`: The value to set the meta character to
194    pub fn set_meta_char(&mut self, what: MetaCharType, meta: MetaChar) {
195        let what = what.bits();
196        let code = match meta {
197            MetaChar::Ineffective => onig_sys::ONIG_INEFFECTIVE_META_CHAR,
198            MetaChar::Character(char) => char as u32,
199        };
200        unsafe {
201            onig_sys::onig_set_meta_char(&mut self.raw, what, code);
202        }
203    }
204
205    fn raw_mut(&self) -> *mut onig_sys::OnigSyntaxType {
206        &self.raw as *const onig_sys::OnigSyntaxType as *mut onig_sys::OnigSyntaxType
207    }
208}
209
210#[cfg(test)]
211mod test {
212    use super::*;
213
214    #[test]
215    fn round_trip_bits() {
216        let mut syn = Syntax::python().clone();
217        syn.enable_operators(SyntaxOperator::SYNTAX_OPERATOR_ESC_X_BRACE_HEX8);
218        assert_ne!(Syntax::python().raw, syn.raw);
219        syn.disable_operators(SyntaxOperator::SYNTAX_OPERATOR_ESC_X_BRACE_HEX8);
220        assert_eq!(Syntax::python().raw, syn.raw);
221    }
222}