artichoke_backend/extn/core/regexp/
mruby.rs

1use std::ffi::CStr;
2
3use super::{Flags, Regexp, trampoline};
4use crate::extn::prelude::*;
5
6const REGEXP_CSTR: &CStr = c"Regexp";
7static REGEXP_RUBY_SOURCE: &[u8] = include_bytes!("regexp.rb");
8
9pub fn init(interp: &mut Artichoke) -> InitializeResult<()> {
10    if interp.is_class_defined::<Regexp>() {
11        return Ok(());
12    }
13
14    let spec = class::Spec::new("Regexp", REGEXP_CSTR, None, Some(def::box_unbox_free::<Regexp>))?;
15    class::Builder::for_spec(interp, &spec)
16        .value_is_rust_object()
17        .add_method("initialize", initialize, sys::mrb_args_req_and_opt(1, 2))?
18        .add_self_method("compile", compile, sys::mrb_args_rest())?
19        .add_self_method("escape", escape, sys::mrb_args_req(1))?
20        .add_self_method("quote", escape, sys::mrb_args_req(1))?
21        .add_self_method("union", union, sys::mrb_args_rest())?
22        .add_method("==", eql, sys::mrb_args_req(1))?
23        .add_method("===", case_compare, sys::mrb_args_req(1))?
24        .add_method("=~", match_operator, sys::mrb_args_req(1))?
25        .add_method("casefold?", casefold, sys::mrb_args_none())?
26        .add_method("eql?", eql, sys::mrb_args_req(1))?
27        .add_method("fixed_encoding?", fixed_encoding, sys::mrb_args_none())?
28        .add_method("hash", hash, sys::mrb_args_none())?
29        .add_method("inspect", inspect, sys::mrb_args_none())?
30        .add_method("match?", match_q, sys::mrb_args_req_and_opt(1, 1))?
31        .add_method("named_captures", named_captures, sys::mrb_args_none())?
32        .add_method("match", match_, sys::mrb_args_req_and_opt(1, 1))?
33        .add_method("names", names, sys::mrb_args_none())?
34        .add_method("options", options, sys::mrb_args_none())?
35        .add_method("source", source, sys::mrb_args_none())?
36        .add_method("to_s", to_s, sys::mrb_args_none())?
37        .define()?;
38    interp.def_class::<Regexp>(spec)?;
39
40    interp.eval(REGEXP_RUBY_SOURCE)?;
41
42    // Declare class constants
43    let ignorecase = interp.convert(Flags::IGNORECASE.bits());
44    interp.define_class_constant::<Regexp>("IGNORECASE", ignorecase)?;
45    let extended = interp.convert(Flags::EXTENDED.bits());
46    interp.define_class_constant::<Regexp>("EXTENDED", extended)?;
47    let multiline = interp.convert(Flags::MULTILINE.bits());
48    interp.define_class_constant::<Regexp>("MULTILINE", multiline)?;
49    let fixed_encoding = interp.convert(Flags::FIXEDENCODING.bits());
50    interp.define_class_constant::<Regexp>("FIXEDENCODING", fixed_encoding)?;
51    let no_encoding = interp.convert(Flags::NOENCODING.bits());
52    interp.define_class_constant::<Regexp>("NOENCODING", no_encoding)?;
53
54    Ok(())
55}
56
57unsafe extern "C-unwind" fn initialize(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
58    let (pattern, options, encoding, _block) = mrb_get_args!(mrb, required = 1, optional = 2, &block);
59    unwrap_interpreter!(mrb, to => guard);
60    let slf = Value::from(slf);
61    let pattern = Value::from(pattern);
62    let options = options.map(Value::from);
63    let encoding = encoding.map(Value::from);
64    let result = trampoline::initialize(&mut guard, pattern, options, encoding, slf);
65    match result {
66        Ok(value) => value.inner(),
67        Err(exception) => {
68            // SAFETY: only Copy objects remain on the stack
69            unsafe { error::raise(guard, exception) }
70        }
71    }
72}
73
74unsafe extern "C-unwind" fn compile(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
75    let args = mrb_get_args!(mrb, *args);
76    // Call `mrb_obj_new` instead of allocating an object of class `slf` and
77    // delegating to `trampoline::initialize` to handle cases where subclasses
78    // override initialize.
79    if let Ok(argslen) = sys::mrb_int::try_from(args.len()) {
80        sys::mrb_obj_new(mrb, sys::mrb_sys_class_ptr(slf), argslen, args.as_ptr())
81    } else {
82        sys::mrb_sys_nil_value()
83    }
84}
85
86unsafe extern "C-unwind" fn escape(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
87    let pattern = mrb_get_args!(mrb, required = 1);
88    unwrap_interpreter!(mrb, to => guard);
89    let pattern = Value::from(pattern);
90    let result = trampoline::escape(&mut guard, pattern);
91    match result {
92        Ok(result) => result.inner(),
93        Err(exception) => {
94            // SAFETY: only Copy objects remain on the stack
95            unsafe { error::raise(guard, exception) }
96        }
97    }
98}
99
100unsafe extern "C-unwind" fn union(mrb: *mut sys::mrb_state, _slf: sys::mrb_value) -> sys::mrb_value {
101    let args = mrb_get_args!(mrb, *args);
102    unwrap_interpreter!(mrb, to => guard);
103    let args = args.iter().copied().map(Value::from);
104    let result = trampoline::union(&mut guard, args);
105    match result {
106        Ok(result) => result.inner(),
107        Err(exception) => {
108            // SAFETY: only Copy objects remain on the stack
109            unsafe { error::raise(guard, exception) }
110        }
111    }
112}
113
114unsafe extern "C-unwind" fn match_q(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
115    let (pattern, pos) = mrb_get_args!(mrb, required = 1, optional = 1);
116    unwrap_interpreter!(mrb, to => guard);
117    let value = Value::from(slf);
118    let pattern = Value::from(pattern);
119    let pos = pos.map(Value::from);
120    let result = trampoline::is_match(&mut guard, value, pattern, pos);
121    match result {
122        Ok(result) => result.inner(),
123        Err(exception) => {
124            // SAFETY: only Copy objects remain on the stack
125            unsafe { error::raise(guard, exception) }
126        }
127    }
128}
129
130unsafe extern "C-unwind" fn match_(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
131    let (pattern, pos, block) = mrb_get_args!(mrb, required = 1, optional = 1, &block);
132    unwrap_interpreter!(mrb, to => guard);
133    let value = Value::from(slf);
134    let pattern = Value::from(pattern);
135    let pos = pos.map(Value::from);
136    let result = trampoline::match_(&mut guard, value, pattern, pos, block);
137    match result {
138        Ok(result) => result.inner(),
139        Err(exception) => {
140            // SAFETY: only Copy objects remain on the stack
141            unsafe { error::raise(guard, exception) }
142        }
143    }
144}
145
146unsafe extern "C-unwind" fn eql(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
147    let other = mrb_get_args!(mrb, required = 1);
148    unwrap_interpreter!(mrb, to => guard);
149    let value = Value::from(slf);
150    let other = Value::from(other);
151    let result = trampoline::eql(&mut guard, value, other);
152    match result {
153        Ok(result) => result.inner(),
154        Err(exception) => {
155            // SAFETY: only Copy objects remain on the stack
156            unsafe { error::raise(guard, exception) }
157        }
158    }
159}
160
161unsafe extern "C-unwind" fn case_compare(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
162    let pattern = mrb_get_args!(mrb, required = 1);
163    unwrap_interpreter!(mrb, to => guard);
164    let value = Value::from(slf);
165    let pattern = Value::from(pattern);
166    let result = trampoline::case_compare(&mut guard, value, pattern);
167    match result {
168        Ok(result) => result.inner(),
169        Err(exception) => {
170            // SAFETY: only Copy objects remain on the stack
171            unsafe { error::raise(guard, exception) }
172        }
173    }
174}
175
176unsafe extern "C-unwind" fn match_operator(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
177    let pattern = mrb_get_args!(mrb, required = 1);
178    unwrap_interpreter!(mrb, to => guard);
179    let value = Value::from(slf);
180    let pattern = Value::from(pattern);
181    let result = trampoline::match_operator(&mut guard, value, pattern);
182    match result {
183        Ok(result) => result.inner(),
184        Err(exception) => {
185            // SAFETY: only Copy objects remain on the stack
186            unsafe { error::raise(guard, exception) }
187        }
188    }
189}
190
191unsafe extern "C-unwind" fn casefold(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
192    mrb_get_args!(mrb, none);
193    unwrap_interpreter!(mrb, to => guard);
194    let value = Value::from(slf);
195    let result = trampoline::is_casefold(&mut guard, value);
196    match result {
197        Ok(result) => result.inner(),
198        Err(exception) => {
199            // SAFETY: only Copy objects remain on the stack
200            unsafe { error::raise(guard, exception) }
201        }
202    }
203}
204
205unsafe extern "C-unwind" fn fixed_encoding(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
206    mrb_get_args!(mrb, none);
207    unwrap_interpreter!(mrb, to => guard);
208    let value = Value::from(slf);
209    let result = trampoline::is_fixed_encoding(&mut guard, value);
210    match result {
211        Ok(result) => result.inner(),
212        Err(exception) => {
213            // SAFETY: only Copy objects remain on the stack
214            unsafe { error::raise(guard, exception) }
215        }
216    }
217}
218
219unsafe extern "C-unwind" fn hash(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
220    mrb_get_args!(mrb, none);
221    unwrap_interpreter!(mrb, to => guard);
222    let value = Value::from(slf);
223    let result = trampoline::hash(&mut guard, value);
224    match result {
225        Ok(result) => result.inner(),
226        Err(exception) => {
227            // SAFETY: only Copy objects remain on the stack
228            unsafe { error::raise(guard, exception) }
229        }
230    }
231}
232
233unsafe extern "C-unwind" fn inspect(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
234    mrb_get_args!(mrb, none);
235    unwrap_interpreter!(mrb, to => guard);
236    let value = Value::from(slf);
237    let result = trampoline::inspect(&mut guard, value);
238    match result {
239        Ok(result) => result.inner(),
240        Err(exception) => {
241            // SAFETY: only Copy objects remain on the stack
242            unsafe { error::raise(guard, exception) }
243        }
244    }
245}
246
247unsafe extern "C-unwind" fn named_captures(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
248    mrb_get_args!(mrb, none);
249    unwrap_interpreter!(mrb, to => guard);
250    let value = Value::from(slf);
251    let result = trampoline::named_captures(&mut guard, value);
252    match result {
253        Ok(result) => result.inner(),
254        Err(exception) => {
255            // SAFETY: only Copy objects remain on the stack
256            unsafe { error::raise(guard, exception) }
257        }
258    }
259}
260
261unsafe extern "C-unwind" fn names(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
262    mrb_get_args!(mrb, none);
263    unwrap_interpreter!(mrb, to => guard);
264    let value = Value::from(slf);
265    let result = trampoline::names(&mut guard, value);
266    match result {
267        Ok(result) => result.inner(),
268        Err(exception) => {
269            // SAFETY: only Copy objects remain on the stack
270            unsafe { error::raise(guard, exception) }
271        }
272    }
273}
274
275unsafe extern "C-unwind" fn options(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
276    mrb_get_args!(mrb, none);
277    unwrap_interpreter!(mrb, to => guard);
278    let value = Value::from(slf);
279    let result = trampoline::options(&mut guard, value);
280    match result {
281        Ok(result) => result.inner(),
282        Err(exception) => {
283            // SAFETY: only Copy objects remain on the stack
284            unsafe { error::raise(guard, exception) }
285        }
286    }
287}
288
289unsafe extern "C-unwind" fn source(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
290    mrb_get_args!(mrb, none);
291    unwrap_interpreter!(mrb, to => guard);
292    let value = Value::from(slf);
293    let result = trampoline::source(&mut guard, value);
294    match result {
295        Ok(result) => result.inner(),
296        Err(exception) => {
297            // SAFETY: only Copy objects remain on the stack
298            unsafe { error::raise(guard, exception) }
299        }
300    }
301}
302
303unsafe extern "C-unwind" fn to_s(mrb: *mut sys::mrb_state, slf: sys::mrb_value) -> sys::mrb_value {
304    mrb_get_args!(mrb, none);
305    unwrap_interpreter!(mrb, to => guard);
306    let value = Value::from(slf);
307    let result = trampoline::to_s(&mut guard, value);
308    match result {
309        Ok(result) => result.inner(),
310        Err(exception) => {
311            // SAFETY: only Copy objects remain on the stack
312            unsafe { error::raise(guard, exception) }
313        }
314    }
315}