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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 unsafe { error::raise(guard, exception) }
313 }
314 }
315}