1 #ifndef RBIMPL_SCAN_ARGS_H
2 #define RBIMPL_SCAN_ARGS_H
32 #include "ruby/internal/config.h"
50 #define RB_SCAN_ARGS_PASS_CALLED_KEYWORDS 0
53 #define RB_SCAN_ARGS_KEYWORDS 1
59 #define RB_SCAN_ARGS_LAST_HASH_KEYWORDS 3
69 #define RB_NO_KEYWORDS 0
72 #define RB_PASS_KEYWORDS 1
78 #define RB_PASS_CALLED_KEYWORDS !!rb_keyword_given_p()
89 #define HAVE_RB_SCAN_ARGS_OPTIONAL_HASH 1
177 void rb_scan_args_bad_format(const
char*);
186 void rb_scan_args_length_mismatch(const
char*,
int);
195 #define rb_scan_args_isdigit(c) (RBIMPL_CAST((unsigned char)((c)-'0'))<10)
197 #define rb_scan_args_count_end(fmt, ofs, vari) \
198 ((fmt)[ofs] ? -1 : (vari))
200 #define rb_scan_args_count_block(fmt, ofs, vari) \
202 rb_scan_args_count_end(fmt, ofs, vari) : \
203 rb_scan_args_count_end(fmt, (ofs)+1, (vari)+1))
205 #define rb_scan_args_count_hash(fmt, ofs, vari) \
207 rb_scan_args_count_block(fmt, ofs, vari) : \
208 rb_scan_args_count_block(fmt, (ofs)+1, (vari)+1))
210 #define rb_scan_args_count_trail(fmt, ofs, vari) \
211 (!rb_scan_args_isdigit((fmt)[ofs]) ? \
212 rb_scan_args_count_hash(fmt, ofs, vari) : \
213 rb_scan_args_count_hash(fmt, (ofs)+1, (vari)+((fmt)[ofs]-'0')))
215 #define rb_scan_args_count_var(fmt, ofs, vari) \
217 rb_scan_args_count_trail(fmt, ofs, vari) : \
218 rb_scan_args_count_trail(fmt, (ofs)+1, (vari)+1))
220 #define rb_scan_args_count_opt(fmt, ofs, vari) \
221 (!rb_scan_args_isdigit((fmt)[ofs]) ? \
222 rb_scan_args_count_var(fmt, ofs, vari) : \
223 rb_scan_args_count_var(fmt, (ofs)+1, (vari)+(fmt)[ofs]-'0'))
225 #define rb_scan_args_count_lead(fmt, ofs, vari) \
226 (!rb_scan_args_isdigit((fmt)[ofs]) ? \
227 rb_scan_args_count_var(fmt, ofs, vari) : \
228 rb_scan_args_count_opt(fmt, (ofs)+1, (vari)+(fmt)[ofs]-'0'))
230 #define rb_scan_args_count(fmt) rb_scan_args_count_lead(fmt, 0, 0)
232 #if RBIMPL_HAS_ATTRIBUTE(diagnose_if)
234 # define rb_scan_args_verify(fmt, varc) RBIMPL_ASSERT_NOTHING
244 # define rb_scan_args_verify(fmt, varc) \
245 (sizeof(char[1-2*(rb_scan_args_count(fmt)<0)])!=1 ? \
246 rb_scan_args_bad_format(fmt) : \
247 sizeof(char[1-2*(rb_scan_args_count(fmt)!=(varc))])!=1 ? \
248 rb_scan_args_length_mismatch(fmt, varc) : \
249 RBIMPL_ASSERT_NOTHING)
253 rb_scan_args_keyword_p(
int kw_flag,
VALUE last)
269 rb_scan_args_lead_p(const
char *fmt)
271 return rb_scan_args_isdigit(fmt[0]);
276 rb_scan_args_n_lead(const
char *fmt)
278 return (rb_scan_args_lead_p(fmt) ? fmt[0]-
'0' : 0);
283 rb_scan_args_opt_p(const
char *fmt)
285 return (rb_scan_args_lead_p(fmt) && rb_scan_args_isdigit(fmt[1]));
290 rb_scan_args_n_opt(const
char *fmt)
292 return (rb_scan_args_opt_p(fmt) ? fmt[1]-
'0' : 0);
297 rb_scan_args_var_idx(const
char *fmt)
299 return (!rb_scan_args_lead_p(fmt) ? 0 : !rb_scan_args_isdigit(fmt[1]) ? 1 : 2);
304 rb_scan_args_f_var(const
char *fmt)
306 return (fmt[rb_scan_args_var_idx(fmt)]==
'*');
311 rb_scan_args_trail_idx(const
char *fmt)
313 const int idx = rb_scan_args_var_idx(fmt);
314 return idx+(fmt[idx]==
'*');
319 rb_scan_args_n_trail(const
char *fmt)
321 const int idx = rb_scan_args_trail_idx(fmt);
322 return (rb_scan_args_isdigit(fmt[idx]) ? fmt[idx]-
'0' : 0);
327 rb_scan_args_hash_idx(const
char *fmt)
329 const int idx = rb_scan_args_trail_idx(fmt);
330 return idx+rb_scan_args_isdigit(fmt[idx]);
335 rb_scan_args_f_hash(const
char *fmt)
337 return (fmt[rb_scan_args_hash_idx(fmt)]==
':');
342 rb_scan_args_block_idx(const
char *fmt)
344 const int idx = rb_scan_args_hash_idx(fmt);
345 return idx+(fmt[idx]==
':');
350 rb_scan_args_f_block(const
char *fmt)
352 return (fmt[rb_scan_args_block_idx(fmt)]==
'&');
358 rb_scan_args_end_idx(const
char *fmt)
360 const int idx = rb_scan_args_block_idx(fmt);
361 return idx+(fmt[idx]==
'&');
367 # define rb_scan_args0(argc, argv, fmt, varc, vars) \
368 rb_scan_args_set(RB_SCAN_ARGS_PASS_CALLED_KEYWORDS, argc, argv, \
369 rb_scan_args_n_lead(fmt), \
370 rb_scan_args_n_opt(fmt), \
371 rb_scan_args_n_trail(fmt), \
372 rb_scan_args_f_var(fmt), \
373 rb_scan_args_f_hash(fmt), \
374 rb_scan_args_f_block(fmt), \
375 (rb_scan_args_verify(fmt, varc), vars), (char *)fmt, varc)
376 # define rb_scan_args_kw0(kw_flag, argc, argv, fmt, varc, vars) \
377 rb_scan_args_set(kw_flag, argc, argv, \
378 rb_scan_args_n_lead(fmt), \
379 rb_scan_args_n_opt(fmt), \
380 rb_scan_args_n_trail(fmt), \
381 rb_scan_args_f_var(fmt), \
382 rb_scan_args_f_hash(fmt), \
383 rb_scan_args_f_block(fmt), \
384 (rb_scan_args_verify(fmt, varc), vars), (char *)fmt, varc)
388 rb_scan_args_set(
int kw_flag,
int argc, const
VALUE *argv,
389 int n_lead,
int n_opt,
int n_trail,
390 bool f_var,
bool f_hash,
bool f_block,
391 VALUE *vars[], RB_UNUSED_VAR(const
char *fmt), RB_UNUSED_VAR(
int varc))
395 int i, argi = 0, vari = 0;
397 #define rb_scan_args_next_param() vars[vari++]
398 const int n_mand = n_lead + n_trail;
401 if (f_hash && argc > 0) {
402 VALUE last = argv[argc - 1];
403 if (rb_scan_args_keyword_p(kw_flag, last)) {
414 for (i = 0; i < n_lead; i++) {
415 var = rb_scan_args_next_param();
416 if (var) *var = argv[argi];
421 for (i = 0; i < n_opt; i++) {
422 var = rb_scan_args_next_param();
423 if (argi < argc - n_trail) {
424 if (var) *var = argv[argi];
428 if (var) *var =
Qnil;
434 int n_var = argc - argi - n_trail;
436 var = rb_scan_args_next_param();
447 for (i = 0; i < n_trail; i++) {
448 var = rb_scan_args_next_param();
449 if (var) *var = argv[argi];
455 var = rb_scan_args_next_param();
456 if (var) *var = hash;
461 var = rb_scan_args_next_param();
477 #undef rb_scan_args_next_param
482 #if defined(__DOXYGEN__)
485 #elif ! defined(HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR_CONSTANT_P)
488 #elif ! defined(HAVE_VA_ARGS_MACRO)
491 #elif ! defined(__OPTIMIZE__)
494 #elif defined(HAVE___VA_OPT__)
495 # define rb_scan_args(argc, argvp, fmt, ...) \
496 __builtin_choose_expr( \
497 __builtin_constant_p(fmt), \
500 (sizeof((VALUE*[]){__VA_ARGS__})/sizeof(VALUE*)), \
501 ((VALUE*[]){__VA_ARGS__})), \
502 (rb_scan_args)(argc, argvp, fmt __VA_OPT__(, __VA_ARGS__)))
503 # define rb_scan_args_kw(kw_flag, argc, argvp, fmt, ...) \
504 __builtin_choose_expr( \
505 __builtin_constant_p(fmt), \
507 kw_flag, argc, argvp, fmt, \
508 (sizeof((VALUE*[]){__VA_ARGS__})/sizeof(VALUE*)), \
509 ((VALUE*[]){__VA_ARGS__})), \
510 (rb_scan_args_kw)(kw_flag, argc, argvp, fmt __VA_OPT__(, __VA_ARGS__)))
512 #elif defined(__STRICT_ANSI__)
515 #elif defined(__GNUC__)
516 # define rb_scan_args(argc, argvp, fmt, ...) \
517 __builtin_choose_expr( \
518 __builtin_constant_p(fmt), \
521 (sizeof((VALUE*[]){__VA_ARGS__})/sizeof(VALUE*)), \
522 ((VALUE*[]){__VA_ARGS__})), \
523 (rb_scan_args)(argc, argvp, fmt, __VA_ARGS__))
524 # define rb_scan_args_kw(kw_flag, argc, argvp, fmt, ...) \
525 __builtin_choose_expr( \
526 __builtin_constant_p(fmt), \
528 kw_flag, argc, argvp, fmt, \
529 (sizeof((VALUE*[]){__VA_ARGS__})/sizeof(VALUE*)), \
530 ((VALUE*[]){__VA_ARGS__})), \
531 (rb_scan_args_kw)(kw_flag, argc, argvp, fmt, __VA_ARGS__ ))
Defines RBIMPL_HAS_ATTRIBUTE.
Defines RBIMPL_ATTR_DIAGNOSE_IF.
#define RBIMPL_ATTR_DIAGNOSE_IF(_, __, ___)
Wraps (or simulates) __attribute__((diagnose_if))
Tweaking visibility of C variables/functions.
#define RBIMPL_SYMBOL_EXPORT_END()
Counterpart of RBIMPL_SYMBOL_EXPORT_BEGIN.
#define RBIMPL_SYMBOL_EXPORT_BEGIN()
Shortcut macro equivalent to RUBY_SYMBOL_EXPORT_BEGIN extern "C" {.
Defines RBIMPL_ATTR_FORCEINLINE.
#define RBIMPL_ATTR_FORCEINLINE()
Wraps (or simulates) __forceinline.
int rb_scan_args_kw(int kw_splat, int argc, const VALUE *argv, const char *fmt,...)
Identical to rb_scan_args(), except it also accepts kw_splat.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
int rb_keyword_given_p(void)
Determines if the current method is given a keyword argument.
int rb_block_given_p(void)
Determines if the current method is given a block.
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
#define T_HASH
Old name of RUBY_T_HASH.
#define Qnil
Old name of RUBY_Qnil.
Defines RBIMPL_ATTR_ERROR.
#define RBIMPL_ATTR_ERROR(msg)
Wraps (or simulates) __attribute__((error))
Public APIs related to rb_cArray.
VALUE rb_ary_new_from_values(long n, const VALUE *elts)
Identical to rb_ary_new_from_args(), except how objects are passed.
VALUE rb_ary_new(void)
Allocates a new, empty array.
Public APIs related to rb_eException.
#define UNLIMITED_ARGUMENTS
This macro is used in conjunction with rb_check_arity().
Public APIs related to rb_cHash.
VALUE rb_hash_dup(VALUE hash)
Duplicates a hash.
Public APIs related to rb_cProc.
VALUE rb_block_proc(void)
Constructs a Proc object from implicitly passed components.
Defines RBIMPL_STATIC_ASSERT.
Defines RBIMPL_ATTR_NONNULL.
#define RBIMPL_ATTR_NONNULL(list)
Wraps (or simulates) __attribute__((nonnull))
Defines RBIMPL_ATTR_NORETURN.
#define RB_SCAN_ARGS_PASS_CALLED_KEYWORDS
Same behaviour as rb_scan_args().
#define RB_SCAN_ARGS_KEYWORDS
The final argument should be a hash treated as keywords.
#define RB_SCAN_ARGS_LAST_HASH_KEYWORDS
Treat a final argument as keywords if it is a hash, and not as keywords otherwise.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.